Better handling of NTP-based clocks.

Now that we have a nice Clock abstraction, we can use it to represent
a clock backed by an NTP fix.  (This makes testing logic much easier
to write.)

We now rely completely on NetworkTimeUpdateService to keep our NTP
fix up to date, instead of trying to refresh in the middle of
critical paths which could trigger random ANRs.

Add internal FallbackClock to make it easier to handle missing NTP
fixes.  Add internal SimpleClock to let implementers focus on single
millis() method.

Test: bit FrameworksNetTests:com.android.server.net.NetworkStatsServiceTest
Test: bit FrameworksServicesTests:com.android.server.NetworkPolicyManagerServiceTest
Bug: 69714690, 72320957
Change-Id: Ic32cdcbe093d08b73b0e4b23d6910b23ea8e1968
Exempt-From-Owner-Approval: approved in previous PS
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index a422b7c..9cd3621 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -16,6 +16,13 @@
 
 package com.android.server;
 
+import static android.app.AlarmManager.ELAPSED_REALTIME;
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
+import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
+import static android.app.AlarmManager.RTC;
+import static android.app.AlarmManager.RTC_WAKEUP;
+
 import android.annotation.UserIdInt;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -46,6 +53,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.ParcelableException;
 import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
@@ -62,6 +70,7 @@
 import android.util.ArraySet;
 import android.util.KeyValueListParser;
 import android.util.Log;
+import android.util.NtpTrustedTime;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -70,10 +79,18 @@
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
 
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.LocalLog;
+import com.android.server.AppStateTracker.Listener;
+
 import java.io.ByteArrayOutputStream;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
+import java.time.DateTimeException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -88,21 +105,6 @@
 import java.util.TreeSet;
 import java.util.function.Predicate;
 
-import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
-import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
-import static android.app.AlarmManager.RTC_WAKEUP;
-import static android.app.AlarmManager.RTC;
-import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
-import static android.app.AlarmManager.ELAPSED_REALTIME;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.LocalLog;
-import com.android.internal.util.Preconditions;
-import com.android.server.AppStateTracker.Listener;
-
 /**
  * Alarm manager implementaion.
  *
@@ -1794,6 +1796,16 @@
         }
 
         @Override
+        public long currentNetworkTimeMillis() {
+            final NtpTrustedTime time = NtpTrustedTime.getInstance(getContext());
+            if (time.hasCache()) {
+                return time.currentTimeMillis();
+            } else {
+                throw new ParcelableException(new DateTimeException("Missing NTP fix"));
+            }
+        }
+
+        @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
 
diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java
index 2c24798..b3a8fb6 100644
--- a/services/core/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
@@ -33,13 +32,12 @@
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
-import android.os.SystemClock;
 import android.os.PowerManager;
+import android.os.SystemClock;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.NtpTrustedTime;
 import android.util.TimeUtils;
-import android.util.TrustedTime;
 
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.DumpUtils;
@@ -75,19 +73,17 @@
     private long mNitzTimeSetTime = NOT_SET;
     private Network mDefaultNetwork = null;
 
-    private Context mContext;
-    private TrustedTime mTime;
+    private final Context mContext;
+    private final NtpTrustedTime mTime;
+    private final AlarmManager mAlarmManager;
+    private final ConnectivityManager mCM;
+    private final PendingIntent mPendingPollIntent;
+    private final PowerManager.WakeLock mWakeLock;
 
     // NTP lookup is done on this thread and handler
     private Handler mHandler;
-    private AlarmManager mAlarmManager;
-    private PendingIntent mPendingPollIntent;
     private SettingsObserver mSettingsObserver;
-    private ConnectivityManager mCM;
     private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
-    // The last time that we successfully fetched the NTP time.
-    private long mLastNtpFetchTime = NOT_SET;
-    private final PowerManager.WakeLock mWakeLock;
 
     // Normal polling frequency
     private final long mPollingIntervalMs;
@@ -105,8 +101,9 @@
     public NetworkTimeUpdateService(Context context) {
         mContext = context;
         mTime = NtpTrustedTime.getInstance(context);
-        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mAlarmManager = mContext.getSystemService(AlarmManager.class);
+        mCM = mContext.getSystemService(ConnectivityManager.class);
+
         Intent pollIntent = new Intent(ACTION_POLL, null);
         mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
 
@@ -119,7 +116,7 @@
         mTimeErrorThresholdMs = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_ntpThreshold);
 
-        mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
+        mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
                 PowerManager.PARTIAL_WAKE_LOCK, TAG);
     }
 
@@ -157,7 +154,7 @@
     private void onPollNetworkTime(int event) {
         // If Automatic time is not set, don't bother. Similarly, if we don't
         // have any default network, don't bother.
-        if (!isAutomaticTimeRequested() || mDefaultNetwork == null) return;
+        if (mDefaultNetwork == null) return;
         mWakeLock.acquire();
         try {
             onPollNetworkTimeUnderWakeLock(event);
@@ -167,61 +164,60 @@
     }
 
     private void onPollNetworkTimeUnderWakeLock(int event) {
-        final long refTime = SystemClock.elapsedRealtime();
-        // If NITZ time was received less than mPollingIntervalMs time ago,
-        // no need to sync to NTP.
-        if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
-            resetAlarm(mPollingIntervalMs);
-            return;
+        // Force an NTP fix when outdated
+        if (mTime.getCacheAge() >= mPollingIntervalMs) {
+            if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
+            mTime.forceRefresh();
         }
-        final long currentTime = System.currentTimeMillis();
-        if (DBG) Log.d(TAG, "System time = " + currentTime);
-        // Get the NTP time
-        if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
-                || event == EVENT_AUTO_TIME_CHANGED) {
-            if (DBG) Log.d(TAG, "Before Ntp fetch");
 
-            // force refresh NTP cache when outdated
-            if (mTime.getCacheAge() >= mPollingIntervalMs) {
-                mTime.forceRefresh();
+        if (mTime.getCacheAge() < mPollingIntervalMs) {
+            // Obtained fresh fix; schedule next normal update
+            resetAlarm(mPollingIntervalMs);
+            if (isAutomaticTimeRequested()) {
+                updateSystemClock(event);
             }
 
-            // only update when NTP time is fresh
-            if (mTime.getCacheAge() < mPollingIntervalMs) {
-                final long ntp = mTime.currentTimeMillis();
-                mTryAgainCounter = 0;
-                // If the clock is more than N seconds off or this is the first time it's been
-                // fetched since boot, set the current time.
-                if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
-                        || mLastNtpFetchTime == NOT_SET) {
-                    // Set the system time
-                    if (DBG && mLastNtpFetchTime == NOT_SET
-                            && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
-                        Log.d(TAG, "For initial setup, rtc = " + currentTime);
-                    }
-                    if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
-                    // Make sure we don't overflow, since it's going to be converted to an int
-                    if (ntp / 1000 < Integer.MAX_VALUE) {
-                        SystemClock.setCurrentTimeMillis(ntp);
-                    }
-                } else {
-                    if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
-                }
-                mLastNtpFetchTime = SystemClock.elapsedRealtime();
+        } else {
+            // No fresh fix; schedule retry
+            mTryAgainCounter++;
+            if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
+                resetAlarm(mPollingIntervalShorterMs);
             } else {
-                // Try again shortly
-                mTryAgainCounter++;
-                if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
-                    resetAlarm(mPollingIntervalShorterMs);
-                } else {
-                    // Try much later
-                    mTryAgainCounter = 0;
-                    resetAlarm(mPollingIntervalMs);
-                }
+                // Try much later
+                mTryAgainCounter = 0;
+                resetAlarm(mPollingIntervalMs);
+            }
+        }
+    }
+
+    private long getNitzAge() {
+        if (mNitzTimeSetTime == NOT_SET) {
+            return Long.MAX_VALUE;
+        } else {
+            return SystemClock.elapsedRealtime() - mNitzTimeSetTime;
+        }
+    }
+
+    /**
+     * Consider updating system clock based on current NTP fix, if requested by
+     * user, significant enough delta, and we don't have a recent NITZ.
+     */
+    private void updateSystemClock(int event) {
+        final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
+        if (!forceUpdate) {
+            if (getNitzAge() < mPollingIntervalMs) {
+                if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
+                return;
+            }
+
+            final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
+            if (skew < mTimeErrorThresholdMs) {
+                if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
                 return;
             }
         }
-        resetAlarm(mPollingIntervalMs);
+
+        SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
     }
 
     /**
@@ -326,8 +322,8 @@
         pw.print("TimeErrorThresholdMs: ");
         TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
         pw.println("\nTryAgainCounter: " + mTryAgainCounter);
-        pw.print("LastNtpFetchTime: ");
-        TimeUtils.formatDuration(mLastNtpFetchTime, pw);
+        pw.println("NTP cache age: " + mTime.getCacheAge());
+        pw.println("NTP cache certainty: " + mTime.getCacheCertainty());
         pw.println();
     }
 }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index e2b2d46..bd9ec55 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -147,6 +147,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Environment;
+import android.os.BestClock;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IDeviceIdleController;
@@ -164,6 +165,7 @@
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
 import android.os.ShellCallback;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -183,7 +185,6 @@
 import android.util.AtomicFile;
 import android.util.DataUnit;
 import android.util.Log;
-import android.util.NtpTrustedTime;
 import android.util.Pair;
 import android.util.RecurrenceRule;
 import android.util.Slog;
@@ -191,7 +192,6 @@
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
-import android.util.TrustedTime;
 import android.util.Xml;
 
 import com.android.internal.R;
@@ -226,7 +226,9 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
+import java.time.Clock;
 import java.time.ZoneId;
+import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -335,8 +337,6 @@
     private static final String ACTION_SNOOZE_RAPID =
             "com.android.server.net.action.SNOOZE_RAPID";
 
-    private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
-
     /**
      * Indicates the maximum wait time for admin data to be available;
      */
@@ -362,7 +362,7 @@
     private final INetworkStatsService mNetworkStats;
     private final INetworkManagementService mNetworkManager;
     private UsageStatsManagerInternal mUsageStats;
-    private final TrustedTime mTime;
+    private final Clock mClock;
     private final UserManager mUserManager;
     private final CarrierConfigManager mCarrierConfigManager;
 
@@ -518,24 +518,29 @@
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             INetworkStatsService networkStats, INetworkManagementService networkManagement) {
         this(context, activityManager, networkStats, networkManagement,
-                AppGlobals.getPackageManager(), NtpTrustedTime.getInstance(context), getSystemDir(),
+                AppGlobals.getPackageManager(), getDefaultClock(), getDefaultSystemDir(),
                 false);
     }
 
-    private static File getSystemDir() {
+    private static @NonNull File getDefaultSystemDir() {
         return new File(Environment.getDataDirectory(), "system");
     }
 
+    private static @NonNull Clock getDefaultClock() {
+        return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(),
+                Clock.systemUTC());
+    }
+
     public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
             INetworkStatsService networkStats, INetworkManagementService networkManagement,
-            IPackageManager pm, TrustedTime time, File systemDir, boolean suppressDefaultPolicy) {
+            IPackageManager pm, Clock clock, File systemDir, boolean suppressDefaultPolicy) {
         mContext = checkNotNull(context, "missing context");
         mActivityManager = checkNotNull(activityManager, "missing activityManager");
         mNetworkStats = checkNotNull(networkStats, "missing networkStats");
         mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
         mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
                 Context.DEVICE_IDLE_CONTROLLER));
-        mTime = checkNotNull(time, "missing TrustedTime");
+        mClock = checkNotNull(clock, "missing Clock");
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
         mIPm = pm;
@@ -932,7 +937,6 @@
             // on background handler thread, and verified
             // READ_NETWORK_USAGE_HISTORY permission above.
 
-            maybeRefreshTrustedTime();
             synchronized (mNetworkPoliciesSecondLock) {
                 updateNetworkEnabledNL();
                 updateNotificationsNL();
@@ -1042,7 +1046,7 @@
         // cycle boundary to recompute notifications.
 
         // examine stats for each active policy
-        final long now = currentTimeMillis();
+        final long now = mClock.millis();
         for (int i = mNetworkPolicy.size()-1; i >= 0; i--) {
             final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
             // ignore policies that aren't relevant to user
@@ -1299,7 +1303,6 @@
             // on background handler thread, and verified CONNECTIVITY_INTERNAL
             // permission above.
 
-            maybeRefreshTrustedTime();
             synchronized (mUidRulesFirstLock) {
                 synchronized (mNetworkPoliciesSecondLock) {
                     ensureActiveMobilePolicyAL();
@@ -1462,7 +1465,6 @@
             final TelephonyManager tele = mContext.getSystemService(TelephonyManager.class);
             final String subscriberId = tele.getSubscriberId(subId);
 
-            maybeRefreshTrustedTime();
             synchronized (mUidRulesFirstLock) {
                 synchronized (mNetworkPoliciesSecondLock) {
                     final boolean added = ensureActiveMobilePolicyAL(subId, subscriberId);
@@ -1723,7 +1725,7 @@
                 final long totalBytes = getTotalBytes(
                         NetworkTemplate.buildTemplateMobileAll(state.subscriberId), start, end);
                 final long remainingBytes = limitBytes - totalBytes;
-                final long remainingDays = Math.max(1, (end - currentTimeMillis())
+                final long remainingDays = Math.max(1, (end - mClock.millis())
                         / TimeUnit.DAYS.toMillis(1));
                 if (remainingBytes > 0) {
                     quotaBytes = (remainingBytes / remainingDays) / 10;
@@ -2444,7 +2446,6 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            maybeRefreshTrustedTime();
             synchronized (mUidRulesFirstLock) {
                 synchronized (mNetworkPoliciesSecondLock) {
                     normalizePoliciesNL(policies);
@@ -2524,8 +2525,7 @@
     }
 
     void performSnooze(NetworkTemplate template, int type) {
-        maybeRefreshTrustedTime();
-        final long currentTime = currentTimeMillis();
+        final long currentTime = mClock.millis();
         synchronized (mUidRulesFirstLock) {
             synchronized (mNetworkPoliciesSecondLock) {
                 // find and snooze local policy that matches
@@ -2571,7 +2571,6 @@
             mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
             final long token = Binder.clearCallingIdentity();
             try {
-                maybeRefreshTrustedTime();
                 synchronized (mUidRulesFirstLock) {
                     setRestrictBackgroundUL(restrictBackground);
                 }
@@ -2916,7 +2915,6 @@
 
         final long token = Binder.clearCallingIdentity();
         try {
-            maybeRefreshTrustedTime();
             synchronized (mUidRulesFirstLock) {
                 synchronized (mNetworkPoliciesSecondLock) {
                     mSubscriptionPlans.put(subId, plans);
@@ -4028,7 +4026,6 @@
                 case MSG_LIMIT_REACHED: {
                     final String iface = (String) msg.obj;
 
-                    maybeRefreshTrustedTime();
                     synchronized (mNetworkPoliciesSecondLock) {
                         if (mMeteredIfaces.contains(iface)) {
                             try {
@@ -4393,19 +4390,6 @@
         }
     }
 
-    /**
-     * Try refreshing {@link #mTime} when stale.
-     */
-    void maybeRefreshTrustedTime() {
-        if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) {
-            mTime.forceRefresh();
-        }
-    }
-
-    private long currentTimeMillis() {
-        return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis();
-    }
-
     private static Intent buildAllowBackgroundDataIntent() {
         return new Intent(ACTION_ALLOW_BACKGROUND);
     }
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 76c4db1..d1aa212 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -68,6 +68,7 @@
 import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
 import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
 
+import android.annotation.NonNull;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
 import android.app.usage.NetworkStatsManager;
@@ -97,6 +98,7 @@
 import android.os.Binder;
 import android.os.DropBoxManager;
 import android.os.Environment;
+import android.os.BestClock;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -120,10 +122,8 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.MathUtils;
-import android.util.NtpTrustedTime;
 import android.util.Slog;
 import android.util.SparseIntArray;
-import android.util.TrustedTime;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
@@ -140,6 +140,8 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.time.Clock;
+import java.time.ZoneOffset;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -167,7 +169,7 @@
     private final Context mContext;
     private final INetworkManagementService mNetworkManager;
     private final AlarmManager mAlarmManager;
-    private final TrustedTime mTime;
+    private final Clock mClock;
     private final TelephonyManager mTeleManager;
     private final NetworkStatsSettings mSettings;
     private final NetworkStatsObservers mStatsObservers;
@@ -202,7 +204,6 @@
      */
     public interface NetworkStatsSettings {
         public long getPollInterval();
-        public long getTimeCacheMaxAge();
         public boolean getSampleEnabled();
         public boolean getAugmentEnabled();
 
@@ -281,16 +282,21 @@
     private long mPersistThreshold = 2 * MB_IN_BYTES;
     private long mGlobalAlertBytes;
 
-    private static File getDefaultSystemDir() {
+    private static @NonNull File getDefaultSystemDir() {
         return new File(Environment.getDataDirectory(), "system");
     }
 
-    private static File getDefaultBaseDir() {
+    private static @NonNull File getDefaultBaseDir() {
         File baseDir = new File(getDefaultSystemDir(), "netstats");
         baseDir.mkdirs();
         return baseDir;
     }
 
+    private static @NonNull Clock getDefaultClock() {
+        return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(),
+                Clock.systemUTC());
+    }
+
     public static NetworkStatsService create(Context context,
                 INetworkManagementService networkManager) {
         AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -299,7 +305,7 @@
                 powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
 
         NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager,
-                wakeLock, NtpTrustedTime.getInstance(context), TelephonyManager.getDefault(),
+                wakeLock, getDefaultClock(), TelephonyManager.getDefault(),
                 new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(),
                 getDefaultSystemDir(), getDefaultBaseDir());
 
@@ -313,13 +319,13 @@
 
     @VisibleForTesting
     NetworkStatsService(Context context, INetworkManagementService networkManager,
-            AlarmManager alarmManager, PowerManager.WakeLock wakeLock, TrustedTime time,
+            AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock,
             TelephonyManager teleManager, NetworkStatsSettings settings,
             NetworkStatsObservers statsObservers, File systemDir, File baseDir) {
         mContext = checkNotNull(context, "missing Context");
         mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
         mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager");
-        mTime = checkNotNull(time, "missing TrustedTime");
+        mClock = checkNotNull(clock, "missing Clock");
         mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
         mTeleManager = checkNotNull(teleManager, "missing TelephonyManager");
         mWakeLock = checkNotNull(wakeLock, "missing WakeLock");
@@ -413,8 +419,7 @@
         mContext.unregisterReceiver(mUserReceiver);
         mContext.unregisterReceiver(mShutdownReceiver);
 
-        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
-                : System.currentTimeMillis();
+        final long currentTime = mClock.millis();
 
         // persist any pending stats
         mDevRecorder.forcePersistLocked(currentTime);
@@ -831,8 +836,7 @@
         }
 
         // update and persist if beyond new thresholds
-        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
-                : System.currentTimeMillis();
+        final long currentTime = mClock.millis();
         synchronized (mStatsLock) {
             if (!mSystemReady) return;
 
@@ -1170,8 +1174,7 @@
      */
     @GuardedBy("mStatsLock")
     private void bootstrapStatsLocked() {
-        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
-                : System.currentTimeMillis();
+        final long currentTime = mClock.millis();
 
         try {
             recordSnapshotLocked(currentTime);
@@ -1183,11 +1186,6 @@
     }
 
     private void performPoll(int flags) {
-        // try refreshing time source when stale
-        if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) {
-            mTime.forceRefresh();
-        }
-
         synchronized (mStatsLock) {
             mWakeLock.acquire();
 
@@ -1215,8 +1213,7 @@
         final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
 
         // TODO: consider marking "untrusted" times in historical stats
-        final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
-                : System.currentTimeMillis();
+        final long currentTime = mClock.millis();
 
         try {
             recordSnapshotLocked(currentTime);
@@ -1268,7 +1265,7 @@
     @GuardedBy("mStatsLock")
     private void performSampleLocked() {
         // TODO: migrate trustedtime fixes to separate binary log events
-        final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1;
+        final long currentTime = mClock.millis();
 
         NetworkTemplate template;
         NetworkStats.Entry devTotal;
@@ -1285,7 +1282,7 @@
                 devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
                 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
                 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
-                trustedTime);
+                currentTime);
 
         // collect wifi sample
         template = buildTemplateWifiWildcard();
@@ -1297,7 +1294,7 @@
                 devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
                 xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
                 uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
-                trustedTime);
+                currentTime);
     }
 
     /**
@@ -1621,10 +1618,6 @@
             return getGlobalLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS);
         }
         @Override
-        public long getTimeCacheMaxAge() {
-            return getGlobalLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS);
-        }
-        @Override
         public long getGlobalAlertBytes(long def) {
             return getGlobalLong(NETSTATS_GLOBAL_ALERT_BYTES, def);
         }
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 184e8de..e1b4422 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -104,6 +104,7 @@
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.RemoteException;
+import android.os.SimpleClock;
 import android.os.UserHandle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
@@ -118,7 +119,6 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.RecurrenceRule;
-import android.util.TrustedTime;
 
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -158,6 +158,7 @@
 import java.time.Instant;
 import java.time.Period;
 import java.time.ZoneId;
+import java.time.ZoneOffset;
 import java.time.ZonedDateTime;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -215,7 +216,6 @@
     private @Mock IActivityManager mActivityManager;
     private @Mock INetworkStatsService mStatsService;
     private @Mock INetworkManagementService mNetworkManager;
-    private @Mock TrustedTime mTime;
     private @Mock IConnectivityManager mConnManager;
     private @Mock NotificationManager mNotifManager;
     private @Mock PackageManager mPackageManager;
@@ -267,6 +267,13 @@
 
     public final @Rule NetPolicyMethodRule mNetPolicyXmlRule = new NetPolicyMethodRule();
 
+    private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
+        @Override
+        public long millis() {
+            return currentTimeMillis();
+        }
+    };
+
     private void registerLocalServices() {
         addLocalServiceMock(DeviceIdleController.LocalService.class);
 
@@ -341,7 +348,7 @@
 
         mFutureIntent = newRestrictBackgroundChangedFuture();
         mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mStatsService,
-                mNetworkManager, mIpm, mTime, mPolicyDir, true);
+                mNetworkManager, mIpm, mClock, mPolicyDir, true);
         mService.bindConnectivityManager(mConnManager);
         mPolicyListener = new NetworkPolicyListenerAnswer(mService);
 
@@ -370,7 +377,6 @@
         when(mPackageManager.getPackagesForUid(UID_A)).thenReturn(new String[] {PKG_NAME_A});
         when(mNetworkManager.isBandwidthControlEnabled()).thenReturn(true);
         when(mNetworkManager.setDataSaverModeEnabled(anyBoolean())).thenReturn(true);
-        expectCurrentTime();
 
         // Prepare NPMS.
         mService.systemReady(mService.networkScoreAndNetworkManagementServiceReady());
@@ -940,7 +946,6 @@
         // which means we shouldn't push limit to interface.
         state = new NetworkState[] { buildWifi() };
         when(mConnManager.getAllNetworkState()).thenReturn(state);
-        expectCurrentTime();
 
         mPolicyListener.expect().onMeteredIfacesChanged(any());
         mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION));
@@ -949,7 +954,6 @@
         // now change cycle to be on 15th, and test in early march, to verify we
         // pick cycle day in previous month.
         when(mConnManager.getAllNetworkState()).thenReturn(state);
-        expectCurrentTime();
 
         // pretend that 512 bytes total have happened
         stats = new NetworkStats(getElapsedRealtime(), 1)
@@ -996,7 +1000,6 @@
         final long start = parseTime("2015-11-01T00:00Z");
         final long end = parseTime("2015-11-07T00:00Z");
         setCurrentTimeMillis(end);
-        expectCurrentTime();
 
         // Normal usage means no notification
         {
@@ -1096,7 +1099,6 @@
         final long start = parseTime("2015-11-01T00:00Z");
         final long end = parseTime("2015-11-07T00:00Z");
         setCurrentTimeMillis(end);
-        expectCurrentTime();
 
         // Using 20% data in 20% time is normal
         {
@@ -1139,7 +1141,6 @@
                 .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L);
 
         {
-            expectCurrentTime();
             when(mConnManager.getAllNetworkState()).thenReturn(state);
             when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
                     currentTimeMillis())).thenReturn(stats.getTotalBytes());
@@ -1474,14 +1475,6 @@
         return new NetworkState(info, prop, networkCapabilities, null, null, TEST_SSID);
     }
 
-    private void expectCurrentTime() throws Exception {
-        when(mTime.forceRefresh()).thenReturn(false);
-        when(mTime.hasCache()).thenReturn(true);
-        when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis());
-        when(mTime.getCacheAge()).thenReturn(0L);
-        when(mTime.getCacheCertainty()).thenReturn(0L);
-    }
-
     private void expectHasInternetPermission(int uid, boolean hasIt) throws Exception {
         when(mIpm.checkUidPermission(Manifest.permission.INTERNET, uid)).thenReturn(
                 hasIt ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED);