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