summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java48
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java51
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) {