Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1409c835 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents 44e67d95 2d5fb885
Loading
Loading
Loading
Loading
+27 −2
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import android.annotation.NonNull;
import android.app.job.JobInfo;
import android.app.job.JobInfo;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener;
import android.app.usage.UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Context;
import android.os.Handler;
import android.os.Handler;
import android.os.Looper;
import android.os.Looper;
@@ -63,6 +64,13 @@ public class PrefetchController extends StateController {
    private final PcConstants mPcConstants;
    private final PcConstants mPcConstants;
    private final PcHandler mHandler;
    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;
    private final UsageStatsManagerInternal mUsageStatsManagerInternal;


    @GuardedBy("mLock")
    @GuardedBy("mLock")
@@ -117,6 +125,11 @@ public class PrefetchController extends StateController {
                .registerLaunchTimeChangedListener(mEstimatedLaunchTimeChangedListener);
                .registerLaunchTimeChangedListener(mEstimatedLaunchTimeChangedListener);
    }
    }


    @Override
    public void onSystemServicesReady() {
        mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
    }

    @Override
    @Override
    @GuardedBy("mLock")
    @GuardedBy("mLock")
    public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
    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:
        // Mark a prefetch constraint as satisfied in the following scenarios:
        //   1. The app is not open but it will be launched soon
        //   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)
        //   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 appIsOpen = mTopUids.get(jobStatus.getSourceUid());
        final boolean satisfied;
        final boolean satisfied;
        if (!appIsOpen) {
        if (!appIsOpen) {
            satisfied = willBeLaunchedSoonLocked(
            final int userId = jobStatus.getSourceUserId();
                    jobStatus.getSourceUserId(), jobStatus.getSourcePackageName(), now);
            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 {
        } else {
            satisfied = mService.isCurrentlyRunningLocked(jobStatus);
            satisfied = mService.isCurrentlyRunningLocked(jobStatus);
        }
        }
+33 −3
Original line number Original line Diff line number Diff line
@@ -43,6 +43,7 @@ import android.app.AlarmManager;
import android.app.job.JobInfo;
import android.app.job.JobInfo;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener;
import android.app.usage.UsageStatsManagerInternal.EstimatedLaunchTimeChangedListener;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.content.pm.ServiceInfo;
@@ -168,12 +169,15 @@ public class PrefetchControllerTest {
        }
        }
    }
    }


    private JobStatus createJobStatus(String testTag, int jobId) {
    private JobInfo createJobInfo(int jobId) {
        JobInfo jobInfo = new JobInfo.Builder(jobId,
        return new JobInfo.Builder(jobId,
                new ComponentName(mContext, "TestPrefetchJobService"))
                new ComponentName(mContext, "TestPrefetchJobService"))
                .setPrefetch(true)
                .setPrefetch(true)
                .build();
                .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,
    private static JobStatus createJobStatus(String testTag, String packageName, int callingUid,
@@ -330,6 +334,32 @@ public class PrefetchControllerTest {
        assertTrue(jobRunning.isConstraintSatisfied(JobStatus.CONSTRAINT_PREFETCH));
        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
    @Test
    public void testEstimatedLaunchTimeChangedToLate() {
    public void testEstimatedLaunchTimeChangedToLate() {
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);
        setDeviceConfigLong(PcConstants.KEY_LAUNCH_TIME_THRESHOLD_MS, 7 * HOUR_IN_MILLIS);