• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NtpTrustedTime(String server, long timeout)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 
getInstance(Context context)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
forceRefresh()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
hasCache()115     public boolean hasCache() {
116         return mHasCache;
117     }
118 
119     @Override
getCacheAge()120     public long getCacheAge() {
121         if (mHasCache) {
122             return SystemClock.elapsedRealtime() - mCachedNtpElapsedRealtime;
123         } else {
124             return Long.MAX_VALUE;
125         }
126     }
127 
128     @Override
getCacheCertainty()129     public long getCacheCertainty() {
130         if (mHasCache) {
131             return mCachedNtpCertainty;
132         } else {
133             return Long.MAX_VALUE;
134         }
135     }
136 
137     @Override
currentTimeMillis()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 
getCachedNtpTime()149     public long getCachedNtpTime() {
150         if (LOGD) Log.d(TAG, "getCachedNtpTime() cache hit");
151         return mCachedNtpTime;
152     }
153 
getCachedNtpTimeReference()154     public long getCachedNtpTimeReference() {
155         return mCachedNtpElapsedRealtime;
156     }
157 }
158