Merge "Remove jobs from the pending queue on user stop."
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