1b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey/* 2b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * Copyright (C) 2011 The Android Open Source Project 3b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * 4b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * you may not use this file except in compliance with the License. 6b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * You may obtain a copy of the License at 7b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * 8b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * 10b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * Unless required by applicable law or agreed to in writing, software 11b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * See the License for the specific language governing permissions and 14b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * limitations under the License. 15b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey */ 16b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 17b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkeypackage android.util; 18b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 19104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkeyimport android.content.ContentResolver; 20104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkeyimport android.content.Context; 21104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkeyimport android.content.res.Resources; 22b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkeyimport android.net.SntpClient; 23b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkeyimport android.os.SystemClock; 24104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkeyimport android.provider.Settings; 25b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 26b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey/** 27104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey * {@link TrustedTime} that connects with a remote NTP server as its trusted 28104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey * time source. 29b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * 30b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey * @hide 31b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey */ 32b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkeypublic class NtpTrustedTime implements TrustedTime { 33104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey private static final String TAG = "NtpTrustedTime"; 34104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey private static final boolean LOGD = false; 35104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey 36104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey private static NtpTrustedTime sSingleton; 37104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey 38104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey private final String mServer; 39104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey private final long mTimeout; 40b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 41b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey private boolean mHasCache; 42b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey private long mCachedNtpTime; 43b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey private long mCachedNtpElapsedRealtime; 44b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey private long mCachedNtpCertainty; 45b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 46104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey private NtpTrustedTime(String server, long timeout) { 47104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server); 48104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey mServer = server; 49104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey mTimeout = timeout; 50b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 51b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 52104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey public static synchronized NtpTrustedTime getInstance(Context context) { 53104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey if (sSingleton == null) { 54104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey final Resources res = context.getResources(); 55104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey final ContentResolver resolver = context.getContentResolver(); 56104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey 57104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey final String defaultServer = res.getString( 58104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey com.android.internal.R.string.config_ntpServer); 59104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey final long defaultTimeout = res.getInteger( 60104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey com.android.internal.R.integer.config_ntpTimeout); 61104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey 62e6e6197d7c2eb5c29224bcddb0131a302267f6deJeff Sharkey final String secureServer = Settings.Global.getString( 63023c05a341b87d0899c89bf355b6ae27d138bb03Jeff Sharkey resolver, Settings.Global.NTP_SERVER); 64e6e6197d7c2eb5c29224bcddb0131a302267f6deJeff Sharkey final long timeout = Settings.Global.getLong( 65023c05a341b87d0899c89bf355b6ae27d138bb03Jeff Sharkey resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout); 66104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey 67104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey final String server = secureServer != null ? secureServer : defaultServer; 68104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey sSingleton = new NtpTrustedTime(server, timeout); 69104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey } 70104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey 71104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey return sSingleton; 72b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 73b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 74023c05a341b87d0899c89bf355b6ae27d138bb03Jeff Sharkey @Override 75b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey public boolean forceRefresh() { 76104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey if (mServer == null) { 77f055829f358f995efe3964706860f101a129f5e3Jeff Sharkey // missing server, so no trusted time available 78f055829f358f995efe3964706860f101a129f5e3Jeff Sharkey return false; 79b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 80b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 81104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey if (LOGD) Log.d(TAG, "forceRefresh() from cache miss"); 82b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey final SntpClient client = new SntpClient(); 83104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey if (client.requestTime(mServer, (int) mTimeout)) { 84b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey mHasCache = true; 85b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey mCachedNtpTime = client.getNtpTime(); 86b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey mCachedNtpElapsedRealtime = client.getNtpTimeReference(); 87b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey mCachedNtpCertainty = client.getRoundTripTime() / 2; 88b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey return true; 89b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } else { 90b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey return false; 91b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 92b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 93b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 94023c05a341b87d0899c89bf355b6ae27d138bb03Jeff Sharkey @Override 95b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey public boolean hasCache() { 96b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey return mHasCache; 97b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 98b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 99023c05a341b87d0899c89bf355b6ae27d138bb03Jeff Sharkey @Override 100b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey public long getCacheAge() { 101b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey if (mHasCache) { 102b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey return SystemClock.elapsedRealtime() - mCachedNtpElapsedRealtime; 103b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } else { 104b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey return Long.MAX_VALUE; 105b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 106b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 107b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 108023c05a341b87d0899c89bf355b6ae27d138bb03Jeff Sharkey @Override 109b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey public long getCacheCertainty() { 110b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey if (mHasCache) { 111b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey return mCachedNtpCertainty; 112b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } else { 113b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey return Long.MAX_VALUE; 114b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 115b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 116b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 117023c05a341b87d0899c89bf355b6ae27d138bb03Jeff Sharkey @Override 118b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey public long currentTimeMillis() { 119b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey if (!mHasCache) { 120b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey throw new IllegalStateException("Missing authoritative time source"); 121b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 122104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey if (LOGD) Log.d(TAG, "currentTimeMillis() cache hit"); 123b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey 124b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey // current time is age after the last ntp cache; callers who 125b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey // want fresh values will hit makeAuthoritative() first. 126b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey return mCachedNtpTime + getCacheAge(); 127b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey } 128104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey 129104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey public long getCachedNtpTime() { 130104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey if (LOGD) Log.d(TAG, "getCachedNtpTime() cache hit"); 131104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey return mCachedNtpTime; 132104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey } 133104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey 134104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey public long getCachedNtpTimeReference() { 135104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey return mCachedNtpElapsedRealtime; 136104344e507610be42fb70c7deda3c422c543bfcbJeff Sharkey } 137b7342acebcb7e5dc7da0cda77fbddf50e7dfdd7cJeff Sharkey} 138