Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6b313042 authored by Kweku Adams's avatar Kweku Adams
Browse files

Fix allow-UIJ-scheduling determination.

The ServiceRecord.fgRequired bit is updated after the call to check the
FGS while-in-use permission. This meant that trying to set the
allow-uij-scheduling bit in that method while limiting it to foreground
services didn't work properly. Instead, wait until the system has
confirmed the FGS can start and updated the ServiceRecord bits before
setting the allow-uij-scheduling bit.

Bug: 277635240
Test: atest CtsJobSchedulerTestCases:UserInitiatedJobTest
Change-Id: Iccb8a9b2ee39745f8f9c9d5db4bcf969cf175997
parent 9d1c9281
Loading
Loading
Loading
Loading
+20 −16
Original line number Diff line number Diff line
@@ -1007,6 +1007,24 @@ public final class ActiveServices {
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants, callingUid, callingProcessName, callingPackage));

        // We want to allow scheduling user-initiated jobs when the app is running a
        // foreground service that was started in the same conditions that allows for scheduling
        // UI jobs. More explicitly, we want to allow scheduling UI jobs when the app is running
        // an FGS that started when the app was in the TOP or a BAL-approved state.
        final boolean isFgs = r.isForeground || r.fgRequired;
        if (isFgs) {
            // As of Android UDC, the conditions required for the while-in-use permissions
            // are the same conditions that we want, so we piggyback on that logic.
            // Use that as a shortcut if possible to avoid having to recheck all the conditions.
            final boolean whileInUseAllowsUiJobScheduling =
                    ActivityManagerService.doesReasonCodeAllowSchedulingUserInitiatedJobs(
                            r.mAllowWhileInUsePermissionInFgsReason);
            r.updateAllowUiJobScheduling(whileInUseAllowsUiJobScheduling
                    || mAm.canScheduleUserInitiatedJobs(callingUid, callingPid, callingPackage));
        } else {
            r.updateAllowUiJobScheduling(false);
        }

        if (fgRequired) {
            // We are now effectively running a foreground service.
            synchronized (mAm.mProcessStats.mLock) {
@@ -7344,26 +7362,12 @@ public final class ActiveServices {
        } else {
            allowWhileInUse = REASON_UNKNOWN;
        }
        // We want to allow scheduling user-initiated jobs when the app is running a
        // foreground service that was started in the same conditions that allows for scheduling
        // UI jobs. More explicitly, we want to allow scheduling UI jobs when the app is running
        // an FGS that started when the app was in the TOP or a BAL-approved state.
        // As of Android UDC, the conditions required for the while-in-use permissions
        // are the same conditions that we want, so we piggyback on that logic.
        // We use that as a shortcut if possible so we don't have to recheck all the conditions.
        final boolean isFgs = r.isForeground || r.fgRequired;
        if (isFgs) {
            r.updateAllowUiJobScheduling(ActivityManagerService
                    .doesReasonCodeAllowSchedulingUserInitiatedJobs(allowWhileInUse)
                    || mAm.canScheduleUserInitiatedJobs(
                            callingUid, callingPid, callingPackage, true));
        } else {
            r.updateAllowUiJobScheduling(false);
        }
        r.mAllowWhileInUsePermissionInFgsReason = allowWhileInUse;
    }

    void resetFgsRestrictionLocked(ServiceRecord r) {
        r.mAllowWhileInUsePermissionInFgs = false;
        r.mAllowWhileInUsePermissionInFgsReason = REASON_DENIED;
        r.mAllowStartForeground = REASON_DENIED;
        r.mInfoAllowStartForeground = null;
        r.mInfoTempFgsAllowListReason = null;
+4 −10
Original line number Diff line number Diff line
@@ -368,7 +368,6 @@ import android.util.FeatureFlagUtils;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.Log;
import android.util.LogWriter;
import android.util.Pair;
import android.util.PrintWriterPrinter;
import android.util.Slog;
@@ -6181,8 +6180,8 @@ public class ActivityManagerService extends IActivityManager.Stub
        final ProcessServiceRecord psr = pr.mServices;
        if (psr != null && psr.hasForegroundServices()) {
            for (int s = psr.numberOfExecutingServices() - 1; s >= 0; --s) {
                final ServiceRecord sr = psr.getExecutingServiceAt(s);
            for (int s = psr.numberOfRunningServices() - 1; s >= 0; --s) {
                final ServiceRecord sr = psr.getRunningServiceAt(s);
                if (sr.isForeground && sr.mAllowUiJobScheduling) {
                    return true;
                }
@@ -6197,12 +6196,7 @@ public class ActivityManagerService extends IActivityManager.Stub
     * {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean) user-initiated job}.
     */
    // TODO(262260570): log allow reason to an atom
    private boolean canScheduleUserInitiatedJobs(int uid, int pid, String pkgName) {
        return canScheduleUserInitiatedJobs(uid, pid, pkgName, false);
    }
    boolean canScheduleUserInitiatedJobs(int uid, int pid, String pkgName,
            boolean skipWhileInUseCheck) {
    boolean canScheduleUserInitiatedJobs(int uid, int pid, String pkgName) {
        synchronized (this) {
            final ProcessRecord processRecord;
            synchronized (mPidsSelfLocked) {
@@ -6232,7 +6226,7 @@ public class ActivityManagerService extends IActivityManager.Stub
            // As of Android UDC, the conditions required to grant a while-in-use permission
            // covers the majority of those cases, and so we piggyback on that logic as the base.
            // Missing cases are added after.
            if (!skipWhileInUseCheck && mServices.canAllowWhileInUsePermissionInFgsLocked(
            if (mServices.canAllowWhileInUsePermissionInFgsLocked(
                    pid, uid, pkgName, processRecord, backgroundStartPrivileges)) {
                return true;
            }
+4 −0
Original line number Diff line number Diff line
@@ -174,6 +174,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
    // allow while-in-use permissions in foreground service or not.
    // while-in-use permissions in FGS started from background might be restricted.
    boolean mAllowWhileInUsePermissionInFgs;
    @PowerExemptionManager.ReasonCode
    int mAllowWhileInUsePermissionInFgsReason;
    // A copy of mAllowWhileInUsePermissionInFgs's value when the service is entering FGS state.
    boolean mAllowWhileInUsePermissionInFgsAtEntering;
    /** Allow scheduling user-initiated jobs from the background. */
@@ -609,6 +611,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
        }
        pw.print(prefix); pw.print("allowWhileInUsePermissionInFgs=");
                pw.println(mAllowWhileInUsePermissionInFgs);
        pw.print(prefix); pw.print("mAllowWhileInUsePermissionInFgsReason=");
        pw.println(mAllowWhileInUsePermissionInFgsReason);
        pw.print(prefix); pw.print("allowUiJobScheduling="); pw.println(mAllowUiJobScheduling);
        pw.print(prefix); pw.print("recentCallingPackage=");
                pw.println(mRecentCallingPackage);