1 /* 2 * Copyright (C) 2018 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 com.android.server.timedetector; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.UserIdInt; 22 import android.app.ActivityManager; 23 import android.app.time.ExternalTimeSuggestion; 24 import android.app.time.ITimeDetectorListener; 25 import android.app.time.TimeCapabilitiesAndConfig; 26 import android.app.time.TimeConfiguration; 27 import android.app.time.TimeState; 28 import android.app.time.UnixEpochTime; 29 import android.app.timedetector.ITimeDetectorService; 30 import android.app.timedetector.ManualTimeSuggestion; 31 import android.app.timedetector.TelephonyTimeSuggestion; 32 import android.content.Context; 33 import android.os.Binder; 34 import android.os.Handler; 35 import android.os.IBinder; 36 import android.os.ParcelableException; 37 import android.os.RemoteException; 38 import android.os.ResultReceiver; 39 import android.os.ShellCallback; 40 import android.os.SystemClock; 41 import android.util.ArrayMap; 42 import android.util.IndentingPrintWriter; 43 import android.util.NtpTrustedTime; 44 import android.util.Slog; 45 46 import com.android.internal.annotations.GuardedBy; 47 import com.android.internal.annotations.VisibleForTesting; 48 import com.android.internal.util.DumpUtils; 49 import com.android.server.FgThread; 50 import com.android.server.SystemService; 51 import com.android.server.location.gnss.TimeDetectorNetworkTimeHelper; 52 import com.android.server.timezonedetector.CallerIdentityInjector; 53 import com.android.server.timezonedetector.CurrentUserIdentityInjector; 54 55 import java.io.FileDescriptor; 56 import java.io.PrintWriter; 57 import java.net.InetSocketAddress; 58 import java.time.DateTimeException; 59 import java.util.Objects; 60 61 /** 62 * The implementation of ITimeDetectorService.aidl. 63 * 64 * <p>This service is implemented as a wrapper around {@link TimeDetectorStrategy}. It handles 65 * interaction with Android framework classes, enforcing caller permissions, capturing user identity 66 * and making calls async, leaving the (consequently more testable) {@link TimeDetectorStrategy} 67 * implementation to deal with the logic around time detection. 68 */ 69 public final class TimeDetectorService extends ITimeDetectorService.Stub 70 implements IBinder.DeathRecipient { 71 static final String TAG = "time_detector"; 72 73 public static class Lifecycle extends SystemService { 74 Lifecycle(@onNull Context context)75 public Lifecycle(@NonNull Context context) { 76 super(context); 77 } 78 79 @Override onStart()80 public void onStart() { 81 Context context = getContext(); 82 Handler handler = FgThread.getHandler(); 83 84 ServiceConfigAccessor serviceConfigAccessor = 85 ServiceConfigAccessorImpl.getInstance(context); 86 TimeDetectorStrategy timeDetectorStrategy = 87 TimeDetectorStrategyImpl.create(context, handler, serviceConfigAccessor); 88 89 // Create and publish the local service for use by internal callers. 90 CurrentUserIdentityInjector currentUserIdentityInjector = 91 CurrentUserIdentityInjector.REAL; 92 TimeDetectorInternal internal = new TimeDetectorInternalImpl( 93 context, handler, currentUserIdentityInjector, serviceConfigAccessor, 94 timeDetectorStrategy); 95 publishLocalService(TimeDetectorInternal.class, internal); 96 97 CallerIdentityInjector callerIdentityInjector = CallerIdentityInjector.REAL; 98 TimeDetectorService service = new TimeDetectorService( 99 context, handler, callerIdentityInjector, timeDetectorStrategy, 100 NtpTrustedTime.getInstance(context)); 101 102 // Publish the binder service so it can be accessed from other (appropriately 103 // permissioned) processes. 104 publishBinderService(Context.TIME_DETECTOR_SERVICE, service); 105 } 106 } 107 108 @NonNull private final Handler mHandler; 109 @NonNull private final Context mContext; 110 @NonNull private final CallerIdentityInjector mCallerIdentityInjector; 111 @NonNull private final TimeDetectorStrategy mTimeDetectorStrategy; 112 @NonNull private final NtpTrustedTime mNtpTrustedTime; 113 114 /** 115 * Holds the listeners. The key is the {@link IBinder} associated with the listener, the value 116 * is the listener itself. 117 */ 118 @GuardedBy("mListeners") 119 @NonNull 120 private final ArrayMap<IBinder, ITimeDetectorListener> mListeners = new ArrayMap<>(); 121 122 @VisibleForTesting TimeDetectorService(@onNull Context context, @NonNull Handler handler, @NonNull CallerIdentityInjector callerIdentityInjector, @NonNull TimeDetectorStrategy timeDetectorStrategy, @NonNull NtpTrustedTime ntpTrustedTime)123 public TimeDetectorService(@NonNull Context context, @NonNull Handler handler, 124 @NonNull CallerIdentityInjector callerIdentityInjector, 125 @NonNull TimeDetectorStrategy timeDetectorStrategy, 126 @NonNull NtpTrustedTime ntpTrustedTime) { 127 mContext = Objects.requireNonNull(context); 128 mHandler = Objects.requireNonNull(handler); 129 mCallerIdentityInjector = Objects.requireNonNull(callerIdentityInjector); 130 mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy); 131 mNtpTrustedTime = Objects.requireNonNull(ntpTrustedTime); 132 133 // Wire up a change listener so that ITimeDetectorListeners can be notified when the 134 // detector state changes for any reason. 135 mTimeDetectorStrategy.addChangeListener( 136 () -> mHandler.post(this::handleChangeOnHandlerThread)); 137 } 138 139 @Override 140 @NonNull getCapabilitiesAndConfig()141 public TimeCapabilitiesAndConfig getCapabilitiesAndConfig() { 142 int userId = mCallerIdentityInjector.getCallingUserId(); 143 return getTimeCapabilitiesAndConfig(userId); 144 } 145 getTimeCapabilitiesAndConfig(@serIdInt int userId)146 private TimeCapabilitiesAndConfig getTimeCapabilitiesAndConfig(@UserIdInt int userId) { 147 enforceManageTimeDetectorPermission(); 148 149 final long token = mCallerIdentityInjector.clearCallingIdentity(); 150 try { 151 final boolean bypassUserPolicyChecks = false; 152 return mTimeDetectorStrategy.getCapabilitiesAndConfig(userId, bypassUserPolicyChecks); 153 } finally { 154 mCallerIdentityInjector.restoreCallingIdentity(token); 155 } 156 } 157 158 @Override updateConfiguration(@onNull TimeConfiguration configuration)159 public boolean updateConfiguration(@NonNull TimeConfiguration configuration) { 160 int callingUserId = mCallerIdentityInjector.getCallingUserId(); 161 return updateConfiguration(callingUserId, configuration); 162 } 163 164 /** 165 * Updates the user's configuration. Exposed for use by {@link TimeDetectorShellCommand}. 166 */ updateConfiguration(@serIdInt int userId, @NonNull TimeConfiguration configuration)167 boolean updateConfiguration(@UserIdInt int userId, @NonNull TimeConfiguration configuration) { 168 // Resolve constants like USER_CURRENT to the true user ID as needed. 169 int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), 170 Binder.getCallingUid(), userId, false, false, "updateConfiguration", null); 171 172 enforceManageTimeDetectorPermission(); 173 174 Objects.requireNonNull(configuration); 175 176 final long token = mCallerIdentityInjector.clearCallingIdentity(); 177 try { 178 final boolean bypassUserPolicyChecks = false; 179 return mTimeDetectorStrategy.updateConfiguration( 180 resolvedUserId, configuration, bypassUserPolicyChecks); 181 } finally { 182 mCallerIdentityInjector.restoreCallingIdentity(token); 183 } 184 } 185 186 @Override addListener(@onNull ITimeDetectorListener listener)187 public void addListener(@NonNull ITimeDetectorListener listener) { 188 enforceManageTimeDetectorPermission(); 189 Objects.requireNonNull(listener); 190 191 synchronized (mListeners) { 192 IBinder listenerBinder = listener.asBinder(); 193 if (mListeners.containsKey(listenerBinder)) { 194 return; 195 } 196 try { 197 // Ensure the reference to the listener will be removed if the client process dies. 198 listenerBinder.linkToDeath(this, 0 /* flags */); 199 200 // Only add the listener if we can linkToDeath(). 201 mListeners.put(listenerBinder, listener); 202 } catch (RemoteException e) { 203 Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e); 204 } 205 } 206 } 207 208 @Override removeListener(@onNull ITimeDetectorListener listener)209 public void removeListener(@NonNull ITimeDetectorListener listener) { 210 enforceManageTimeDetectorPermission(); 211 Objects.requireNonNull(listener); 212 213 synchronized (mListeners) { 214 IBinder listenerBinder = listener.asBinder(); 215 boolean removedListener = false; 216 if (mListeners.remove(listenerBinder) != null) { 217 // Stop listening for the client process to die. 218 listenerBinder.unlinkToDeath(this, 0 /* flags */); 219 removedListener = true; 220 } 221 if (!removedListener) { 222 Slog.w(TAG, "Client asked to remove listener=" + listener 223 + ", but no listeners were removed." 224 + " mListeners=" + mListeners); 225 } 226 } 227 } 228 229 @Override binderDied()230 public void binderDied() { 231 // Should not be used as binderDied(IBinder who) is overridden. 232 Slog.wtf(TAG, "binderDied() called unexpectedly."); 233 } 234 235 /** 236 * Called when one of the ITimeDetectorListener processes dies before calling 237 * {@link #removeListener(ITimeDetectorListener)}. 238 */ 239 @Override binderDied(IBinder who)240 public void binderDied(IBinder who) { 241 synchronized (mListeners) { 242 boolean removedListener = false; 243 final int listenerCount = mListeners.size(); 244 for (int listenerIndex = listenerCount - 1; listenerIndex >= 0; listenerIndex--) { 245 IBinder listenerBinder = mListeners.keyAt(listenerIndex); 246 if (listenerBinder.equals(who)) { 247 mListeners.removeAt(listenerIndex); 248 removedListener = true; 249 break; 250 } 251 } 252 if (!removedListener) { 253 Slog.w(TAG, "Notified of binder death for who=" + who 254 + ", but did not remove any listeners." 255 + " mListeners=" + mListeners); 256 } 257 } 258 } 259 handleChangeOnHandlerThread()260 private void handleChangeOnHandlerThread() { 261 // Configuration has changed, but each user may have a different view of the configuration. 262 // It's possible that this will cause unnecessary notifications but that shouldn't be a 263 // problem. 264 synchronized (mListeners) { 265 final int listenerCount = mListeners.size(); 266 for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) { 267 ITimeDetectorListener listener = mListeners.valueAt(listenerIndex); 268 try { 269 // No need to surrender the mListeners lock while doing this: 270 // ITimeDetectorListener is declared "oneway". 271 listener.onChange(); 272 } catch (RemoteException e) { 273 Slog.w(TAG, "Unable to notify listener=" + listener, e); 274 } 275 } 276 } 277 } 278 279 @Override getTimeState()280 public TimeState getTimeState() { 281 enforceManageTimeDetectorPermission(); 282 283 final long token = Binder.clearCallingIdentity(); 284 try { 285 return mTimeDetectorStrategy.getTimeState(); 286 } finally { 287 Binder.restoreCallingIdentity(token); 288 } 289 } 290 291 /** 292 * Sets the system time state. See {@link TimeState} for details. For use by {@link 293 * TimeDetectorShellCommand}. 294 */ setTimeState(@onNull TimeState timeState)295 void setTimeState(@NonNull TimeState timeState) { 296 enforceManageTimeDetectorPermission(); 297 298 final long token = Binder.clearCallingIdentity(); 299 try { 300 mTimeDetectorStrategy.setTimeState(timeState); 301 } finally { 302 Binder.restoreCallingIdentity(token); 303 } 304 } 305 306 @Override confirmTime(@onNull UnixEpochTime time)307 public boolean confirmTime(@NonNull UnixEpochTime time) { 308 enforceManageTimeDetectorPermission(); 309 Objects.requireNonNull(time); 310 311 final long token = Binder.clearCallingIdentity(); 312 try { 313 return mTimeDetectorStrategy.confirmTime(time); 314 } finally { 315 Binder.restoreCallingIdentity(token); 316 } 317 } 318 319 @Override setManualTime(@onNull ManualTimeSuggestion suggestion)320 public boolean setManualTime(@NonNull ManualTimeSuggestion suggestion) { 321 enforceManageTimeDetectorPermission(); 322 Objects.requireNonNull(suggestion); 323 324 // This calls suggestManualTime() as the logic is identical, it only differs in the 325 // permission required, which is handled on the line above. 326 int userId = mCallerIdentityInjector.getCallingUserId(); 327 final long token = Binder.clearCallingIdentity(); 328 try { 329 final boolean bypassUserPolicyChecks = false; 330 return mTimeDetectorStrategy.suggestManualTime( 331 userId, suggestion, bypassUserPolicyChecks); 332 } finally { 333 Binder.restoreCallingIdentity(token); 334 } 335 } 336 337 @Override suggestTelephonyTime(@onNull TelephonyTimeSuggestion timeSignal)338 public void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSignal) { 339 enforceSuggestTelephonyTimePermission(); 340 Objects.requireNonNull(timeSignal); 341 342 mHandler.post(() -> mTimeDetectorStrategy.suggestTelephonyTime(timeSignal)); 343 } 344 345 @Override suggestManualTime(@onNull ManualTimeSuggestion timeSignal)346 public boolean suggestManualTime(@NonNull ManualTimeSuggestion timeSignal) { 347 enforceSuggestManualTimePermission(); 348 Objects.requireNonNull(timeSignal); 349 350 int userId = mCallerIdentityInjector.getCallingUserId(); 351 final long token = mCallerIdentityInjector.clearCallingIdentity(); 352 try { 353 final boolean bypassUserPolicyChecks = false; 354 return mTimeDetectorStrategy.suggestManualTime( 355 userId, timeSignal, bypassUserPolicyChecks); 356 } finally { 357 mCallerIdentityInjector.restoreCallingIdentity(token); 358 } 359 } 360 361 /** 362 * Suggests network time with permission checks. For use by {@link TimeDetectorShellCommand}. 363 */ suggestNetworkTime(@onNull NetworkTimeSuggestion suggestion)364 void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion) { 365 enforceSuggestNetworkTimePermission(); 366 Objects.requireNonNull(suggestion); 367 368 mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(suggestion)); 369 } 370 371 /** 372 * Clears the cached network time information. For use during tests to simulate when no network 373 * time has been made available. For use by {@link TimeDetectorShellCommand}. 374 * 375 * <p>This operation takes place in the calling thread. 376 */ clearLatestNetworkTime()377 void clearLatestNetworkTime() { 378 enforceSuggestNetworkTimePermission(); 379 380 final long token = Binder.clearCallingIdentity(); 381 try { 382 mTimeDetectorStrategy.clearLatestNetworkSuggestion(); 383 } finally { 384 Binder.restoreCallingIdentity(token); 385 } 386 } 387 388 @Override latestNetworkTime()389 public UnixEpochTime latestNetworkTime() { 390 NetworkTimeSuggestion latestNetworkTime; 391 // TODO(b/222295093): Remove this condition once we can be sure that all uses of 392 // NtpTrustedTime result in a suggestion being made to the time detector. 393 // mNtpTrustedTime can be removed once this happens. 394 if (TimeDetectorNetworkTimeHelper.isInUse()) { 395 // The new implementation. 396 latestNetworkTime = mTimeDetectorStrategy.getLatestNetworkSuggestion(); 397 } else { 398 // The old implementation. 399 NtpTrustedTime.TimeResult ntpResult = mNtpTrustedTime.getCachedTimeResult(); 400 if (ntpResult != null) { 401 latestNetworkTime = new NetworkTimeSuggestion( 402 new UnixEpochTime( 403 ntpResult.getElapsedRealtimeMillis(), ntpResult.getTimeMillis()), 404 ntpResult.getUncertaintyMillis()); 405 } else { 406 latestNetworkTime = null; 407 } 408 } 409 if (latestNetworkTime == null) { 410 throw new ParcelableException(new DateTimeException("Missing network time fix")); 411 } 412 return latestNetworkTime.getUnixEpochTime(); 413 } 414 415 /** 416 * Returns the latest network suggestion accepted. For use by {@link TimeDetectorShellCommand}. 417 */ 418 @Nullable getLatestNetworkSuggestion()419 NetworkTimeSuggestion getLatestNetworkSuggestion() { 420 return mTimeDetectorStrategy.getLatestNetworkSuggestion(); 421 } 422 423 /** 424 * Suggests GNSS time with permission checks. For use by {@link TimeDetectorShellCommand}. 425 */ suggestGnssTime(@onNull GnssTimeSuggestion timeSignal)426 void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal) { 427 enforceSuggestGnssTimePermission(); 428 Objects.requireNonNull(timeSignal); 429 430 mHandler.post(() -> mTimeDetectorStrategy.suggestGnssTime(timeSignal)); 431 } 432 433 @Override suggestExternalTime(@onNull ExternalTimeSuggestion timeSignal)434 public void suggestExternalTime(@NonNull ExternalTimeSuggestion timeSignal) { 435 enforceSuggestExternalTimePermission(); 436 Objects.requireNonNull(timeSignal); 437 438 mHandler.post(() -> mTimeDetectorStrategy.suggestExternalTime(timeSignal)); 439 } 440 441 /** 442 * Sets the network time for testing {@link SystemClock#currentNetworkTimeClock()}. 443 * 444 * <p>This operation takes place in the calling thread. 445 */ setNetworkTimeForSystemClockForTests( @onNull UnixEpochTime unixEpochTime, int uncertaintyMillis)446 void setNetworkTimeForSystemClockForTests( 447 @NonNull UnixEpochTime unixEpochTime, int uncertaintyMillis) { 448 enforceSuggestNetworkTimePermission(); 449 450 // TODO(b/222295093): Remove this condition once we can be sure that all uses of 451 // NtpTrustedTime result in a suggestion being made to the time detector. 452 // mNtpTrustedTime can be removed once this happens. 453 if (TimeDetectorNetworkTimeHelper.isInUse()) { 454 NetworkTimeSuggestion suggestion = 455 new NetworkTimeSuggestion(unixEpochTime, uncertaintyMillis); 456 suggestion.addDebugInfo("Injected for tests"); 457 mTimeDetectorStrategy.suggestNetworkTime(suggestion); 458 } else { 459 NtpTrustedTime.TimeResult timeResult = new NtpTrustedTime.TimeResult( 460 unixEpochTime.getUnixEpochTimeMillis(), 461 unixEpochTime.getElapsedRealtimeMillis(), 462 uncertaintyMillis, 463 InetSocketAddress.createUnresolved("time.set.for.tests", 123)); 464 mNtpTrustedTime.setCachedTimeResult(timeResult); 465 } 466 } 467 468 /** 469 * Clears the network time for testing {@link SystemClock#currentNetworkTimeClock()}. 470 * 471 * <p>This operation takes place in the calling thread. 472 */ clearNetworkTimeForSystemClockForTests()473 void clearNetworkTimeForSystemClockForTests() { 474 enforceSuggestNetworkTimePermission(); 475 476 final long token = Binder.clearCallingIdentity(); 477 try { 478 // TODO(b/222295093): Remove this condition once we can be sure that all uses of 479 // NtpTrustedTime result in a suggestion being made to the time detector. 480 // mNtpTrustedTime can be removed once this happens. 481 if (TimeDetectorNetworkTimeHelper.isInUse()) { 482 // Clear the latest network suggestion. Done in all c 483 mTimeDetectorStrategy.clearLatestNetworkSuggestion(); 484 } else { 485 mNtpTrustedTime.clearCachedTimeResult(); 486 } 487 } finally { 488 Binder.restoreCallingIdentity(token); 489 } 490 } 491 492 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter pw, @Nullable String[] args)493 protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, 494 @Nullable String[] args) { 495 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 496 497 IndentingPrintWriter ipw = new IndentingPrintWriter(pw); 498 mTimeDetectorStrategy.dump(ipw, args); 499 ipw.flush(); 500 } 501 502 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)503 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 504 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 505 new TimeDetectorShellCommand(this).exec( 506 this, in, out, err, args, callback, resultReceiver); 507 } 508 enforceSuggestTelephonyTimePermission()509 private void enforceSuggestTelephonyTimePermission() { 510 mContext.enforceCallingPermission( 511 android.Manifest.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE, 512 "suggest telephony time and time zone"); 513 } 514 enforceSuggestManualTimePermission()515 private void enforceSuggestManualTimePermission() { 516 mContext.enforceCallingPermission( 517 android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE, 518 "suggest manual time and time zone"); 519 } 520 enforceSuggestNetworkTimePermission()521 private void enforceSuggestNetworkTimePermission() { 522 mContext.enforceCallingPermission( 523 android.Manifest.permission.SET_TIME, 524 "suggest network time"); 525 } 526 enforceSuggestGnssTimePermission()527 private void enforceSuggestGnssTimePermission() { 528 mContext.enforceCallingPermission( 529 android.Manifest.permission.SET_TIME, 530 "suggest gnss time"); 531 } 532 enforceSuggestExternalTimePermission()533 private void enforceSuggestExternalTimePermission() { 534 // We don't expect a call from system server, so simply enforce calling permission. 535 mContext.enforceCallingPermission( 536 android.Manifest.permission.SUGGEST_EXTERNAL_TIME, 537 "suggest time from external source"); 538 } 539 enforceManageTimeDetectorPermission()540 private void enforceManageTimeDetectorPermission() { 541 mContext.enforceCallingPermission( 542 android.Manifest.permission.MANAGE_TIME_AND_ZONE_DETECTION, 543 "manage time and time zone detection"); 544 } 545 } 546