Remove jobs from the pending queue on user stop.
Remove jobs from the pending queue when the user stops the app via Task Manager so we don't immediately restart the process. Bug: 261999509 Test: atest FrameworksMockingServicesTests:JobSchedulerServiceTest Change-Id: I76f9bb9778ca9b2fd3cfaef99430334547206ad4
This commit is contained in:
@@ -1584,6 +1584,12 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
return reason;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@JobScheduler.PendingJobReason
|
||||
int getPendingJobReason(JobStatus job) {
|
||||
return getPendingJobReason(job.getUid(), job.getNamespace(), job.getJobId());
|
||||
}
|
||||
|
||||
@JobScheduler.PendingJobReason
|
||||
@GuardedBy("mLock")
|
||||
private int getPendingJobReasonLocked(int uid, String namespace, int jobId) {
|
||||
@@ -1694,7 +1700,8 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
}
|
||||
}
|
||||
|
||||
private void stopUserVisibleJobsInternal(@NonNull String packageName, int userId) {
|
||||
@VisibleForTesting
|
||||
void stopUserVisibleJobsInternal(@NonNull String packageName, int userId) {
|
||||
final int packageUid = mLocalPM.getPackageUid(packageName, 0, userId);
|
||||
if (packageUid < 0) {
|
||||
Slog.wtf(TAG, "Asked to stop jobs of an unknown package");
|
||||
@@ -1716,6 +1723,21 @@ public class JobSchedulerService extends com.android.server.SystemService
|
||||
// to stop only that work, B's jobs would be demoted as well.
|
||||
// TODO(255768978): make it possible to demote only the relevant subset of jobs
|
||||
job.addInternalFlags(JobStatus.INTERNAL_FLAG_DEMOTED_BY_USER);
|
||||
|
||||
// The app process will be killed soon. There's no point keeping its jobs in
|
||||
// the pending queue to try and start them.
|
||||
if (mPendingJobQueue.remove(job)) {
|
||||
synchronized (mPendingJobReasonCache) {
|
||||
SparseIntArray jobIdToReason = mPendingJobReasonCache.get(
|
||||
job.getUid(), job.getNamespace());
|
||||
if (jobIdToReason == null) {
|
||||
jobIdToReason = new SparseIntArray();
|
||||
mPendingJobReasonCache.add(job.getUid(), job.getNamespace(),
|
||||
jobIdToReason);
|
||||
}
|
||||
jobIdToReason.put(job.getJobId(), JobScheduler.PENDING_JOB_REASON_USER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,9 @@ import static com.android.server.job.JobSchedulerService.RARE_INDEX;
|
||||
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
@@ -95,6 +97,8 @@ public class JobSchedulerServiceTest {
|
||||
private ActivityManagerInternal mActivityMangerInternal;
|
||||
@Mock
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private PackageManagerInternal mPackageManagerInternal;
|
||||
|
||||
private class TestJobSchedulerService extends JobSchedulerService {
|
||||
TestJobSchedulerService(Context context) {
|
||||
@@ -121,6 +125,8 @@ public class JobSchedulerServiceTest {
|
||||
.when(() -> LocalServices.getService(AppStandbyInternal.class));
|
||||
doReturn(mock(BatteryManagerInternal.class))
|
||||
.when(() -> LocalServices.getService(BatteryManagerInternal.class));
|
||||
doReturn(mPackageManagerInternal)
|
||||
.when(() -> LocalServices.getService(PackageManagerInternal.class));
|
||||
doReturn(mock(UsageStatsManagerInternal.class))
|
||||
.when(() -> LocalServices.getService(UsageStatsManagerInternal.class));
|
||||
when(mContext.getString(anyInt())).thenReturn("some_test_string");
|
||||
@@ -138,9 +144,6 @@ public class JobSchedulerServiceTest {
|
||||
// Used in JobConcurrencyManager.
|
||||
doReturn(mock(UserManagerInternal.class))
|
||||
.when(() -> LocalServices.getService(UserManagerInternal.class));
|
||||
// Used in JobStatus.
|
||||
doReturn(mock(PackageManagerInternal.class))
|
||||
.when(() -> LocalServices.getService(PackageManagerInternal.class));
|
||||
// Called via IdleController constructor.
|
||||
when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
|
||||
when(mContext.getResources()).thenReturn(mock(Resources.class));
|
||||
@@ -197,8 +200,13 @@ public class JobSchedulerServiceTest {
|
||||
|
||||
private JobStatus createJobStatus(String testTag, JobInfo.Builder jobInfoBuilder,
|
||||
int callingUid) {
|
||||
return createJobStatus(testTag, jobInfoBuilder, callingUid, "com.android.test");
|
||||
}
|
||||
|
||||
private JobStatus createJobStatus(String testTag, JobInfo.Builder jobInfoBuilder,
|
||||
int callingUid, String sourcePkg) {
|
||||
return JobStatus.createFromJobInfo(
|
||||
jobInfoBuilder.build(), callingUid, "com.android.test", 0, "JSSTest", testTag);
|
||||
jobInfoBuilder.build(), callingUid, sourcePkg, 0, "JSSTest", testTag);
|
||||
}
|
||||
|
||||
private void grantRunLongJobsPermission(boolean grant) {
|
||||
@@ -1238,4 +1246,57 @@ public class JobSchedulerServiceTest {
|
||||
0, "JSSTest", ""));
|
||||
}
|
||||
}
|
||||
|
||||
/** Tests that jobs are removed from the pending list if the user stops the app. */
|
||||
@Test
|
||||
public void testUserStopRemovesPending() {
|
||||
spyOn(mService);
|
||||
|
||||
JobStatus job1a = createJobStatus("testUserStopRemovesPending",
|
||||
createJobInfo(1), 1, "pkg1");
|
||||
JobStatus job1b = createJobStatus("testUserStopRemovesPending",
|
||||
createJobInfo(2), 1, "pkg1");
|
||||
JobStatus job2a = createJobStatus("testUserStopRemovesPending",
|
||||
createJobInfo(1), 2, "pkg2");
|
||||
JobStatus job2b = createJobStatus("testUserStopRemovesPending",
|
||||
createJobInfo(2), 2, "pkg2");
|
||||
doReturn(1).when(mPackageManagerInternal).getPackageUid("pkg1", 0, 0);
|
||||
doReturn(11).when(mPackageManagerInternal).getPackageUid("pkg1", 0, 1);
|
||||
doReturn(2).when(mPackageManagerInternal).getPackageUid("pkg2", 0, 0);
|
||||
|
||||
mService.getPendingJobQueue().clear();
|
||||
mService.getPendingJobQueue().add(job1a);
|
||||
mService.getPendingJobQueue().add(job1b);
|
||||
mService.getPendingJobQueue().add(job2a);
|
||||
mService.getPendingJobQueue().add(job2b);
|
||||
mService.getJobStore().add(job1a);
|
||||
mService.getJobStore().add(job1b);
|
||||
mService.getJobStore().add(job2a);
|
||||
mService.getJobStore().add(job2b);
|
||||
|
||||
mService.stopUserVisibleJobsInternal("pkg1", 1);
|
||||
assertEquals(4, mService.getPendingJobQueue().size());
|
||||
assertTrue(mService.getPendingJobQueue().contains(job1a));
|
||||
assertTrue(mService.getPendingJobQueue().contains(job1b));
|
||||
assertTrue(mService.getPendingJobQueue().contains(job2a));
|
||||
assertTrue(mService.getPendingJobQueue().contains(job2b));
|
||||
|
||||
mService.stopUserVisibleJobsInternal("pkg1", 0);
|
||||
assertEquals(2, mService.getPendingJobQueue().size());
|
||||
assertFalse(mService.getPendingJobQueue().contains(job1a));
|
||||
assertEquals(JobScheduler.PENDING_JOB_REASON_USER, mService.getPendingJobReason(job1a));
|
||||
assertFalse(mService.getPendingJobQueue().contains(job1b));
|
||||
assertEquals(JobScheduler.PENDING_JOB_REASON_USER, mService.getPendingJobReason(job1b));
|
||||
assertTrue(mService.getPendingJobQueue().contains(job2a));
|
||||
assertTrue(mService.getPendingJobQueue().contains(job2b));
|
||||
|
||||
mService.stopUserVisibleJobsInternal("pkg2", 0);
|
||||
assertEquals(0, mService.getPendingJobQueue().size());
|
||||
assertFalse(mService.getPendingJobQueue().contains(job1a));
|
||||
assertFalse(mService.getPendingJobQueue().contains(job1b));
|
||||
assertFalse(mService.getPendingJobQueue().contains(job2a));
|
||||
assertEquals(JobScheduler.PENDING_JOB_REASON_USER, mService.getPendingJobReason(job2a));
|
||||
assertFalse(mService.getPendingJobQueue().contains(job2b));
|
||||
assertEquals(JobScheduler.PENDING_JOB_REASON_USER, mService.getPendingJobReason(job2b));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user