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

Commit 8cff21c0 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Require permission for setUserInitiated()."

parents 90d98182 f60cd87a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -400,6 +400,8 @@ public abstract class JobScheduler {
     * Returns {@code true} if the app currently holds the
     * {@link android.Manifest.permission#RUN_LONG_JOBS} permission, allowing it to run long jobs.
     * @hide
     * TODO(255371817): consider exposing this to apps who could call
     * {@link #scheduleAsPackage(JobInfo, String, int, String)}
     */
    public boolean hasRunLongJobsPermission(@NonNull String packageName, @UserIdInt int userId) {
        return false;
+65 −10
Original line number Diff line number Diff line
@@ -3660,11 +3660,8 @@ public class JobSchedulerService extends com.android.server.SystemService
            return canPersist;
        }

        private void validateJob(JobInfo job, int callingUid) {
            validateJob(job, callingUid, null);
        }

        private void validateJob(JobInfo job, int callingUid, @Nullable JobWorkItem jobWorkItem) {
        private int validateJob(@NonNull JobInfo job, int callingUid, int sourceUserId,
                @Nullable String sourcePkgName, @Nullable JobWorkItem jobWorkItem) {
            final boolean rejectNegativeNetworkEstimates = CompatChanges.isChangeEnabled(
                            JobInfo.REJECT_NEGATIVE_NETWORK_ESTIMATES, callingUid);
            job.enforceValidity(
@@ -3684,6 +3681,37 @@ public class JobSchedulerService extends com.android.server.SystemService
                            + " FLAG_EXEMPT_FROM_APP_STANDBY. Job=" + job);
                }
            }
            if (job.isUserInitiated()) {
                int sourceUid = -1;
                if (sourceUserId != -1 && sourcePkgName != null) {
                    try {
                        sourceUid = AppGlobals.getPackageManager().getPackageUid(
                                sourcePkgName, 0, sourceUserId);
                    } catch (RemoteException ex) {
                        // Can't happen, PackageManager runs in the same process.
                    }
                }
                // 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.
                if (sourceUid != -1) {
                    // Check the permission of the source app.
                    final int sourceResult =
                            validateRunLongJobsPermission(sourceUid, sourcePkgName);
                    if (sourceResult != JobScheduler.RESULT_SUCCESS) {
                        return sourceResult;
                    }
                }
                final String callingPkgName = job.getService().getPackageName();
                if (callingUid != sourceUid || !callingPkgName.equals(sourcePkgName)) {
                    // Source app is different from calling app. Make sure the calling app also has
                    // the permission.
                    final int callingResult =
                            validateRunLongJobsPermission(callingUid, callingPkgName);
                    if (callingResult != JobScheduler.RESULT_SUCCESS) {
                        return callingResult;
                    }
                }
            }
            if (jobWorkItem != null) {
                jobWorkItem.enforceValidity(rejectNegativeNetworkEstimates);
                if (jobWorkItem.getEstimatedNetworkDownloadBytes() != JobInfo.NETWORK_BYTES_UNKNOWN
@@ -3704,6 +3732,19 @@ public class JobSchedulerService extends com.android.server.SystemService
                    }
                }
            }
            return JobScheduler.RESULT_SUCCESS;
        }

        private int validateRunLongJobsPermission(int uid, String packageName) {
            final int state = getRunLongJobsPermissionState(uid, packageName);
            if (state == PermissionChecker.PERMISSION_HARD_DENIED) {
                throw new SecurityException(android.Manifest.permission.RUN_LONG_JOBS
                        + " required to schedule user-initiated jobs.");
            }
            if (state == PermissionChecker.PERMISSION_SOFT_DENIED) {
                return JobScheduler.RESULT_FAILURE;
            }
            return JobScheduler.RESULT_SUCCESS;
        }

        // IJobScheduler implementation
@@ -3724,7 +3765,10 @@ public class JobSchedulerService extends com.android.server.SystemService
                }
            }

            validateJob(job, uid);
            final int result = validateJob(job, uid, -1, null, null);
            if (result != JobScheduler.RESULT_SUCCESS) {
                return result;
            }

            final long ident = Binder.clearCallingIdentity();
            try {
@@ -3752,7 +3796,10 @@ public class JobSchedulerService extends com.android.server.SystemService
                throw new NullPointerException("work is null");
            }

            validateJob(job, uid, work);
            final int result = validateJob(job, uid, -1, null, work);
            if (result != JobScheduler.RESULT_SUCCESS) {
                return result;
            }

            final long ident = Binder.clearCallingIdentity();
            try {
@@ -3783,7 +3830,10 @@ public class JobSchedulerService extends com.android.server.SystemService
                        + " not permitted to schedule jobs for other apps");
            }

            validateJob(job, callerUid);
            int result = validateJob(job, callerUid, userId, packageName, null);
            if (result != JobScheduler.RESULT_SUCCESS) {
                return result;
            }

            final long ident = Binder.clearCallingIdentity();
            try {
@@ -4257,11 +4307,16 @@ public class JobSchedulerService extends com.android.server.SystemService
        return 0;
    }

    /** Returns true if both the appop and permission are granted. */
    private boolean checkRunLongJobsPermission(int packageUid, String packageName) {
        // Returns true if both the appop and permission are granted.
        return getRunLongJobsPermissionState(packageUid, packageName)
                == PermissionChecker.PERMISSION_GRANTED;
    }

    private int getRunLongJobsPermissionState(int packageUid, String packageName) {
        return PermissionChecker.checkPermissionForPreflight(getTestableContext(),
                android.Manifest.permission.RUN_LONG_JOBS, PermissionChecker.PID_UNKNOWN,
                packageUid, packageName) == PermissionChecker.PERMISSION_GRANTED;
                packageUid, packageName);
    }

    @VisibleForTesting