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

Commit 52afe2c3 authored by Kweku Adams's avatar Kweku Adams Committed by Automerger Merge Worker
Browse files

Merge "Add additional UI job scheduling cases." into udc-dev am: e87bf3f9

parents 15c65363 e87bf3f9
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -1259,10 +1259,14 @@ class JobConcurrencyManager {

                final BackgroundStartPrivileges bsp =
                        activityManagerInternal.getBackgroundStartPrivileges(uid);
                final boolean balAllowed = bsp.allowsBackgroundActivityStarts();
                if (DEBUG) {
                    Slog.d(TAG, "Job " + job.toShortString() + " bal state: " + bsp);
                    Slog.d(TAG, "Job " + job.toShortString() + " bsp state: " + bsp);
                }
                // Intentionally use the background activity start BSP here instead of
                // the full BAL check since the former is transient and better indicates that the
                // user recently interacted with the app, while the latter includes
                // permanent exceptions that don't warrant bypassing normal concurrency policy.
                final boolean balAllowed = bsp.allowsBackgroundActivityStarts();
                cachedPrivilegedState.put(uid,
                        balAllowed ? PRIVILEGED_STATE_BAL : PRIVILEGED_STATE_NONE);
                return balAllowed;
+41 −23
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.BackgroundStartPrivileges;
import android.app.IUidObserver;
import android.app.compat.CompatChanges;
import android.app.job.IJobScheduler;
@@ -3782,7 +3781,8 @@ public class JobSchedulerService extends com.android.server.SystemService
            return canPersist;
        }

        private int validateJob(@NonNull JobInfo job, int callingUid, int sourceUserId,
        private int validateJob(@NonNull JobInfo job, int callingUid, int callingPid,
                int sourceUserId,
                @Nullable String sourcePkgName, @Nullable JobWorkItem jobWorkItem) {
            final boolean rejectNegativeNetworkEstimates = CompatChanges.isChangeEnabled(
                            JobInfo.REJECT_NEGATIVE_NETWORK_ESTIMATES, callingUid);
@@ -3815,6 +3815,8 @@ public class JobSchedulerService extends com.android.server.SystemService
                }
                // We aim to check the permission of both the source and calling app so that apps
                // don't attempt to bypass the permission by using other apps to do the work.
                boolean isInStateToScheduleUiJobSource = false;
                final String callingPkgName = job.getService().getPackageName();
                if (sourceUid != -1) {
                    // Check the permission of the source app.
                    final int sourceResult =
@@ -3822,8 +3824,13 @@ public class JobSchedulerService extends com.android.server.SystemService
                    if (sourceResult != JobScheduler.RESULT_SUCCESS) {
                        return sourceResult;
                    }
                    final int sourcePid =
                            callingUid == sourceUid && callingPkgName.equals(sourcePkgName)
                                    ? callingPid : -1;
                    isInStateToScheduleUiJobSource = isInStateToScheduleUserInitiatedJobs(
                            sourceUid, sourcePid, sourcePkgName);
                }
                final String callingPkgName = job.getService().getPackageName();
                boolean isInStateToScheduleUiJobCalling = false;
                if (callingUid != sourceUid || !callingPkgName.equals(sourcePkgName)) {
                    // Source app is different from calling app. Make sure the calling app also has
                    // the permission.
@@ -3832,27 +3839,19 @@ public class JobSchedulerService extends com.android.server.SystemService
                    if (callingResult != JobScheduler.RESULT_SUCCESS) {
                        return callingResult;
                    }
                    // Avoid rechecking the state if the source app is able to schedule the job.
                    if (!isInStateToScheduleUiJobSource) {
                        isInStateToScheduleUiJobCalling = isInStateToScheduleUserInitiatedJobs(
                                callingUid, callingPid, callingPkgName);
                    }

                final int uid = sourceUid != -1 ? sourceUid : callingUid;
                final int procState = mActivityManagerInternal.getUidProcessState(uid);
                if (DEBUG) {
                    Slog.d(TAG, "Uid " + uid + " proc state="
                            + ActivityManager.procStateToString(procState));
                }
                if (procState != ActivityManager.PROCESS_STATE_TOP) {
                    final BackgroundStartPrivileges bsp =
                            mActivityManagerInternal.getBackgroundStartPrivileges(uid);
                    if (DEBUG) {
                        Slog.d(TAG, "Uid " + uid + ": " + bsp);
                }
                    if (!bsp.allowsBackgroundActivityStarts()) {
                        Slog.e(TAG,
                                "Uid " + uid + " not in a state to schedule user-initiated jobs");

                if (!isInStateToScheduleUiJobSource && !isInStateToScheduleUiJobCalling) {
                    Slog.e(TAG, "Uid(s) " + sourceUid + "/" + callingUid
                            + " not in a state to schedule user-initiated jobs");
                    return JobScheduler.RESULT_FAILURE;
                }
            }
            }
            if (jobWorkItem != null) {
                jobWorkItem.enforceValidity(rejectNegativeNetworkEstimates);
                if (jobWorkItem.getEstimatedNetworkDownloadBytes() != JobInfo.NETWORK_BYTES_UNKNOWN
@@ -3896,6 +3895,24 @@ public class JobSchedulerService extends com.android.server.SystemService
            return JobScheduler.RESULT_SUCCESS;
        }

        private boolean isInStateToScheduleUserInitiatedJobs(int uid, int pid, String pkgName) {
            final int procState = mActivityManagerInternal.getUidProcessState(uid);
            if (DEBUG) {
                Slog.d(TAG, "Uid " + uid + " proc state="
                        + ActivityManager.procStateToString(procState));
            }
            if (procState == ActivityManager.PROCESS_STATE_TOP) {
                return true;
            }
            final boolean canScheduleUiJobsInBg =
                    mActivityManagerInternal.canScheduleUserInitiatedJobs(uid, pid, pkgName);
            if (DEBUG) {
                Slog.d(TAG, "Uid " + uid
                        + " AM.canScheduleUserInitiatedJobs= " + canScheduleUiJobsInBg);
            }
            return canScheduleUiJobsInBg;
        }

        // IJobScheduler implementation
        @Override
        public int schedule(String namespace, JobInfo job) throws RemoteException {
@@ -3908,7 +3925,7 @@ public class JobSchedulerService extends com.android.server.SystemService

            enforceValidJobRequest(uid, pid, job);

            final int result = validateJob(job, uid, -1, null, null);
            final int result = validateJob(job, uid, pid, -1, null, null);
            if (result != JobScheduler.RESULT_SUCCESS) {
                return result;
            }
@@ -3941,7 +3958,7 @@ public class JobSchedulerService extends com.android.server.SystemService
                throw new NullPointerException("work is null");
            }

            final int result = validateJob(job, uid, -1, null, work);
            final int result = validateJob(job, uid, pid, -1, null, work);
            if (result != JobScheduler.RESULT_SUCCESS) {
                return result;
            }
@@ -3963,6 +3980,7 @@ public class JobSchedulerService extends com.android.server.SystemService
        public int scheduleAsPackage(String namespace, JobInfo job, String packageName, int userId,
                String tag) throws RemoteException {
            final int callerUid = Binder.getCallingUid();
            final int callerPid = Binder.getCallingPid();
            if (DEBUG) {
                Slog.d(TAG, "Caller uid " + callerUid + " scheduling job: " + job.toString()
                        + " on behalf of " + packageName + "/");
@@ -3979,7 +3997,7 @@ public class JobSchedulerService extends com.android.server.SystemService
                        + " not permitted to schedule jobs for other apps");
            }

            int result = validateJob(job, callerUid, userId, packageName, null);
            int result = validateJob(job, callerUid, callerPid, userId, packageName, null);
            if (result != JobScheduler.RESULT_SUCCESS) {
                return result;
            }
+6 −0
Original line number Diff line number Diff line
@@ -474,6 +474,12 @@ public abstract class ActivityManagerInternal {
    public abstract BackgroundStartPrivileges getBackgroundStartPrivileges(int uid);
    public abstract void reportCurKeyguardUsageEvent(boolean keyguardShowing);

    /**
     * Returns whether the app is in a state where it is allowed to schedule a
     * {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean) user-initiated job}.
     */
    public abstract boolean canScheduleUserInitiatedJobs(int uid, int pid, String pkgName);

    /** @see com.android.server.am.ActivityManagerService#monitor */
    public abstract void monitor();

+17 −9
Original line number Diff line number Diff line
@@ -7322,7 +7322,7 @@ public final class ActiveServices {
        if (!r.mAllowWhileInUsePermissionInFgs
                || (r.mAllowStartForeground == REASON_DENIED)) {
            final @ReasonCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
                    callingPackage, callingPid, callingUid, r, backgroundStartPrivileges,
                    callingPackage, callingPid, callingUid, r.app, backgroundStartPrivileges,
                    isBindService);
            if (!r.mAllowWhileInUsePermissionInFgs) {
                r.mAllowWhileInUsePermissionInFgs = (allowWhileInUse != REASON_DENIED);
@@ -7349,7 +7349,7 @@ public final class ActiveServices {
            return true;
        }
        final @ReasonCode int allowWhileInUse = shouldAllowFgsWhileInUsePermissionLocked(
                callingPackage, callingPid, callingUid, null /* serviceRecord */,
                callingPackage, callingPid, callingUid, null /* targetProcess */,
                BackgroundStartPrivileges.NONE, false);
        @ReasonCode int allowStartFgs = shouldAllowFgsStartForegroundNoBindingCheckLocked(
                allowWhileInUse, callingPid, callingUid, callingPackage, null /* targetService */,
@@ -7366,13 +7366,14 @@ public final class ActiveServices {
    /**
     * Should allow while-in-use permissions in FGS or not.
     * A typical BG started FGS is not allowed to have while-in-use permissions.
     *
     * @param callingPackage caller app's package name.
     * @param callingUid     caller app's uid.
     * @param targetService the service to start.
     * @param targetProcess  the process of the service to start.
     * @return {@link ReasonCode}
     */
    private @ReasonCode int shouldAllowFgsWhileInUsePermissionLocked(String callingPackage,
            int callingPid, int callingUid, @Nullable ServiceRecord targetService,
            int callingPid, int callingUid, @Nullable ProcessRecord targetProcess,
            BackgroundStartPrivileges backgroundStartPrivileges, boolean isBindService) {
        int ret = REASON_DENIED;

@@ -7440,8 +7441,8 @@ public final class ActiveServices {
        }

        if (ret == REASON_DENIED) {
            if (targetService != null && targetService.app != null) {
                ActiveInstrumentation instr = targetService.app.getActiveInstrumentation();
            if (targetProcess != null) {
                ActiveInstrumentation instr = targetProcess.getActiveInstrumentation();
                if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
                    ret = REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
                }
@@ -7526,7 +7527,7 @@ public final class ActiveServices {
                                final @ReasonCode int allowWhileInUse2 =
                                        shouldAllowFgsWhileInUsePermissionLocked(
                                                clientPackageName,
                                                clientPid, clientUid, null /* serviceRecord */,
                                                clientPid, clientUid, null /* targetProcess */,
                                                BackgroundStartPrivileges.NONE, false);
                                final @ReasonCode int allowStartFgs =
                                        shouldAllowFgsStartForegroundNoBindingCheckLocked(
@@ -7946,11 +7947,18 @@ public final class ActiveServices {
    boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
            String callingPackage) {
        return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid,
                /* targetService */ null,
                /* targetProcess */ null,
                BackgroundStartPrivileges.NONE, false)
                != REASON_DENIED;
    }

    boolean canAllowWhileInUsePermissionInFgsLocked(int callingPid, int callingUid,
            String callingPackage, @Nullable ProcessRecord targetProcess,
            @NonNull BackgroundStartPrivileges backgroundStartPrivileges) {
        return shouldAllowFgsWhileInUsePermissionLocked(callingPackage, callingPid, callingUid,
                targetProcess, backgroundStartPrivileges, false) != REASON_DENIED;
    }

    /**
     * Checks if a given packageName belongs to a given uid.
     * @param packageName the package of the caller
+23 −0
Original line number Diff line number Diff line
@@ -118,6 +118,8 @@ final class ActivityManagerConstants extends ContentObserver {
    static final String KEY_PROCESS_CRASH_COUNT_LIMIT = "process_crash_count_limit";
    static final String KEY_BOOT_TIME_TEMP_ALLOWLIST_DURATION = "boot_time_temp_allowlist_duration";
    static final String KEY_FG_TO_BG_FGS_GRACE_DURATION = "fg_to_bg_fgs_grace_duration";
    static final String KEY_VISIBLE_TO_INVISIBLE_UIJ_SCHEDULE_GRACE_DURATION =
            "vis_to_invis_uij_schedule_grace_duration";
    static final String KEY_FGS_START_FOREGROUND_TIMEOUT = "fgs_start_foreground_timeout";
    static final String KEY_FGS_ATOM_SAMPLE_RATE = "fgs_atom_sample_rate";
    static final String KEY_FGS_START_ALLOWED_LOG_SAMPLE_RATE = "fgs_start_allowed_log_sample_rate";
@@ -191,6 +193,8 @@ final class ActivityManagerConstants extends ContentObserver {
    private static final int DEFAULT_PROCESS_CRASH_COUNT_LIMIT = 12;
    private static final int DEFAULT_BOOT_TIME_TEMP_ALLOWLIST_DURATION = 20 * 1000;
    private static final long DEFAULT_FG_TO_BG_FGS_GRACE_DURATION = 5 * 1000;
    private static final long DEFAULT_VISIBLE_TO_INVISIBLE_UIJ_SCHEDULE_GRACE_DURATION =
            DEFAULT_FG_TO_BG_FGS_GRACE_DURATION;
    private static final int DEFAULT_FGS_START_FOREGROUND_TIMEOUT_MS = 10 * 1000;
    private static final float DEFAULT_FGS_ATOM_SAMPLE_RATE = 1; // 100 %
    private static final float DEFAULT_FGS_START_ALLOWED_LOG_SAMPLE_RATE = 0.25f; // 25%
@@ -679,6 +683,15 @@ final class ActivityManagerConstants extends ContentObserver {
     */
    volatile long mFgToBgFgsGraceDuration = DEFAULT_FG_TO_BG_FGS_GRACE_DURATION;

    /**
     * The grace period in milliseconds to allow a process to schedule a
     * {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean) user-initiated job}
     * after switching from visible to a non-visible state.
     * Currently it's only applicable to its activities.
     */
    volatile long mVisibleToInvisibleUijScheduleGraceDurationMs =
            DEFAULT_VISIBLE_TO_INVISIBLE_UIJ_SCHEDULE_GRACE_DURATION;

    /**
     * When service started from background, before the timeout it can be promoted to FGS by calling
     * Service.startForeground().
@@ -1123,6 +1136,9 @@ final class ActivityManagerConstants extends ContentObserver {
                            case KEY_FG_TO_BG_FGS_GRACE_DURATION:
                                updateFgToBgFgsGraceDuration();
                                break;
                            case KEY_VISIBLE_TO_INVISIBLE_UIJ_SCHEDULE_GRACE_DURATION:
                                updateFgToBgFgsGraceDuration();
                                break;
                            case KEY_FGS_START_FOREGROUND_TIMEOUT:
                                updateFgsStartForegroundTimeout();
                                break;
@@ -1598,6 +1614,13 @@ final class ActivityManagerConstants extends ContentObserver {
                DEFAULT_FG_TO_BG_FGS_GRACE_DURATION);
    }

    private void updateVisibleToInvisibleUijScheduleGraceDuration() {
        mVisibleToInvisibleUijScheduleGraceDurationMs = DeviceConfig.getLong(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                KEY_VISIBLE_TO_INVISIBLE_UIJ_SCHEDULE_GRACE_DURATION,
                DEFAULT_VISIBLE_TO_INVISIBLE_UIJ_SCHEDULE_GRACE_DURATION);
    }

    private void updateFgsStartForegroundTimeout() {
        mFgsStartForegroundTimeoutMs = DeviceConfig.getLong(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
Loading