Merge "Let prefetch jobs run for apps with active widgets."

This commit is contained in:
TreeHugger Robot
2021-11-29 18:33:05 +00:00
committed by Android (Google) Code Review
2 changed files with 60 additions and 5 deletions

View File

@@ -28,6 +28,7 @@ import android.annotation.NonNull;
import android.app.job.JobInfo;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
@@ -63,6 +64,13 @@ public class PrefetchController extends StateController {
private final PcConstants mPcConstants;
private final PcHandler mHandler;
// Note: when determining prefetch bit satisfaction, we mark the bit as satisfied for apps with
// active widgets assuming that any prefetch jobs are being used for the widget. However, we
// don't have a callback telling us when widget status changes, which is incongruent with the
// aforementioned assumption. This inconsistency _should_ be fine since any jobs scheduled
// before the widget is activated are definitely not for the widget and don't have to be updated
// to "satisfied=true".
private AppWidgetManager mAppWidgetManager;
private final UsageStatsManagerInternal mUsageStatsManagerInternal;
@GuardedBy("mLock")
@@ -117,6 +125,11 @@ public class PrefetchController extends StateController {
.registerLaunchTimeChangedListener(mEstimatedLaunchTimeChangedListener);
}
@Override
public void onSystemServicesReady() {
mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
}
@Override
@GuardedBy("mLock")
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
@@ -298,11 +311,23 @@ public class PrefetchController extends StateController {
// Mark a prefetch constraint as satisfied in the following scenarios:
// 1. The app is not open but it will be launched soon
// 2. The app is open and the job is already running (so we let it finish)
// 3. The app is not open but has an active widget (we can't tell if a widget displays
// status/data, so this assumes the prefetch job is to update the data displayed on
// the widget).
final boolean appIsOpen = mTopUids.get(jobStatus.getSourceUid());
final boolean satisfied;
if (!appIsOpen) {
satisfied = willBeLaunchedSoonLocked(
jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), now);
final int userId = jobStatus.getSourceUserId();
final String pkgName = jobStatus.getSourcePackageName();
satisfied = willBeLaunchedSoonLocked(userId, pkgName, now)
// At the time of implementation, isBoundWidgetPackage() results in a process ID
// check and then a lookup into a map. Calling the method here every time
// is based on the assumption that widgets won't change often and
// AppWidgetManager won't be a bottleneck, so having a local cache won't provide
// huge performance gains. If anything changes, we should reconsider having a
// local cache.
|| (mAppWidgetManager != null
&& mAppWidgetManager.isBoundWidgetPackage(pkgName, userId));
} else {
satisfied = mService.isCurrentlyRunningLocked(jobStatus);
}

View File

@@ -43,6 +43,7 @@ import android.app.AlarmManager;
import android.app.job.JobInfo;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ServiceInfo;
@@ -168,12 +169,15 @@ public class PrefetchControllerTest {
}
}
private JobStatus createJobStatus(String testTag, int jobId) {
JobInfo jobInfo = new JobInfo.Builder(jobId,
private JobInfo createJobInfo(int jobId) {
return new JobInfo.Builder(jobId,
new ComponentName(mContext, "TestPrefetchJobService"))
.setPrefetch(true)
.build();
return createJobStatus(testTag, SOURCE_PACKAGE, CALLING_UID, jobInfo);
}
private JobStatus createJobStatus(String testTag, int jobId) {
return createJobStatus(testTag, SOURCE_PACKAGE, CALLING_UID, createJobInfo(jobId));
}
private static JobStatus createJobStatus(String testTag, String packageName, int callingUid,
@@ -330,6 +334,32 @@ public class PrefetchControllerTest {
assertTrue(jobRunning.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
}
@Test
public void testConstraintSatisfiedWhenWidget() {
final JobStatus jobNonWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 1);
final JobStatus jobWidget = createJobStatus("testConstraintSatisfiedWhenWidget", 2);
when(mUsageStatsManagerInternal
.getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID))
.thenReturn(sSystemClock.millis() + 100 * HOUR_IN_MILLIS);
final AppWidgetManager appWidgetManager = mock(AppWidgetManager.class);
when(mContext.getSystemService(AppWidgetManager.class)).thenReturn(appWidgetManager);
mPrefetchController.onSystemServicesReady();
when(appWidgetManager.isBoundWidgetPackage(SOURCE_PACKAGE, SOURCE_USER_ID))
.thenReturn(false);
trackJobs(jobNonWidget);
verify(mUsageStatsManagerInternal, timeout(DEFAULT_WAIT_MS))
.getEstimatedPackageLaunchTime(SOURCE_PACKAGE, SOURCE_USER_ID);
assertFalse(jobNonWidget.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
when(appWidgetManager.isBoundWidgetPackage(SOURCE_PACKAGE, SOURCE_USER_ID))
.thenReturn(true);
trackJobs(jobWidget);
assertTrue(jobWidget.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
}
@Test
public void testEstimatedLaunchTimeChangedToLate() {
setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);