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