Merge "Remove jobs from the pending queue on user stop."

This commit is contained in:
Kweku Adams
2023-01-30 16:48:03 +00:00
committed by Android (Google) Code Review
2 changed files with 88 additions and 5 deletions

View File

@@ -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);
}
}
}
}
}

View File

@@ -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));
}
}