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