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.Network;
     24 import android.net.NetworkInfo;
     25 import android.net.SntpClient;
     26 import android.os.SystemClock;
     27 import android.provider.Settings;
     28 import android.text.TextUtils;
     29 
     30 /**
     31  * {@link TrustedTime} that connects with a remote NTP server as its trusted
     32  * time source.
     33  *
     34  * @hide
     35  */
     36 public class NtpTrustedTime implements TrustedTime {
     37     private static final String TAG = "NtpTrustedTime";
     38     private static final boolean LOGD = false;
     39 
     40     private static NtpTrustedTime sSingleton;
     41     private static Context sContext;
     42 
     43     private final String mServer;
     44     private final long mTimeout;
     45 
     46     private ConnectivityManager mCM;
     47 
     48     private boolean mHasCache;
     49     private long mCachedNtpTime;
     50     private long mCachedNtpElapsedRealtime;
     51     private long mCachedNtpCertainty;
     52 
     53     private NtpTrustedTime(String server, long timeout) {
     54         if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server);
     55         mServer = server;
     56         mTimeout = timeout;
     57     }
     58 
     59     public static synchronized NtpTrustedTime getInstance(Context context) {
     60         if (sSingleton == null) {
     61             final Resources res = context.getResources();
     62             final ContentResolver resolver = context.getContentResolver();
     63 
     64             final String defaultServer = res.getString(
     65                     com.android.internal.R.string.config_ntpServer);
     66             final long defaultTimeout = res.getInteger(
     67                     com.android.internal.R.integer.config_ntpTimeout);
     68 
     69             final String secureServer = Settings.Global.getString(
     70                     resolver, Settings.Global.NTP_SERVER);
     71             final long timeout = Settings.Global.getLong(
     72                     resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout);
     73 
     74             final String server = secureServer != null ? secureServer : defaultServer;
     75             sSingleton = new NtpTrustedTime(server, timeout);
     76             sContext = context;
     77         }
     78 
     79         return sSingleton;
     80     }
     81 
     82     @Override
     83     public boolean forceRefresh() {
     84         // We can't do this at initialization time: ConnectivityService might not be running yet.
     85         synchronized (this) {
     86             if (mCM == null) {
     87                 mCM = sContext.getSystemService(ConnectivityManager.class);
     88             }
     89         }
     90 
     91         final Network network = mCM == null ? null : mCM.getActiveNetwork();
     92         return forceRefresh(network);
     93     }
     94 
     95     public boolean forceRefresh(Network network) {
     96         if (TextUtils.isEmpty(mServer)) {
     97             // missing server, so no trusted time available
     98             return false;
     99         }
    100 
    101         // We can't do this at initialization time: ConnectivityService might not be running yet.
    102         synchronized (this) {
    103             if (mCM == null) {
    104                 mCM = sContext.getSystemService(ConnectivityManager.class);
    105             }
    106         }
    107 
    108         final NetworkInfo ni = mCM == null ? null : mCM.getNetworkInfo(network);
    109         if (ni == null || !ni.isConnected()) {
    110             if (LOGD) Log.d(TAG, "forceRefresh: no connectivity");
    111             return false;
    112         }
    113 
    114 
    115         if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
    116         final SntpClient client = new SntpClient();
    117         if (client.requestTime(mServer, (int) mTimeout, network)) {
    118             mHasCache = true;
    119             mCachedNtpTime = client.getNtpTime();
    120             mCachedNtpElapsedRealtime = client.getNtpTimeReference();
    121             mCachedNtpCertainty = client.getRoundTripTime() / 2;
    122             return true;
    123         } else {
    124             return false;
    125         }
    126     }
    127 
    128     @Override
    129     public boolean hasCache() {
    130         return mHasCache;
    131     }
    132 
    133     @Override
    134     public long getCacheAge() {
    135         if (mHasCache) {
    136             return SystemClock.elapsedRealtime() - mCachedNtpElapsedRealtime;
    137         } else {
    138             return Long.MAX_VALUE;
    139         }
    140     }
    141 
    142     @Override
    143     public long getCacheCertainty() {
    144         if (mHasCache) {
    145             return mCachedNtpCertainty;
    146         } else {
    147             return Long.MAX_VALUE;
    148         }
    149     }
    150 
    151     @Override
    152     public long currentTimeMillis() {
    153         if (!mHasCache) {
    154             throw new IllegalStateException("Missing authoritative time source");
    155         }
    156         if (LOGD) Log.d(TAG, "currentTimeMillis() cache hit");
    157 
    158         // current time is age after the last ntp cache; callers who
    159         // want fresh values will hit makeAuthoritative() first.
    160         return mCachedNtpTime + getCacheAge();
    161     }
    162 
    163     public long getCachedNtpTime() {
    164         if (LOGD) Log.d(TAG, "getCachedNtpTime() cache hit");
    165         return mCachedNtpTime;
    166     }
    167 
    168     public long getCachedNtpTimeReference() {
    169         return mCachedNtpElapsedRealtime;
    170     }
    171 }
    172