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