Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.util;
     18 
     19 import android.content.ContentResolver;
     20 import android.content.Context;
     21 import android.content.res.Resources;
     22 import android.net.ConnectivityManager;
     23 import android.net.NetworkInfo;
     24 import android.net.SntpClient;
     25 import android.os.SystemClock;
     26 import android.provider.Settings;
     27 
     28 /**
     29  * {@link TrustedTime} that connects with a remote NTP server as its trusted
     30  * time source.
     31  *
     32  * @hide
     33  */
     34 public class NtpTrustedTime implements TrustedTime {
     35     private static final String TAG = "NtpTrustedTime";
     36     private static final boolean LOGD = false;
     37 
     38     private static NtpTrustedTime sSingleton;
     39     private static Context sContext;
     40 
     41     private final String mServer;
     42     private final long mTimeout;
     43 
     44     private ConnectivityManager mCM;
     45 
     46     private boolean mHasCache;
     47     private long mCachedNtpTime;
     48     private long mCachedNtpElapsedRealtime;
     49     private long mCachedNtpCertainty;
     50 
     51     private NtpTrustedTime(String server, long timeout) {
     52         if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server);
     53         mServer = server;
     54         mTimeout = timeout;
     55     }
     56 
     57     public static synchronized NtpTrustedTime getInstance(Context context) {
     58         if (sSingleton == null) {
     59             final Resources res = context.getResources();
     60             final ContentResolver resolver = context.getContentResolver();
     61 
     62             final String defaultServer = res.getString(
     63                     com.android.internal.R.string.config_ntpServer);
     64             final long defaultTimeout = res.getInteger(
     65                     com.android.internal.R.integer.config_ntpTimeout);
     66 
     67             final String secureServer = Settings.Global.getString(
     68                     resolver, Settings.Global.NTP_SERVER);
     69             final long timeout = Settings.Global.getLong(
     70                     resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout);
     71 
     72             final String server = secureServer != null ? secureServer : defaultServer;
     73             sSingleton = new NtpTrustedTime(server, timeout);
     74             sContext = context;
     75         }
     76 
     77         return sSingleton;
     78     }
     79 
     80     @Override
     81     public boolean forceRefresh() {
     82         if (mServer == null) {
     83             // missing server, so no trusted time available
     84             return false;
     85         }
     86 
     87         // We can't do this at initialization time: ConnectivityService might not be running yet.
     88         synchronized (this) {
     89             if (mCM == null) {
     90                 mCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
     91             }
     92         }
     93 
     94         final NetworkInfo ni = mCM == null ? null : mCM.getActiveNetworkInfo();
     95         if (ni == null || !ni.isConnected()) {
     96             if (LOGD) Log.d(TAG, "forceRefresh: no connectivity");
     97             return false;
     98         }
     99 
    100 
    101         if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
    102         final SntpClient client = new SntpClient();
    103         if (client.requestTime(mServer, (int) mTimeout)) {
    104             mHasCache = true;
    105             mCachedNtpTime = client.getNtpTime();
    106             mCachedNtpElapsedRealtime = client.getNtpTimeReference();
    107             mCachedNtpCertainty = client.getRoundTripTime() / 2;
    108             return true;
    109         } else {
    110             return false;
    111         }
    112     }
    113 
    114     @Override
    115     public boolean hasCache() {
    116         return mHasCache;
    117     }
    118 
    119     @Override
    120     public long getCacheAge() {
    121         if (mHasCache) {
    122             return SystemClock.elapsedRealtime() - mCachedNtpElapsedRealtime;
    123         } else {
    124             return Long.MAX_VALUE;
    125         }
    126     }
    127 
    128     @Override
    129     public long getCacheCertainty() {
    130         if (mHasCache) {
    131             return mCachedNtpCertainty;
    132         } else {
    133             return Long.MAX_VALUE;
    134         }
    135     }
    136 
    137     @Override
    138     public long currentTimeMillis() {
    139         if (!mHasCache) {
    140             throw new IllegalStateException("Missing authoritative time source");
    141         }
    142         if (LOGD) Log.d(TAG, "currentTimeMillis() cache hit");
    143 
    144         // current time is age after the last ntp cache; callers who
    145         // want fresh values will hit makeAuthoritative() first.
    146         return mCachedNtpTime + getCacheAge();
    147     }
    148 
    149     public long getCachedNtpTime() {
    150         if (LOGD) Log.d(TAG, "getCachedNtpTime() cache hit");
    151         return mCachedNtpTime;
    152     }
    153 
    154     public long getCachedNtpTimeReference() {
    155         return mCachedNtpElapsedRealtime;
    156     }
    157 }
    158