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