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 17package android.util; 18 19import android.content.ContentResolver; 20import android.content.Context; 21import android.content.res.Resources; 22import android.net.ConnectivityManager; 23import android.net.Network; 24import android.net.NetworkInfo; 25import android.net.SntpClient; 26import android.os.SystemClock; 27import android.provider.Settings; 28import 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 */ 36public 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