diff options
| -rw-r--r-- | apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java | 48 | ||||
| -rw-r--r-- | apex/jobscheduler/service/java/com/android/server/job/JobStore.java | 51 |
2 files changed, 70 insertions, 29 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java index 4d5eef2f65f5..dbac4c57f5ba 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java @@ -882,6 +882,8 @@ public class JobSchedulerService extends com.android.server.SystemService // a user-initiated action, it should be fine to just // put USER instead of UNINSTALL or DISABLED. cancelJobsForPackageAndUidLocked(pkgName, pkgUid, + /* includeSchedulingApp */ true, + /* includeSourceApp */ true, JobParameters.STOP_REASON_USER, JobParameters.INTERNAL_STOP_REASON_UNINSTALL, "app disabled"); @@ -932,6 +934,7 @@ public class JobSchedulerService extends com.android.server.SystemService // get here, but since this is generally a user-initiated action, it should // be fine to just put USER instead of UNINSTALL or DISABLED. cancelJobsForPackageAndUidLocked(pkgName, pkgUid, + /* includeSchedulingApp */ true, /* includeSourceApp */ true, JobParameters.STOP_REASON_USER, JobParameters.INTERNAL_STOP_REASON_UNINSTALL, "app uninstalled"); for (int c = 0; c < mControllers.size(); ++c) { @@ -986,7 +989,12 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "Removing jobs for pkg " + pkgName + " at uid " + pkgUid); } synchronized (mLock) { + // Exclude jobs scheduled on behalf of this app for now because SyncManager + // and other job proxy agents may not know to reschedule the job properly + // after force stop. + // TODO(209852664): determine how to best handle syncs & other proxied jobs cancelJobsForPackageAndUidLocked(pkgName, pkgUid, + /* includeSchedulingApp */ true, /* includeSourceApp */ false, JobParameters.STOP_REASON_USER, JobParameters.INTERNAL_STOP_REASON_CANCELED, "app force stopped"); @@ -1304,16 +1312,18 @@ public class JobSchedulerService extends com.android.server.SystemService } } + private final Consumer<JobStatus> mCancelJobDueToUserRemovalConsumer = (toRemove) -> { + // There's no guarantee that the process has been stopped by the time we get + // here, but since this is a user-initiated action, it should be fine to just + // put USER instead of UNINSTALL or DISABLED. + cancelJobImplLocked(toRemove, null, JobParameters.STOP_REASON_USER, + JobParameters.INTERNAL_STOP_REASON_UNINSTALL, "user removed"); + }; + private void cancelJobsForUserLocked(int userHandle) { - final List<JobStatus> jobsForUser = mJobs.getJobsByUser(userHandle); - for (int i = 0; i < jobsForUser.size(); i++) { - JobStatus toRemove = jobsForUser.get(i); - // There's no guarantee that the process has been stopped by the time we get here, - // but since this is a user-initiated action, it should be fine to just put USER - // instead of UNINSTALL or DISABLED. - cancelJobImplLocked(toRemove, null, JobParameters.STOP_REASON_USER, - JobParameters.INTERNAL_STOP_REASON_UNINSTALL, "user removed"); - } + mJobs.forEachJob( + (job) -> job.getUserId() == userHandle || job.getSourceUserId() == userHandle, + mCancelJobDueToUserRemovalConsumer); } private void cancelJobsForNonExistentUsers() { @@ -1324,15 +1334,31 @@ public class JobSchedulerService extends com.android.server.SystemService } private void cancelJobsForPackageAndUidLocked(String pkgName, int uid, + boolean includeSchedulingApp, boolean includeSourceApp, @JobParameters.StopReason int reason, int internalReasonCode, String debugReason) { + if (!includeSchedulingApp && !includeSourceApp) { + Slog.wtfStack(TAG, + "Didn't indicate whether to cancel jobs for scheduling and/or source app"); + includeSourceApp = true; + } if ("android".equals(pkgName)) { Slog.wtfStack(TAG, "Can't cancel all jobs for system package"); return; } - final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid); + final List<JobStatus> jobsForUid = new ArrayList<>(); + if (includeSchedulingApp) { + mJobs.getJobsByUid(uid, jobsForUid); + } + if (includeSourceApp) { + mJobs.getJobsBySourceUid(uid, jobsForUid); + } for (int i = jobsForUid.size() - 1; i >= 0; i--) { final JobStatus job = jobsForUid.get(i); - if (job.getSourcePackageName().equals(pkgName)) { + final boolean shouldCancel = + (includeSchedulingApp + && job.getServiceComponent().getPackageName().equals(pkgName)) + || (includeSourceApp && job.getSourcePackageName().equals(pkgName)); + if (shouldCancel) { cancelJobImplLocked(job, null, reason, internalReasonCode, debugReason); } } diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java index dfa1442a3192..7dcd1ec47278 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java @@ -22,6 +22,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; import static com.android.server.job.JobSchedulerService.sSystemClock; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.job.JobInfo; import android.content.ComponentName; @@ -32,7 +33,6 @@ import android.os.Handler; import android.os.PersistableBundle; import android.os.Process; import android.os.SystemClock; -import android.os.UserHandle; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArraySet; @@ -287,26 +287,37 @@ public final class JobStore { } /** - * @param userHandle User for whom we are querying the list of jobs. - * @return A list of all the jobs scheduled for the provided user. Never null. + * @param sourceUid Uid of the source app. + * @return A list of all the jobs scheduled for the source app. Never null. */ - public List<JobStatus> getJobsByUser(int userHandle) { - return mJobSet.getJobsByUser(userHandle); + @NonNull + public List<JobStatus> getJobsBySourceUid(int sourceUid) { + return mJobSet.getJobsBySourceUid(sourceUid); + } + + public void getJobsBySourceUid(int sourceUid, @NonNull List<JobStatus> insertInto) { + mJobSet.getJobsBySourceUid(sourceUid, insertInto); } /** * @param uid Uid of the requesting app. * @return All JobStatus objects for a given uid from the master list. Never null. */ + @NonNull public List<JobStatus> getJobsByUid(int uid) { return mJobSet.getJobsByUid(uid); } + public void getJobsByUid(int uid, @NonNull List<JobStatus> insertInto) { + mJobSet.getJobsByUid(uid, insertInto); + } + /** * @param uid Uid of the requesting app. * @param jobId Job id, specified at schedule-time. * @return the JobStatus that matches the provided uId and jobId, or null if none found. */ + @Nullable public JobStatus getJobByUidAndJobId(int uid, int jobId) { return mJobSet.get(uid, jobId); } @@ -1207,27 +1218,31 @@ public final class JobStore { public List<JobStatus> getJobsByUid(int uid) { ArrayList<JobStatus> matchingJobs = new ArrayList<JobStatus>(); + getJobsByUid(uid, matchingJobs); + return matchingJobs; + } + + public void getJobsByUid(int uid, List<JobStatus> insertInto) { ArraySet<JobStatus> jobs = mJobs.get(uid); if (jobs != null) { - matchingJobs.addAll(jobs); + insertInto.addAll(jobs); } - return matchingJobs; } - // By user, not by uid, so we need to traverse by key and check - public List<JobStatus> getJobsByUser(int userId) { + @NonNull + public List<JobStatus> getJobsBySourceUid(int sourceUid) { final ArrayList<JobStatus> result = new ArrayList<JobStatus>(); - for (int i = mJobsPerSourceUid.size() - 1; i >= 0; i--) { - if (UserHandle.getUserId(mJobsPerSourceUid.keyAt(i)) == userId) { - final ArraySet<JobStatus> jobs = mJobsPerSourceUid.valueAt(i); - if (jobs != null) { - result.addAll(jobs); - } - } - } + getJobsBySourceUid(sourceUid, result); return result; } + public void getJobsBySourceUid(int sourceUid, List<JobStatus> insertInto) { + final ArraySet<JobStatus> jobs = mJobsPerSourceUid.get(sourceUid); + if (jobs != null) { + insertInto.addAll(jobs); + } + } + public boolean add(JobStatus job) { final int uid = job.getUid(); final int sourceUid = job.getSourceUid(); @@ -1369,7 +1384,7 @@ public final class JobStore { } public void forEachJob(@Nullable Predicate<JobStatus> filterPredicate, - Consumer<JobStatus> functor) { + @NonNull Consumer<JobStatus> functor) { for (int uidIndex = mJobs.size() - 1; uidIndex >= 0; uidIndex--) { ArraySet<JobStatus> jobs = mJobs.valueAt(uidIndex); if (jobs != null) { |