Merge "Fix reliability triggering"
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 6db70cd..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 */);
         }
     }