Merge "Cancel all jobs associated with a UID when appropriate."

This commit is contained in:
Kweku Adams
2022-10-15 18:50:25 +00:00
committed by Android (Google) Code Review
5 changed files with 51 additions and 33 deletions

View File

@@ -36,9 +36,11 @@ public interface JobSchedulerInternal {
/**
* Cancel the jobs for a given uid (e.g. when app data is cleared)
*
* @param includeProxiedJobs Include jobs scheduled for this UID by other apps
*/
void cancelJobsForUid(int uid, @JobParameters.StopReason int reason, int debugReasonCode,
String debugReason);
void cancelJobsForUid(int uid, boolean includeProxiedJobs,
@JobParameters.StopReason int reason, int debugReasonCode, String debugReason);
/**
* These are for activity manager to communicate to use what is currently performing backups.

View File

@@ -970,12 +970,12 @@ public class JobSchedulerService extends com.android.server.SystemService
// Has this package scheduled any jobs, such that we will take action
// if it were to be force-stopped?
if (pkgUid != -1) {
List<JobStatus> jobsForUid;
ArraySet<JobStatus> jobsForUid;
synchronized (mLock) {
jobsForUid = mJobs.getJobsByUid(pkgUid);
}
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
if (jobsForUid.get(i).getSourcePackageName().equals(pkgName)) {
if (jobsForUid.valueAt(i).getSourcePackageName().equals(pkgName)) {
if (DEBUG) {
Slog.d(TAG, "Restart query: package " + pkgName + " at uid "
+ pkgUid + " has jobs");
@@ -1292,10 +1292,11 @@ public class JobSchedulerService extends com.android.server.SystemService
public List<JobInfo> getPendingJobs(int uid) {
synchronized (mLock) {
List<JobStatus> jobs = mJobs.getJobsByUid(uid);
ArraySet<JobStatus> jobs = mJobs.getJobsByUid(uid);
ArrayList<JobInfo> outList = new ArrayList<JobInfo>(jobs.size());
// Write out for loop to avoid addAll() creating an Iterator.
for (int i = jobs.size() - 1; i >= 0; i--) {
JobStatus job = jobs.get(i);
final JobStatus job = jobs.valueAt(i);
outList.add(job.getJob());
}
return outList;
@@ -1304,9 +1305,9 @@ public class JobSchedulerService extends com.android.server.SystemService
public JobInfo getPendingJob(int uid, int jobId) {
synchronized (mLock) {
List<JobStatus> jobs = mJobs.getJobsByUid(uid);
ArraySet<JobStatus> jobs = mJobs.getJobsByUid(uid);
for (int i = jobs.size() - 1; i >= 0; i--) {
JobStatus job = jobs.get(i);
JobStatus job = jobs.valueAt(i);
if (job.getJobId() == jobId) {
return job.getJob();
}
@@ -1348,7 +1349,7 @@ public class JobSchedulerService extends com.android.server.SystemService
Slog.wtfStack(TAG, "Can't cancel all jobs for system package");
return;
}
final List<JobStatus> jobsForUid = new ArrayList<>();
final ArraySet<JobStatus> jobsForUid = new ArraySet<>();
if (includeSchedulingApp) {
mJobs.getJobsByUid(uid, jobsForUid);
}
@@ -1356,7 +1357,7 @@ public class JobSchedulerService extends com.android.server.SystemService
mJobs.getJobsBySourceUid(uid, jobsForUid);
}
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
final JobStatus job = jobsForUid.get(i);
final JobStatus job = jobsForUid.valueAt(i);
final boolean shouldCancel =
(includeSchedulingApp
&& job.getServiceComponent().getPackageName().equals(pkgName))
@@ -1368,14 +1369,16 @@ public class JobSchedulerService extends com.android.server.SystemService
}
/**
* Entry point from client to cancel all jobs originating from their uid.
* Entry point from client to cancel all jobs scheduled for or from their uid.
* This will remove the job from the master list, and cancel the job if it was staged for
* execution or being executed.
*
* @param uid Uid to check against for removal of a job.
* @param includeSourceApp Whether to include jobs scheduled for this UID by another UID.
* If false, only jobs scheduled by this UID will be cancelled.
*/
public boolean cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
int internalReasonCode, String debugReason) {
public boolean cancelJobsForUid(int uid, boolean includeSourceApp,
@JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
if (uid == Process.SYSTEM_UID) {
Slog.wtfStack(TAG, "Can't cancel all jobs for system uid");
return false;
@@ -1383,9 +1386,15 @@ public class JobSchedulerService extends com.android.server.SystemService
boolean jobsCanceled = false;
synchronized (mLock) {
final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
final ArraySet<JobStatus> jobsForUid = new ArraySet<>();
// Get jobs scheduled by the app.
mJobs.getJobsByUid(uid, jobsForUid);
if (includeSourceApp) {
// Get jobs scheduled for the app by someone else.
mJobs.getJobsBySourceUid(uid, jobsForUid);
}
for (int i = 0; i < jobsForUid.size(); i++) {
JobStatus toRemove = jobsForUid.get(i);
JobStatus toRemove = jobsForUid.valueAt(i);
cancelJobImplLocked(toRemove, null, reason, internalReasonCode, debugReason);
jobsCanceled = true;
}
@@ -2220,6 +2229,7 @@ public class JobSchedulerService extends com.android.server.SystemService
updateUidState(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
if (disabled) {
cancelJobsForUid(uid,
/* includeSourceApp */ true,
JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
"uid gone");
@@ -2241,6 +2251,7 @@ public class JobSchedulerService extends com.android.server.SystemService
final boolean disabled = message.arg2 != 0;
if (disabled) {
cancelJobsForUid(uid,
/* includeSourceApp */ true,
JobParameters.STOP_REASON_BACKGROUND_RESTRICTION,
JobParameters.INTERNAL_STOP_REASON_CONSTRAINTS_NOT_SATISFIED,
"app uid idle");
@@ -2899,9 +2910,10 @@ public class JobSchedulerService extends com.android.server.SystemService
}
@Override
public void cancelJobsForUid(int uid, @JobParameters.StopReason int reason,
int internalReasonCode, String debugReason) {
JobSchedulerService.this.cancelJobsForUid(uid, reason, internalReasonCode, debugReason);
public void cancelJobsForUid(int uid, boolean includeProxiedJobs,
@JobParameters.StopReason int reason, int internalReasonCode, String debugReason) {
JobSchedulerService.this.cancelJobsForUid(uid,
includeProxiedJobs, reason, internalReasonCode, debugReason);
}
@Override
@@ -3273,6 +3285,8 @@ public class JobSchedulerService extends com.android.server.SystemService
final long ident = Binder.clearCallingIdentity();
try {
JobSchedulerService.this.cancelJobsForUid(uid,
// Documentation says only jobs scheduled BY the app will be cancelled
/* includeSourceApp */ false,
JobParameters.STOP_REASON_CANCELLED_BY_APP,
JobParameters.INTERNAL_STOP_REASON_CANCELED,
"cancelAll() called by app, callingUid=" + uid);
@@ -3484,7 +3498,9 @@ public class JobSchedulerService extends com.android.server.SystemService
if (!hasJobId) {
pw.println("Canceling all jobs for " + pkgName + " in user " + userId);
if (!cancelJobsForUid(pkgUid, JobParameters.STOP_REASON_USER,
if (!cancelJobsForUid(pkgUid,
/* includeSourceApp */ false,
JobParameters.STOP_REASON_USER,
JobParameters.INTERNAL_STOP_REASON_CANCELED,
"cancel shell command for package")) {
pw.println("No matching jobs found.");

View File

@@ -291,11 +291,11 @@ public final class JobStore {
* @return A list of all the jobs scheduled for the source app. Never null.
*/
@NonNull
public List<JobStatus> getJobsBySourceUid(int sourceUid) {
public ArraySet<JobStatus> getJobsBySourceUid(int sourceUid) {
return mJobSet.getJobsBySourceUid(sourceUid);
}
public void getJobsBySourceUid(int sourceUid, @NonNull List<JobStatus> insertInto) {
public void getJobsBySourceUid(int sourceUid, @NonNull Set<JobStatus> insertInto) {
mJobSet.getJobsBySourceUid(sourceUid, insertInto);
}
@@ -304,11 +304,11 @@ public final class JobStore {
* @return All JobStatus objects for a given uid from the master list. Never null.
*/
@NonNull
public List<JobStatus> getJobsByUid(int uid) {
public ArraySet<JobStatus> getJobsByUid(int uid) {
return mJobSet.getJobsByUid(uid);
}
public void getJobsByUid(int uid, @NonNull List<JobStatus> insertInto) {
public void getJobsByUid(int uid, @NonNull Set<JobStatus> insertInto) {
mJobSet.getJobsByUid(uid, insertInto);
}
@@ -1232,13 +1232,13 @@ public final class JobStore {
mJobsPerSourceUid = new SparseArray<>();
}
public List<JobStatus> getJobsByUid(int uid) {
ArrayList<JobStatus> matchingJobs = new ArrayList<JobStatus>();
public ArraySet<JobStatus> getJobsByUid(int uid) {
ArraySet<JobStatus> matchingJobs = new ArraySet<>();
getJobsByUid(uid, matchingJobs);
return matchingJobs;
}
public void getJobsByUid(int uid, List<JobStatus> insertInto) {
public void getJobsByUid(int uid, Set<JobStatus> insertInto) {
ArraySet<JobStatus> jobs = mJobs.get(uid);
if (jobs != null) {
insertInto.addAll(jobs);
@@ -1246,13 +1246,13 @@ public final class JobStore {
}
@NonNull
public List<JobStatus> getJobsBySourceUid(int sourceUid) {
final ArrayList<JobStatus> result = new ArrayList<JobStatus>();
public ArraySet<JobStatus> getJobsBySourceUid(int sourceUid) {
final ArraySet<JobStatus> result = new ArraySet<>();
getJobsBySourceUid(sourceUid, result);
return result;
}
public void getJobsBySourceUid(int sourceUid, List<JobStatus> insertInto) {
public void getJobsBySourceUid(int sourceUid, Set<JobStatus> insertInto) {
final ArraySet<JobStatus> jobs = mJobsPerSourceUid.get(sourceUid);
if (jobs != null) {
insertInto.addAll(jobs);

View File

@@ -50,7 +50,6 @@ import com.android.server.utils.AlarmQueue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
/**
@@ -397,10 +396,10 @@ public final class FlexibilityController extends StateController {
return;
}
final long nowElapsed = sElapsedRealtimeClock.millis();
List<JobStatus> jobsByUid = mService.getJobStore().getJobsByUid(uid);
ArraySet<JobStatus> jobsByUid = mService.getJobStore().getJobsBySourceUid(uid);
boolean hasPrefetch = false;
for (int i = 0; i < jobsByUid.size(); i++) {
JobStatus js = jobsByUid.get(i);
JobStatus js = jobsByUid.valueAt(i);
if (js.hasFlexibilityConstraint()) {
js.setFlexibilityConstraintSatisfied(nowElapsed, isFlexibilitySatisfiedLocked(js));
hasPrefetch |= js.getJob().isPrefetch();

View File

@@ -3937,7 +3937,8 @@ public class ActivityManagerService extends IActivityManager.Stub
// Clear its scheduled jobs
JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class);
// Clearing data is a user-initiated action.
js.cancelJobsForUid(appInfo.uid, JobParameters.STOP_REASON_USER,
js.cancelJobsForUid(appInfo.uid, /* includeProxiedJobs */ true,
JobParameters.STOP_REASON_USER,
JobParameters.INTERNAL_STOP_REASON_DATA_CLEARED, "clear data");
// Clear its pending alarms