Fix reliability triggering

Fix reliability triggering in the time zone update
feature. The reliability triggering is there to
resume an update check when things go wrong. For
example, if the device is turned off after a
time zone data app is updated but before the time
zone update process has finished pulling the data
out and installing it in /data. The reliability
trigger happens when the device is idle and will
complete the work.

The idle triggering currently doesn't work as it
was implemented incorrectly.

The code has been changed to use the
JobScheduler to trigger on idle and scheduling
has been made explicit.

Unit tests run with:

make -j30 FrameworksServicesTests
adb install -r -g \
  "out/target/product/marlin/data/app/FrameworksServicesTests/FrameworksServicesTests.apk"
adb shell am instrument -e package com.android.server.timezone -w \
  com.android.frameworks.servicestests \
  "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner"

Test: See above
Test: Manual testing: adb shell am idle-maintenance, adb logcat/adb shell dumpsys timezone
Test: PTS: run pts -m PtsTimeZoneTestCases
Bug: 65657543
Change-Id: Ibb2c537955d09a5d538c50490dae94a518522f19
Merged-In: Ibb2c537955d09a5d538c50490dae94a518522f19
(cherry picked from commit cd1a109b872f58f5baa0ce8438bf3ddd69eec9fc)
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9a4d63c..0668b8b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3764,6 +3764,10 @@
         <service android:name="com.android.server.PreloadsFileCacheExpirationJobService"
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
+
+        <service android:name="com.android.server.timezone.TimeZoneUpdateIdler"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
     </application>
 
 </manifest>
diff --git a/services/core/java/com/android/server/timezone/IntentHelper.java b/services/core/java/com/android/server/timezone/IntentHelper.java
index 0cb9065..5de5432 100644
--- a/services/core/java/com/android/server/timezone/IntentHelper.java
+++ b/services/core/java/com/android/server/timezone/IntentHelper.java
@@ -23,15 +23,22 @@
  */
 interface IntentHelper {
 
-    void initialize(String updateAppPackageName, String dataAppPackageName, Listener listener);
+    void initialize(String updateAppPackageName, String dataAppPackageName,
+            PackageTracker packageTracker);
 
     void sendTriggerUpdateCheck(CheckToken checkToken);
 
-    void enableReliabilityTriggering();
+    /**
+     * Schedule a "reliability trigger" after at least minimumDelayMillis, replacing any existing
+     * scheduled one. A reliability trigger ensures that the {@link PackageTracker} can pick up
+     * reliably if a previous update check did not complete for some reason. It can happen when
+     * the device is idle. The trigger is expected to call
+     * {@link PackageTracker#triggerUpdateIfNeeded(boolean)} with a {@code false} value.
+     */
+    void scheduleReliabilityTrigger(long minimumDelayMillis);
 
-    void disableReliabilityTriggering();
-
-    interface Listener {
-        void triggerUpdateIfNeeded(boolean packageUpdated);
-    }
+    /**
+     * Make sure there is no reliability trigger scheduled. No-op if there wasn't one.
+     */
+    void unscheduleReliabilityTrigger();
 }
diff --git a/services/core/java/com/android/server/timezone/IntentHelperImpl.java b/services/core/java/com/android/server/timezone/IntentHelperImpl.java
index 6db70cd8..bc0f6e4 100644
--- a/services/core/java/com/android/server/timezone/IntentHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/IntentHelperImpl.java
@@ -36,16 +36,13 @@
     private final Context mContext;
     private String mUpdaterAppPackageName;
 
-    private boolean mReliabilityReceiverEnabled;
-    private Receiver mReliabilityReceiver;
-
     IntentHelperImpl(Context context) {
         mContext = context;
     }
 
     @Override
-    public void initialize(
-            String updaterAppPackageName, String dataAppPackageName, Listener listener) {
+    public void initialize(String updaterAppPackageName, String dataAppPackageName,
+            PackageTracker packageTracker) {
         mUpdaterAppPackageName = updaterAppPackageName;
 
         // Register for events of interest.
@@ -78,10 +75,8 @@
         // We do not register for ACTION_PACKAGE_DATA_CLEARED because the updater / data apps are
         // not expected to need local data.
 
-        Receiver packageUpdateReceiver = new Receiver(listener, true /* packageUpdated */);
+        Receiver packageUpdateReceiver = new Receiver(packageTracker);
         mContext.registerReceiver(packageUpdateReceiver, packageIntentFilter);
-
-        mReliabilityReceiver = new Receiver(listener, false /* packageUpdated */);
     }
 
     /** Sends an intent to trigger an update check. */
@@ -93,39 +88,26 @@
     }
 
     @Override
-    public synchronized void enableReliabilityTriggering() {
-        if (!mReliabilityReceiverEnabled) {
-            // The intent filter that exists to make updates reliable in the event of failures /
-            // reboots.
-            IntentFilter reliabilityIntentFilter = new IntentFilter();
-            reliabilityIntentFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
-            mContext.registerReceiver(mReliabilityReceiver, reliabilityIntentFilter);
-            mReliabilityReceiverEnabled = true;
-        }
+    public synchronized void scheduleReliabilityTrigger(long minimumDelayMillis) {
+        TimeZoneUpdateIdler.schedule(mContext, minimumDelayMillis);
     }
 
     @Override
-    public synchronized void disableReliabilityTriggering() {
-        if (mReliabilityReceiverEnabled) {
-            mContext.unregisterReceiver(mReliabilityReceiver);
-            mReliabilityReceiverEnabled = false;
-        }
+    public synchronized void unscheduleReliabilityTrigger() {
+        TimeZoneUpdateIdler.unschedule(mContext);
     }
 
     private static class Receiver extends BroadcastReceiver {
-        private final Listener mListener;
-        private final boolean mPackageUpdated;
+        private final PackageTracker mPackageTracker;
 
-        private Receiver(Listener listener, boolean packageUpdated) {
-            mListener = listener;
-            mPackageUpdated = packageUpdated;
+        private Receiver(PackageTracker packageTracker) {
+            mPackageTracker = packageTracker;
         }
 
         @Override
         public void onReceive(Context context, Intent intent) {
             Slog.d(TAG, "Received intent: " + intent.toString());
-            mListener.triggerUpdateIfNeeded(mPackageUpdated);
+            mPackageTracker.triggerUpdateIfNeeded(true /* packageChanged */);
         }
     }
-
 }
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
index 24e0fe4..f0306b9 100644
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -51,7 +51,7 @@
  */
 // Also made non-final so it can be mocked.
 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
-public class PackageTracker implements IntentHelper.Listener {
+public class PackageTracker {
     private static final String TAG = "timezone.PackageTracker";
 
     private final PackageManagerHelper mPackageManagerHelper;
@@ -72,6 +72,13 @@
     // The number of failed checks in a row before reliability checks should stop happening.
     private long mFailedCheckRetryCount;
 
+    /*
+     * The minimum delay between a successive reliability triggers / other operations. Should to be
+     * larger than mCheckTimeAllowedMillis to avoid reliability triggers happening during package
+     * update checks.
+     */
+    private int mDelayBeforeReliabilityCheckMillis;
+
     // Reliability check state: If a check was triggered but not acknowledged within
     // mCheckTimeAllowedMillis then another one can be triggered.
     private Long mLastTriggerTimestamp = null;
@@ -122,6 +129,7 @@
         mDataAppPackageName = mConfigHelper.getDataAppPackageName();
         mCheckTimeAllowedMillis = mConfigHelper.getCheckTimeAllowedMillis();
         mFailedCheckRetryCount = mConfigHelper.getFailedCheckRetryCount();
+        mDelayBeforeReliabilityCheckMillis = mCheckTimeAllowedMillis + (60 * 1000);
 
         // Validate the device configuration including the application packages.
         // The manifest entries in the apps themselves are not validated until use as they can
@@ -135,9 +143,10 @@
         // Initialize the intent helper.
         mIntentHelper.initialize(mUpdateAppPackageName, mDataAppPackageName, this);
 
-        // Enable the reliability triggering so we will have at least one reliability trigger if
-        // a package isn't updated.
-        mIntentHelper.enableReliabilityTriggering();
+        // Schedule a reliability trigger so we will have at least one after boot. This will allow
+        // us to catch if a package updated wasn't handled to completion. There's no hurry: it's ok
+        // to delay for a while before doing this even if idle.
+        mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
 
         Slog.i(TAG, "Time zone updater / data package tracking enabled");
     }
@@ -195,7 +204,6 @@
      * @param packageChanged true if this method was called because a known packaged definitely
      *     changed, false if the cause is a reliability trigger
      */
-    @Override
     public synchronized void triggerUpdateIfNeeded(boolean packageChanged) {
         if (!mTrackingEnabled) {
             throw new IllegalStateException("Unexpected call. Tracking is disabled.");
@@ -212,8 +220,8 @@
                     + " updaterApp=" + updaterAppManifestValid
                     + ", dataApp=" + dataAppManifestValid);
 
-            // There's no point in doing reliability checks if the current packages are bad.
-            mIntentHelper.disableReliabilityTriggering();
+            // There's no point in doing any reliability triggers if the current packages are bad.
+            mIntentHelper.unscheduleReliabilityTrigger();
             return;
         }
 
@@ -238,7 +246,8 @@
                     Slog.d(TAG,
                             "triggerUpdateIfNeeded: checkComplete call is not yet overdue."
                                     + " Not triggering.");
-                    // Not doing any work, but also not disabling future reliability triggers.
+                    // Don't do any work now but we do schedule a future reliability trigger.
+                    mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
                     return;
                 }
             } else if (mCheckFailureCount > mFailedCheckRetryCount) {
@@ -247,13 +256,13 @@
                 Slog.i(TAG, "triggerUpdateIfNeeded: number of allowed consecutive check failures"
                         + " exceeded. Stopping reliability triggers until next reboot or package"
                         + " update.");
-                mIntentHelper.disableReliabilityTriggering();
+                mIntentHelper.unscheduleReliabilityTrigger();
                 return;
             } else if (mCheckFailureCount == 0) {
                 // Case 4.
                 Slog.i(TAG, "triggerUpdateIfNeeded: No reliability check required. Last check was"
                         + " successful.");
-                mIntentHelper.disableReliabilityTriggering();
+                mIntentHelper.unscheduleReliabilityTrigger();
                 return;
             }
         }
@@ -263,7 +272,7 @@
         if (currentInstalledVersions == null) {
             // This should not happen if the device is configured in a valid way.
             Slog.e(TAG, "triggerUpdateIfNeeded: currentInstalledVersions was null");
-            mIntentHelper.disableReliabilityTriggering();
+            mIntentHelper.unscheduleReliabilityTrigger();
             return;
         }
 
@@ -288,7 +297,7 @@
                 // The last check succeeded and nothing has changed. Do nothing and disable
                 // reliability checks.
                 Slog.i(TAG, "triggerUpdateIfNeeded: Prior check succeeded. No need to trigger.");
-                mIntentHelper.disableReliabilityTriggering();
+                mIntentHelper.unscheduleReliabilityTrigger();
                 return;
             }
         }
@@ -299,6 +308,8 @@
         if (checkToken == null) {
             Slog.w(TAG, "triggerUpdateIfNeeded: Unable to generate check token."
                     + " Not sending check request.");
+            // Trigger again later: perhaps we'll have better luck.
+            mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
             return;
         }
 
@@ -309,9 +320,9 @@
         // Update the reliability check state in case the update fails.
         setCheckInProgress();
 
-        // Enable reliability triggering in case the check doesn't succeed and there is no
-        // response at all. Enabling reliability triggering is idempotent.
-        mIntentHelper.enableReliabilityTriggering();
+        // Schedule a reliability trigger in case the update check doesn't succeed and there is no
+        // response at all. It will be cancelled if the check is successful in recordCheckResult.
+        mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
     }
 
     /**
@@ -370,9 +381,9 @@
                     + " storage state.");
             mPackageStatusStorage.resetCheckState();
 
-            // Enable reliability triggering and reset the failure count so we know that the
+            // Schedule a reliability trigger and reset the failure count so we know that the
             // next reliability trigger will do something.
-            mIntentHelper.enableReliabilityTriggering();
+            mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
             mCheckFailureCount = 0;
         } else {
             // This is the expected case when tracking is enabled: a check was triggered and it has
@@ -385,13 +396,13 @@
                 setCheckComplete();
 
                 if (success) {
-                    // Since the check was successful, no more reliability checks are required until
+                    // Since the check was successful, no reliability trigger is required until
                     // there is a package change.
-                    mIntentHelper.disableReliabilityTriggering();
+                    mIntentHelper.unscheduleReliabilityTrigger();
                     mCheckFailureCount = 0;
                 } else {
-                    // Enable reliability triggering to potentially check again in future.
-                    mIntentHelper.enableReliabilityTriggering();
+                    // Enable schedule a reliability trigger to check again in future.
+                    mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
                     mCheckFailureCount++;
                 }
             } else {
@@ -400,8 +411,8 @@
                 Slog.i(TAG, "recordCheckResult: could not update token=" + checkToken
                         + " with success=" + success + ". Optimistic lock failure");
 
-                // Enable reliability triggering to potentially try again in future.
-                mIntentHelper.enableReliabilityTriggering();
+                // Schedule a reliability trigger to potentially try again in future.
+                mIntentHelper.scheduleReliabilityTrigger(mDelayBeforeReliabilityCheckMillis);
                 mCheckFailureCount++;
             }
         }
@@ -515,6 +526,7 @@
                 ", mUpdateAppPackageName='" + mUpdateAppPackageName + '\'' +
                 ", mDataAppPackageName='" + mDataAppPackageName + '\'' +
                 ", mCheckTimeAllowedMillis=" + mCheckTimeAllowedMillis +
+                ", mDelayBeforeReliabilityCheckMillis=" + mDelayBeforeReliabilityCheckMillis +
                 ", mFailedCheckRetryCount=" + mFailedCheckRetryCount +
                 ", mLastTriggerTimestamp=" + mLastTriggerTimestamp +
                 ", mCheckTriggered=" + mCheckTriggered +
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index 3ad4419..6824a59 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -69,18 +69,22 @@
                     DistroVersion.CURRENT_FORMAT_MINOR_VERSION);
 
     public static class Lifecycle extends SystemService {
-        private RulesManagerService mService;
-
         public Lifecycle(Context context) {
             super(context);
         }
 
         @Override
         public void onStart() {
-            mService = RulesManagerService.create(getContext());
-            mService.start();
+            RulesManagerService service = RulesManagerService.create(getContext());
+            service.start();
 
-            publishBinderService(Context.TIME_ZONE_RULES_MANAGER_SERVICE, mService);
+            // Publish the binder service so it can be accessed from other (appropriately
+            // permissioned) processes.
+            publishBinderService(Context.TIME_ZONE_RULES_MANAGER_SERVICE, service);
+
+            // Publish the service instance locally so we can use it directly from within the system
+            // server from TimeZoneUpdateIdler.
+            publishLocalService(RulesManagerService.class, service);
         }
     }
 
@@ -496,6 +500,16 @@
         mPackageTracker.dump(pw);
     }
 
+    /**
+     * Called when the device is considered idle.
+     */
+    void notifyIdle() {
+        // No package has changed: we are just triggering because the device is idle and there
+        // *might* be work to do.
+        final boolean packageChanged = false;
+        mPackageTracker.triggerUpdateIfNeeded(packageChanged);
+    }
+
     @Override
     public String toString() {
         return "RulesManagerService{" +
diff --git a/services/core/java/com/android/server/timezone/TimeZoneUpdateIdler.java b/services/core/java/com/android/server/timezone/TimeZoneUpdateIdler.java
new file mode 100644
index 0000000..a7767a4
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/TimeZoneUpdateIdler.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezone;
+
+import com.android.server.LocalServices;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.Slog;
+
+/**
+ * A JobService used to trigger time zone rules update work when a device falls idle.
+ */
+public final class TimeZoneUpdateIdler extends JobService {
+
+    private static final String TAG = "timezone.TimeZoneUpdateIdler";
+
+    /** The static job ID used to handle on-idle work. */
+    // Must be unique within UID (system service)
+    private static final int TIME_ZONE_UPDATE_IDLE_JOB_ID = 27042305;
+
+    @Override
+    public boolean onStartJob(JobParameters params) {
+        RulesManagerService rulesManagerService =
+                LocalServices.getService(RulesManagerService.class);
+
+        Slog.d(TAG, "onStartJob() called");
+
+        // Note: notifyIdle() explicitly handles canceling / re-scheduling so no need to reschedule
+        // here.
+        rulesManagerService.notifyIdle();
+
+        // Everything is handled synchronously. We are done.
+        return false;
+    }
+
+    @Override
+    public boolean onStopJob(JobParameters params) {
+        // Reschedule if stopped unless it was cancelled due to unschedule().
+        boolean reschedule = params.getStopReason() != JobParameters.REASON_CANCELED;
+        Slog.d(TAG, "onStopJob() called: Reschedule=" + reschedule);
+        return reschedule;
+    }
+
+    /**
+     * Schedules the TimeZoneUpdateIdler job service to run once.
+     *
+     * @param context Context to use to get a job scheduler.
+     */
+    public static void schedule(Context context, long minimumDelayMillis) {
+        // Request that the JobScheduler tell us when the device falls idle.
+        JobScheduler jobScheduler =
+                (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+        // The TimeZoneUpdateIdler will send an intent that will trigger the Receiver.
+        ComponentName idlerJobServiceName =
+                new ComponentName(context, TimeZoneUpdateIdler.class);
+
+        // We require the device is idle, but also that it is charging to be as non-invasive as
+        // we can.
+        JobInfo.Builder jobInfoBuilder =
+                new JobInfo.Builder(TIME_ZONE_UPDATE_IDLE_JOB_ID, idlerJobServiceName)
+                        .setRequiresDeviceIdle(true)
+                        .setRequiresCharging(true)
+                        .setMinimumLatency(minimumDelayMillis);
+
+        Slog.d(TAG, "schedule() called: minimumDelayMillis=" + minimumDelayMillis);
+        jobScheduler.schedule(jobInfoBuilder.build());
+    }
+
+    /**
+     * Unschedules the TimeZoneUpdateIdler job service.
+     *
+     * @param context Context to use to get a job scheduler.
+     */
+    public static void unschedule(Context context) {
+        JobScheduler jobScheduler =
+                (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+        Slog.d(TAG, "unschedule() called");
+        jobScheduler.cancel(TIME_ZONE_UPDATE_IDLE_JOB_ID);
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f92f83a..3b3c234 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1182,18 +1182,6 @@
                 traceEnd();
             }
 
-            // timezone.RulesManagerService will prevent a device starting up if the chain of trust
-            // required for safe time zone updates might be broken. RuleManagerService cannot do
-            // this check when mOnlyCore == true, so we don't enable the service in this case.
-            final boolean startRulesManagerService =
-                    !mOnlyCore && context.getResources().getBoolean(
-                            R.bool.config_enableUpdateableTimeZoneRules);
-            if (startRulesManagerService) {
-                traceBeginAndSlog("StartTimeZoneRulesManagerService");
-                mSystemServiceManager.startService(TIME_ZONE_RULES_MANAGER_SERVICE_CLASS);
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-            }
-
             traceBeginAndSlog("StartAudioService");
             mSystemServiceManager.startService(AudioService.Lifecycle.class);
             traceEnd();
@@ -1326,6 +1314,19 @@
             }
             traceEnd();
 
+            // timezone.RulesManagerService will prevent a device starting up if the chain of trust
+            // required for safe time zone updates might be broken. RuleManagerService cannot do
+            // this check when mOnlyCore == true, so we don't enable the service in this case.
+            // This service requires that JobSchedulerService is already started when it starts.
+            final boolean startRulesManagerService =
+                    !mOnlyCore && context.getResources().getBoolean(
+                            R.bool.config_enableUpdateableTimeZoneRules);
+            if (startRulesManagerService) {
+                traceBeginAndSlog("StartTimeZoneRulesManagerService");
+                mSystemServiceManager.startService(TIME_ZONE_RULES_MANAGER_SERVICE_CLASS);
+                traceEnd();
+            }
+
             if (!disableNetwork && !disableNetworkTime) {
                 traceBeginAndSlog("StartNetworkTimeUpdateService");
                 try {
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
index 38142d3..7d73e82 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
@@ -107,7 +107,7 @@
         mFakeIntentHelper.assertNotInitialized();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
     }
 
     @Test
@@ -119,7 +119,7 @@
         mPackageTracker.start();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
 
         try {
             // This call should also not be allowed and will throw an exception if tracking is
@@ -129,7 +129,7 @@
         } catch (IllegalStateException expected) {}
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
     }
 
     @Test
@@ -141,14 +141,14 @@
         mPackageTracker.start();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
 
         // Receiving a check result when tracking is disabled should cause the storage to be
         // reset.
         mPackageTracker.recordCheckResult(null /* checkToken */, true /* success */);
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
 
         // Assert the storage was reset.
         checkPackageStorageStatusIsInitialOrReset();
@@ -166,13 +166,13 @@
         mPackageTracker.start();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
 
         // Receiving a check result when tracking is disabled should cause the storage to be reset.
         mPackageTracker.recordCheckResult(createArbitraryCheckToken(), true /* success */);
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
 
         // Assert the storage was reset.
         checkPackageStorageStatusIsInitialOrReset();
@@ -195,7 +195,7 @@
         mFakeIntentHelper.assertNotInitialized();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
     }
 
     @Test
@@ -215,7 +215,7 @@
         mFakeIntentHelper.assertNotInitialized();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
     }
 
     @Test
@@ -235,7 +235,7 @@
         mFakeIntentHelper.assertNotInitialized();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
     }
 
     @Test
@@ -255,7 +255,7 @@
         mFakeIntentHelper.assertNotInitialized();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
      }
 
     @Test
@@ -289,7 +289,7 @@
         mFakeIntentHelper.assertUpdateNotTriggered();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
 
         // Assert the storage was not touched.
         checkPackageStorageStatusIsInitialOrReset();
@@ -325,7 +325,7 @@
         mFakeIntentHelper.assertUpdateNotTriggered();
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
 
         // Assert the storage was not touched.
         checkPackageStorageStatusIsInitialOrReset();
@@ -416,7 +416,7 @@
         mPackageTracker.recordCheckResult(null /* checkToken */, success);
 
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+        mFakeIntentHelper.assertReliabilityTriggerScheduled();
 
         // Assert the storage was reset.
         checkPackageStorageStatusIsInitialOrReset();
@@ -627,7 +627,7 @@
         mPackageTracker.recordCheckResult(token1, true /* success */);
 
         // Reliability triggering should still be enabled.
-        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+        mFakeIntentHelper.assertReliabilityTriggerScheduled();
 
         // Check the expected storage state.
         checkPackageStorageStatus(PackageStatus.CHECK_STARTED, packageVersions2);
@@ -743,7 +743,7 @@
 
         // Under the covers we expect it to fail to update because the storage should recognize that
         // the token is no longer valid.
-        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+        mFakeIntentHelper.assertReliabilityTriggerScheduled();
 
         // Peek inside the package tracker to make sure it is tracking failure counts properly.
         assertEquals(1, mPackageTracker.getCheckFailureCountForTests());
@@ -766,7 +766,7 @@
         checkPackageStorageStatusIsInitialOrReset();
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Assert the PackageTracker did trigger an update.
         checkUpdateCheckTriggered(packageVersions);
@@ -803,7 +803,7 @@
         checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Assert the PackageTracker did not attempt to trigger an update.
         mFakeIntentHelper.assertUpdateNotTriggered();
@@ -843,7 +843,7 @@
         checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Assert the PackageTracker did trigger an update.
         checkUpdateCheckTriggered(currentPackageVersions);
@@ -890,7 +890,7 @@
 
         for (int i = 0; i < retriesAllowed + 1; i++) {
             // Simulate a reliability trigger.
-            mFakeIntentHelper.simulateReliabilityTrigger();
+            mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
             // Assert the PackageTracker did trigger an update.
             checkUpdateCheckTriggered(currentPackageVersions);
@@ -912,9 +912,9 @@
 
             // Check reliability triggering is in the correct state.
             if (i <= retriesAllowed) {
-                mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+                mFakeIntentHelper.assertReliabilityTriggerScheduled();
             } else {
-                mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+                mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
             }
         }
     }
@@ -950,7 +950,7 @@
         // Fail (retries - 1) times.
         for (int i = 0; i < retriesAllowed - 1; i++) {
             // Simulate a reliability trigger.
-            mFakeIntentHelper.simulateReliabilityTrigger();
+            mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
             // Assert the PackageTracker did trigger an update.
             checkUpdateCheckTriggered(currentPackageVersions);
@@ -971,11 +971,11 @@
                     currentPackageVersions);
 
             // Check reliability triggering is still enabled.
-            mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+            mFakeIntentHelper.assertReliabilityTriggerScheduled();
         }
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Assert the PackageTracker did trigger an update.
         checkUpdateCheckTriggered(currentPackageVersions);
@@ -1023,7 +1023,7 @@
         checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Assert the PackageTracker did trigger an update.
         checkUpdateCheckTriggered(currentPackageVersions);
@@ -1033,18 +1033,18 @@
         mFakeClock.incrementClock(checkDelayMillis - 1);
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Assert the PackageTracker did not trigger an update.
         mFakeIntentHelper.assertUpdateNotTriggered();
         checkPackageStorageStatus(PackageStatus.CHECK_STARTED, currentPackageVersions);
-        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+        mFakeIntentHelper.assertReliabilityTriggerScheduled();
 
         // Increment the clock slightly more. Should now consider the response overdue.
         mFakeClock.incrementClock(2);
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Triggering should have happened.
         checkUpdateCheckTriggered(currentPackageVersions);
@@ -1096,7 +1096,7 @@
         mFakeClock.incrementClock(checkDelayMillis + 1);
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Assert the PackageTracker triggered an update.
         checkUpdateCheckTriggered(newPackageVersions);
@@ -1154,18 +1154,18 @@
         mFakeClock.incrementClock(checkDelayMillis - 1);
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Assert the PackageTracker did not trigger an update.
         mFakeIntentHelper.assertUpdateNotTriggered();
         checkPackageStorageStatus(PackageStatus.CHECK_STARTED, newPackageVersions);
-        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+        mFakeIntentHelper.assertReliabilityTriggerScheduled();
 
         // Increment the clock slightly more. Should now consider the response overdue.
         mFakeClock.incrementClock(2);
 
         // Simulate a reliability trigger.
-        mFakeIntentHelper.simulateReliabilityTrigger();
+        mPackageTracker.triggerUpdateIfNeeded(false /* packageChanged */);
 
         // Triggering should have happened.
         checkUpdateCheckTriggered(newPackageVersions);
@@ -1202,7 +1202,7 @@
 
         // If an update check was triggered reliability triggering should always be enabled to
         // ensure that it can be completed if it fails.
-        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+        mFakeIntentHelper.assertReliabilityTriggerScheduled();
 
         // Check the expected storage state.
         checkPackageStorageStatus(PackageStatus.CHECK_STARTED, packageVersions);
@@ -1210,7 +1210,7 @@
 
     private void checkUpdateCheckFailed(PackageVersions packageVersions) {
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+        mFakeIntentHelper.assertReliabilityTriggerScheduled();
 
         // Assert the storage was updated.
         checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, packageVersions);
@@ -1218,7 +1218,7 @@
 
     private void checkUpdateCheckSuccessful(PackageVersions packageVersions) {
         // Check reliability triggering state.
-        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+        mFakeIntentHelper.assertReliabilityTriggerNotScheduled();
 
         // Assert the storage was updated.
         checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
@@ -1345,7 +1345,7 @@
         mFakeIntentHelper.assertInitialized(UPDATE_APP_PACKAGE_NAME, DATA_APP_PACKAGE_NAME);
 
         // Assert that reliability tracking is always enabled after initialization.
-        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+        mFakeIntentHelper.assertReliabilityTriggerScheduled();
     }
 
     private void checkPackageStorageStatus(
@@ -1368,34 +1368,34 @@
      */
     private static class FakeIntentHelper implements IntentHelper {
 
-        private Listener mListener;
+        private PackageTracker mPackageTracker;
         private String mUpdateAppPackageName;
         private String mDataAppPackageName;
 
         private CheckToken mLastToken;
 
-        private boolean mReliabilityTriggeringEnabled;
+        private boolean mReliabilityTriggerScheduled;
 
         @Override
         public void initialize(String updateAppPackageName, String dataAppPackageName,
-                Listener listener) {
+                PackageTracker packageTracker) {
             assertNotNull(updateAppPackageName);
             assertNotNull(dataAppPackageName);
-            assertNotNull(listener);
-            mListener = listener;
+            assertNotNull(packageTracker);
+            mPackageTracker = packageTracker;
             mUpdateAppPackageName = updateAppPackageName;
             mDataAppPackageName = dataAppPackageName;
         }
 
         public void assertInitialized(
                 String expectedUpdateAppPackageName, String expectedDataAppPackageName) {
-            assertNotNull(mListener);
+            assertNotNull(mPackageTracker);
             assertEquals(expectedUpdateAppPackageName, mUpdateAppPackageName);
             assertEquals(expectedDataAppPackageName, mDataAppPackageName);
         }
 
         public void assertNotInitialized() {
-            assertNull(mListener);
+            assertNull(mPackageTracker);
         }
 
         @Override
@@ -1407,21 +1407,21 @@
         }
 
         @Override
-        public void enableReliabilityTriggering() {
-            mReliabilityTriggeringEnabled = true;
+        public void scheduleReliabilityTrigger(long minimumDelayMillis) {
+            mReliabilityTriggerScheduled = true;
         }
 
         @Override
-        public void disableReliabilityTriggering() {
-            mReliabilityTriggeringEnabled = false;
+        public void unscheduleReliabilityTrigger() {
+            mReliabilityTriggerScheduled = false;
         }
 
-        public void assertReliabilityTriggeringEnabled() {
-            assertTrue(mReliabilityTriggeringEnabled);
+        public void assertReliabilityTriggerScheduled() {
+            assertTrue(mReliabilityTriggerScheduled);
         }
 
-        public void assertReliabilityTriggeringDisabled() {
-            assertFalse(mReliabilityTriggeringEnabled);
+        public void assertReliabilityTriggerNotScheduled() {
+            assertFalse(mReliabilityTriggerScheduled);
         }
 
         public void assertUpdateTriggered() {
@@ -1440,11 +1440,7 @@
         }
 
         public void simulatePackageUpdatedEvent() {
-            mListener.triggerUpdateIfNeeded(true);
-        }
-
-        public void simulateReliabilityTrigger() {
-            mListener.triggerUpdateIfNeeded(false);
+            mPackageTracker.triggerUpdateIfNeeded(true /* packageChanged */);
         }
     }