1 /* 2 * Copyright (C) 2013 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; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.UserIdInt; 22 import android.app.ActivityManager; 23 import android.content.Context; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.PackageInfo; 26 import android.content.pm.PackageManager; 27 import android.content.pm.UserInfo; 28 import android.os.Environment; 29 import android.os.SystemClock; 30 import android.os.Trace; 31 import android.os.UserHandle; 32 import android.util.ArraySet; 33 import android.util.Dumpable; 34 import android.util.EventLog; 35 import android.util.Slog; 36 import android.util.SparseArray; 37 38 import com.android.internal.annotations.GuardedBy; 39 import com.android.internal.os.SystemServerClassLoaderFactory; 40 import com.android.internal.util.Preconditions; 41 import com.android.server.SystemService.TargetUser; 42 import com.android.server.SystemService.UserCompletedEventType; 43 import com.android.server.am.EventLogTags; 44 import com.android.server.pm.ApexManager; 45 import com.android.server.pm.UserManagerInternal; 46 import com.android.server.utils.TimingsTraceAndSlog; 47 48 import dalvik.system.PathClassLoader; 49 50 import java.io.File; 51 import java.io.PrintWriter; 52 import java.lang.reflect.Constructor; 53 import java.lang.reflect.InvocationTargetException; 54 import java.nio.file.Path; 55 import java.nio.file.Paths; 56 import java.util.ArrayList; 57 import java.util.Collections; 58 import java.util.List; 59 import java.util.Set; 60 import java.util.concurrent.ExecutorService; 61 import java.util.concurrent.Executors; 62 import java.util.concurrent.TimeUnit; 63 64 /** 65 * Manages creating, starting, and other lifecycle events of 66 * {@link com.android.server.SystemService system services}. 67 * 68 * {@hide} 69 */ 70 public final class SystemServiceManager implements Dumpable { 71 private static final String TAG = SystemServiceManager.class.getSimpleName(); 72 private static final boolean DEBUG = false; 73 private static final int SERVICE_CALL_WARN_TIME_MS = 50; 74 75 // Constants used on onUser(...) 76 // NOTE: do not change their values, as they're used on Trace calls and changes might break 77 // performance tests that rely on them. 78 private static final String USER_STARTING = "Start"; // Logged as onUserStarting() 79 private static final String USER_UNLOCKING = "Unlocking"; // Logged as onUserUnlocking() 80 private static final String USER_UNLOCKED = "Unlocked"; // Logged as onUserUnlocked() 81 private static final String USER_SWITCHING = "Switch"; // Logged as onUserSwitching() 82 private static final String USER_STOPPING = "Stop"; // Logged as onUserStopping() 83 private static final String USER_STOPPED = "Cleanup"; // Logged as onUserStopped() 84 private static final String USER_COMPLETED_EVENT = "CompletedEvent"; // onUserCompletedEvent() 85 86 // The default number of threads to use if lifecycle thread pool is enabled. 87 private static final int DEFAULT_MAX_USER_POOL_THREADS = 3; 88 // The number of threads to use if lifecycle thread pool is enabled, dependent on the number of 89 // available cores on the device. 90 private final int mNumUserPoolThreads; 91 // Maximum time to wait for a particular lifecycle phase to finish. 92 private static final long USER_POOL_SHUTDOWN_TIMEOUT_SECONDS = 30; 93 // Indirectly indicates how many services belong in the bootstrap and core service categories. 94 // This is used to decide which services the user lifecycle phases should be parallelized for. 95 private static volatile int sOtherServicesStartIndex; 96 97 private static File sSystemDir; 98 private final Context mContext; 99 private boolean mSafeMode; 100 private boolean mRuntimeRestarted; 101 private long mRuntimeStartElapsedTime; 102 private long mRuntimeStartUptime; 103 104 // Services that should receive lifecycle events. 105 private List<SystemService> mServices; 106 private Set<String> mServiceClassnames; 107 108 private int mCurrentPhase = -1; 109 110 private UserManagerInternal mUserManagerInternal; 111 112 /** 113 * Map of started {@link TargetUser TargetUsers} by user id; users are added on start and 114 * removed after they're completely shut down. 115 */ 116 @GuardedBy("mTargetUsers") 117 private final SparseArray<TargetUser> mTargetUsers = new SparseArray<>(); 118 119 /** 120 * Reference to the current user, it's used to set the {@link TargetUser} on 121 * {@link #onUserSwitching(int, int)} as the previous user might have been removed already. 122 */ 123 @GuardedBy("mTargetUsers") 124 @Nullable private TargetUser mCurrentUser; 125 SystemServiceManager(Context context)126 SystemServiceManager(Context context) { 127 mContext = context; 128 mServices = new ArrayList<>(); 129 mServiceClassnames = new ArraySet<>(); 130 mNumUserPoolThreads = Math.min(Runtime.getRuntime().availableProcessors(), 131 DEFAULT_MAX_USER_POOL_THREADS); 132 } 133 134 /** 135 * Starts a service by class name. 136 * 137 * @return The service instance. 138 */ startService(String className)139 public SystemService startService(String className) { 140 final Class<SystemService> serviceClass = loadClassFromLoader(className, 141 this.getClass().getClassLoader()); 142 return startService(serviceClass); 143 } 144 145 /** 146 * Starts a service by class name and a path that specifies the jar where the service lives. 147 * 148 * @return The service instance. 149 */ startServiceFromJar(String className, String path)150 public SystemService startServiceFromJar(String className, String path) { 151 PathClassLoader pathClassLoader = 152 SystemServerClassLoaderFactory.getOrCreateClassLoader( 153 path, this.getClass().getClassLoader(), isJarInTestApex(path)); 154 final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader); 155 return startService(serviceClass); 156 } 157 158 /** 159 * Returns true if the jar is in a test APEX. 160 */ isJarInTestApex(String pathStr)161 private boolean isJarInTestApex(String pathStr) { 162 Path path = Paths.get(pathStr); 163 if (path.getNameCount() >= 2 && path.getName(0).toString().equals("apex")) { 164 String apexModuleName = path.getName(1).toString(); 165 ApexManager apexManager = ApexManager.getInstance(); 166 String packageName = apexManager.getActivePackageNameForApexModuleName(apexModuleName); 167 try { 168 PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(packageName, 169 PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX)); 170 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0; 171 } catch (Exception ignore) { 172 } 173 } 174 return false; 175 } 176 177 /* 178 * Loads and initializes a class from the given classLoader. Returns the class. 179 */ 180 @SuppressWarnings("unchecked") loadClassFromLoader(String className, ClassLoader classLoader)181 private static Class<SystemService> loadClassFromLoader(String className, 182 ClassLoader classLoader) { 183 try { 184 return (Class<SystemService>) Class.forName(className, true, classLoader); 185 } catch (ClassNotFoundException ex) { 186 throw new RuntimeException("Failed to create service " + className 187 + " from class loader " + classLoader.toString() + ": service class not " 188 + "found, usually indicates that the caller should " 189 + "have called PackageManager.hasSystemFeature() to check whether the " 190 + "feature is available on this device before trying to start the " 191 + "services that implement it. Also ensure that the correct path for the " 192 + "classloader is supplied, if applicable.", ex); 193 } 194 } 195 196 /** 197 * Creates and starts a system service. The class must be a subclass of 198 * {@link com.android.server.SystemService}. 199 * 200 * @param serviceClass A Java class that implements the SystemService interface. 201 * @return The service instance, never null. 202 * @throws RuntimeException if the service fails to start. 203 */ startService(Class<T> serviceClass)204 public <T extends SystemService> T startService(Class<T> serviceClass) { 205 try { 206 final String name = serviceClass.getName(); 207 Slog.i(TAG, "Starting " + name); 208 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name); 209 210 // Create the service. 211 if (!SystemService.class.isAssignableFrom(serviceClass)) { 212 throw new RuntimeException("Failed to create " + name 213 + ": service must extend " + SystemService.class.getName()); 214 } 215 final T service; 216 try { 217 Constructor<T> constructor = serviceClass.getConstructor(Context.class); 218 service = constructor.newInstance(mContext); 219 } catch (InstantiationException ex) { 220 throw new RuntimeException("Failed to create service " + name 221 + ": service could not be instantiated", ex); 222 } catch (IllegalAccessException ex) { 223 throw new RuntimeException("Failed to create service " + name 224 + ": service must have a public constructor with a Context argument", ex); 225 } catch (NoSuchMethodException ex) { 226 throw new RuntimeException("Failed to create service " + name 227 + ": service must have a public constructor with a Context argument", ex); 228 } catch (InvocationTargetException ex) { 229 throw new RuntimeException("Failed to create service " + name 230 + ": service constructor threw an exception", ex); 231 } 232 233 startService(service); 234 return service; 235 } finally { 236 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 237 } 238 } 239 startService(@onNull final SystemService service)240 public void startService(@NonNull final SystemService service) { 241 // Check if already started 242 String className = service.getClass().getName(); 243 if (mServiceClassnames.contains(className)) { 244 Slog.i(TAG, "Not starting an already started service " + className); 245 return; 246 } 247 mServiceClassnames.add(className); 248 249 // Register it. 250 mServices.add(service); 251 252 // Start it. 253 long time = SystemClock.elapsedRealtime(); 254 try { 255 service.onStart(); 256 } catch (RuntimeException ex) { 257 throw new RuntimeException("Failed to start service " + service.getClass().getName() 258 + ": onStart threw an exception", ex); 259 } 260 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart"); 261 } 262 263 /** Disallow starting new services after this call. */ sealStartedServices()264 void sealStartedServices() { 265 mServiceClassnames = Collections.emptySet(); 266 mServices = Collections.unmodifiableList(mServices); 267 } 268 269 /** 270 * Starts the specified boot phase for all system services that have been started up to 271 * this point. 272 * 273 * @param t trace logger 274 * @param phase The boot phase to start. 275 */ startBootPhase(@onNull TimingsTraceAndSlog t, int phase)276 public void startBootPhase(@NonNull TimingsTraceAndSlog t, int phase) { 277 if (phase <= mCurrentPhase) { 278 throw new IllegalArgumentException("Next phase must be larger than previous"); 279 } 280 mCurrentPhase = phase; 281 282 Slog.i(TAG, "Starting phase " + mCurrentPhase); 283 try { 284 t.traceBegin("OnBootPhase_" + phase); 285 final int serviceLen = mServices.size(); 286 for (int i = 0; i < serviceLen; i++) { 287 final SystemService service = mServices.get(i); 288 long time = SystemClock.elapsedRealtime(); 289 t.traceBegin("OnBootPhase_" + phase + "_" + service.getClass().getName()); 290 try { 291 service.onBootPhase(mCurrentPhase); 292 } catch (Exception ex) { 293 throw new RuntimeException("Failed to boot service " 294 + service.getClass().getName() 295 + ": onBootPhase threw an exception during phase " 296 + mCurrentPhase, ex); 297 } 298 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase"); 299 t.traceEnd(); 300 } 301 } finally { 302 t.traceEnd(); 303 } 304 305 if (phase == SystemService.PHASE_BOOT_COMPLETED) { 306 final long totalBootTime = SystemClock.uptimeMillis() - mRuntimeStartUptime; 307 t.logDuration("TotalBootTime", totalBootTime); 308 SystemServerInitThreadPool.shutdown(); 309 } 310 } 311 312 /** 313 * @return true if system has completed the boot; false otherwise. 314 */ isBootCompleted()315 public boolean isBootCompleted() { 316 return mCurrentPhase >= SystemService.PHASE_BOOT_COMPLETED; 317 } 318 319 /** 320 * Called from SystemServer to indicate that services in the other category are now starting. 321 * This is used to keep track of how many services are in the bootstrap and core service 322 * categories for the purposes of user lifecycle parallelization. 323 */ updateOtherServicesStartIndex()324 public void updateOtherServicesStartIndex() { 325 // Only update the index if the boot phase has not been completed yet 326 if (!isBootCompleted()) { 327 sOtherServicesStartIndex = mServices.size(); 328 } 329 } 330 331 /** 332 * Called at the beginning of {@code ActivityManagerService.systemReady()}. 333 */ preSystemReady()334 public void preSystemReady() { 335 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); 336 } 337 getTargetUser(@serIdInt int userId)338 @Nullable private TargetUser getTargetUser(@UserIdInt int userId) { 339 synchronized (mTargetUsers) { 340 return mTargetUsers.get(userId); 341 } 342 } 343 newTargetUser(@serIdInt int userId)344 private @NonNull TargetUser newTargetUser(@UserIdInt int userId) { 345 final UserInfo userInfo = mUserManagerInternal.getUserInfo(userId); 346 Preconditions.checkState(userInfo != null, "No UserInfo for " + userId); 347 return new TargetUser(userInfo); 348 } 349 350 /** 351 * Starts the given user. 352 */ onUserStarting(@onNull TimingsTraceAndSlog t, @UserIdInt int userId)353 public void onUserStarting(@NonNull TimingsTraceAndSlog t, @UserIdInt int userId) { 354 final TargetUser targetUser = newTargetUser(userId); 355 synchronized (mTargetUsers) { 356 // On Automotive / Headless System User Mode, the system user will be started twice: 357 // - Once by some external or local service that switches the system user to 358 // the background. 359 // - Once by the ActivityManagerService, when the system is marked ready. 360 // These two events are not synchronized and the order of execution is 361 // non-deterministic. To avoid starting the system user twice, verify whether 362 // the system user has already been started by checking the mTargetUsers. 363 // TODO(b/242195409): this workaround shouldn't be necessary once we move 364 // the headless-user start logic to UserManager-land. 365 if (userId == UserHandle.USER_SYSTEM && mTargetUsers.contains(userId)) { 366 Slog.e(TAG, "Skipping starting system user twice"); 367 return; 368 } 369 mTargetUsers.put(userId, targetUser); 370 } 371 EventLog.writeEvent(EventLogTags.SSM_USER_STARTING, userId); 372 onUser(t, USER_STARTING, /* prevUser= */ null, targetUser); 373 } 374 375 /** 376 * Unlocks the given user. 377 */ onUserUnlocking(@serIdInt int userId)378 public void onUserUnlocking(@UserIdInt int userId) { 379 EventLog.writeEvent(EventLogTags.SSM_USER_UNLOCKING, userId); 380 onUser(USER_UNLOCKING, userId); 381 } 382 383 /** 384 * Called after the user was unlocked. 385 */ onUserUnlocked(@serIdInt int userId)386 public void onUserUnlocked(@UserIdInt int userId) { 387 EventLog.writeEvent(EventLogTags.SSM_USER_UNLOCKED, userId); 388 onUser(USER_UNLOCKED, userId); 389 } 390 391 /** 392 * Switches to the given user. 393 */ onUserSwitching(@serIdInt int from, @UserIdInt int to)394 public void onUserSwitching(@UserIdInt int from, @UserIdInt int to) { 395 EventLog.writeEvent(EventLogTags.SSM_USER_SWITCHING, from, to); 396 final TargetUser curUser, prevUser; 397 synchronized (mTargetUsers) { 398 if (mCurrentUser == null) { 399 if (DEBUG) { 400 Slog.d(TAG, "First user switch: from " + from + " to " + to); 401 } 402 prevUser = newTargetUser(from); 403 } else { 404 if (from != mCurrentUser.getUserIdentifier()) { 405 Slog.wtf(TAG, "switchUser(" + from + "," + to + "): mCurrentUser is " 406 + mCurrentUser + ", it should be " + from); 407 } 408 prevUser = mCurrentUser; 409 } 410 curUser = mCurrentUser = getTargetUser(to); 411 Preconditions.checkState(curUser != null, "No TargetUser for " + to); 412 if (DEBUG) { 413 Slog.d(TAG, "Set mCurrentUser to " + mCurrentUser); 414 } 415 } 416 onUser(TimingsTraceAndSlog.newAsyncLog(), USER_SWITCHING, prevUser, curUser); 417 } 418 419 /** 420 * Stops the given user. 421 */ onUserStopping(@serIdInt int userId)422 public void onUserStopping(@UserIdInt int userId) { 423 EventLog.writeEvent(EventLogTags.SSM_USER_STOPPING, userId); 424 onUser(USER_STOPPING, userId); 425 } 426 427 /** 428 * Cleans up the given user. 429 */ onUserStopped(@serIdInt int userId)430 public void onUserStopped(@UserIdInt int userId) { 431 EventLog.writeEvent(EventLogTags.SSM_USER_STOPPED, userId); 432 onUser(USER_STOPPED, userId); 433 434 // Remove cached TargetUser 435 synchronized (mTargetUsers) { 436 mTargetUsers.remove(userId); 437 } 438 } 439 440 /** 441 * Called some time <i>after</i> an onUser... event has completed, for the events delineated in 442 * {@link UserCompletedEventType}. 443 * 444 * @param eventFlags the events that completed, per {@link UserCompletedEventType}, or 0. 445 * @see SystemService#onUserCompletedEvent 446 */ onUserCompletedEvent(@serIdInt int userId, @UserCompletedEventType.EventTypesFlag int eventFlags)447 public void onUserCompletedEvent(@UserIdInt int userId, 448 @UserCompletedEventType.EventTypesFlag int eventFlags) { 449 EventLog.writeEvent(EventLogTags.SSM_USER_COMPLETED_EVENT, userId, eventFlags); 450 if (eventFlags == 0) { 451 return; 452 } 453 454 TargetUser targetUser = getTargetUser(userId); 455 if (targetUser == null) { 456 return; 457 } 458 459 onUser(TimingsTraceAndSlog.newAsyncLog(), 460 USER_COMPLETED_EVENT, 461 /* prevUser= */ null, 462 targetUser, 463 new UserCompletedEventType(eventFlags)); 464 } 465 onUser(@onNull String onWhat, @UserIdInt int userId)466 private void onUser(@NonNull String onWhat, @UserIdInt int userId) { 467 TargetUser targetUser = getTargetUser(userId); 468 Preconditions.checkState(targetUser != null, "No TargetUser for " + userId); 469 470 onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, /* prevUser= */ null, targetUser); 471 } 472 onUser(@onNull TimingsTraceAndSlog t, @NonNull String onWhat, @Nullable TargetUser prevUser, @NonNull TargetUser curUser)473 private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat, 474 @Nullable TargetUser prevUser, @NonNull TargetUser curUser) { 475 onUser(t, onWhat, prevUser, curUser, /* completedEventType= */ null); 476 } 477 onUser(@onNull TimingsTraceAndSlog t, @NonNull String onWhat, @Nullable TargetUser prevUser, @NonNull TargetUser curUser, @Nullable UserCompletedEventType completedEventType)478 private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat, 479 @Nullable TargetUser prevUser, @NonNull TargetUser curUser, 480 @Nullable UserCompletedEventType completedEventType) { 481 final int curUserId = curUser.getUserIdentifier(); 482 // NOTE: do not change label below, or it might break performance tests that rely on it. 483 t.traceBegin("ssm." + onWhat + "User-" + curUserId); 484 Slog.i(TAG, "Calling on" + onWhat + "User " + curUserId 485 + (prevUser != null ? " (from " + prevUser + ")" : "")); 486 487 final boolean useThreadPool = useThreadPool(curUserId, onWhat); 488 final ExecutorService threadPool = 489 useThreadPool ? Executors.newFixedThreadPool(mNumUserPoolThreads) : null; 490 491 final int serviceLen = mServices.size(); 492 for (int i = 0; i < serviceLen; i++) { 493 final SystemService service = mServices.get(i); 494 final String serviceName = service.getClass().getName(); 495 boolean supported = service.isUserSupported(curUser); 496 497 // Must check if either curUser or prevUser is supported (for example, if switching from 498 // unsupported to supported, we still need to notify the services) 499 if (!supported && prevUser != null) { 500 supported = service.isUserSupported(prevUser); 501 } 502 503 if (!supported) { 504 if (DEBUG) { 505 Slog.d(TAG, "Skipping " + onWhat + "User-" + curUserId + " on service " 506 + serviceName + " because it's not supported (curUser: " 507 + curUser + ", prevUser:" + prevUser + ")"); 508 } else { 509 Slog.i(TAG, "Skipping " + onWhat + "User-" + curUserId + " on " 510 + serviceName); 511 } 512 continue; 513 } 514 final boolean submitToThreadPool = useThreadPool && useThreadPoolForService(onWhat, i); 515 if (!submitToThreadPool) { 516 t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + "_" + serviceName); 517 } 518 long time = SystemClock.elapsedRealtime(); 519 try { 520 switch (onWhat) { 521 case USER_SWITCHING: 522 service.onUserSwitching(prevUser, curUser); 523 break; 524 case USER_STARTING: 525 if (submitToThreadPool) { 526 threadPool.submit(getOnUserStartingRunnable(t, service, curUser)); 527 } else { 528 service.onUserStarting(curUser); 529 } 530 break; 531 case USER_UNLOCKING: 532 service.onUserUnlocking(curUser); 533 break; 534 case USER_UNLOCKED: 535 service.onUserUnlocked(curUser); 536 break; 537 case USER_STOPPING: 538 service.onUserStopping(curUser); 539 break; 540 case USER_STOPPED: 541 service.onUserStopped(curUser); 542 break; 543 case USER_COMPLETED_EVENT: 544 threadPool.submit(getOnUserCompletedEventRunnable( 545 t, service, serviceName, curUser, completedEventType)); 546 break; 547 default: 548 throw new IllegalArgumentException(onWhat + " what?"); 549 } 550 } catch (Exception ex) { 551 logFailure(onWhat, curUser, serviceName, ex); 552 } 553 if (!submitToThreadPool) { 554 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, 555 "on" + onWhat + "User-" + curUserId); 556 t.traceEnd(); // what on service 557 } 558 } 559 if (useThreadPool) { 560 boolean terminated = false; 561 threadPool.shutdown(); 562 try { 563 terminated = threadPool.awaitTermination( 564 USER_POOL_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS); 565 } catch (InterruptedException e) { 566 logFailure(onWhat, curUser, "(user lifecycle threadpool was interrupted)", e); 567 } 568 if (!terminated) { 569 logFailure(onWhat, curUser, "(user lifecycle threadpool was not terminated)", null); 570 } 571 } 572 t.traceEnd(); // main entry 573 } 574 575 /** 576 * Whether the given onWhat should use a thread pool. 577 * IMPORTANT: changing the logic to return true won't necessarily make it multi-threaded. 578 * There needs to be a corresponding logic change in onUser() to actually submit 579 * to a threadPool for the given onWhat. 580 */ useThreadPool(int userId, @NonNull String onWhat)581 private boolean useThreadPool(int userId, @NonNull String onWhat) { 582 switch (onWhat) { 583 case USER_STARTING: 584 // Don't allow lifecycle parallelization for user start on low ram devices and 585 // the system user. 586 return !ActivityManager.isLowRamDeviceStatic() && userId != UserHandle.USER_SYSTEM; 587 case USER_COMPLETED_EVENT: 588 return true; 589 default: 590 return false; 591 } 592 } 593 useThreadPoolForService(@onNull String onWhat, int serviceIndex)594 private boolean useThreadPoolForService(@NonNull String onWhat, int serviceIndex) { 595 switch (onWhat) { 596 case USER_STARTING: 597 // Only submit this service to the thread pool if it's in the "other" category. 598 return serviceIndex >= sOtherServicesStartIndex; 599 case USER_COMPLETED_EVENT: 600 return true; 601 default: 602 return false; 603 } 604 } 605 getOnUserStartingRunnable(TimingsTraceAndSlog oldTrace, SystemService service, TargetUser curUser)606 private Runnable getOnUserStartingRunnable(TimingsTraceAndSlog oldTrace, SystemService service, 607 TargetUser curUser) { 608 return () -> { 609 final TimingsTraceAndSlog t = new TimingsTraceAndSlog(oldTrace); 610 final String serviceName = service.getClass().getName(); 611 final int curUserId = curUser.getUserIdentifier(); 612 t.traceBegin("ssm.on" + USER_STARTING + "User-" + curUserId + "_" + serviceName); 613 try { 614 long time = SystemClock.elapsedRealtime(); 615 service.onUserStarting(curUser); 616 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, 617 "on" + USER_STARTING + "User-" + curUserId); 618 } catch (Exception e) { 619 logFailure(USER_STARTING, curUser, serviceName, e); 620 } finally { 621 t.traceEnd(); 622 } 623 }; 624 } 625 getOnUserCompletedEventRunnable(TimingsTraceAndSlog oldTrace, SystemService service, String serviceName, TargetUser curUser, UserCompletedEventType eventType)626 private Runnable getOnUserCompletedEventRunnable(TimingsTraceAndSlog oldTrace, 627 SystemService service, String serviceName, TargetUser curUser, 628 UserCompletedEventType eventType) { 629 return () -> { 630 final TimingsTraceAndSlog t = new TimingsTraceAndSlog(oldTrace); 631 final int curUserId = curUser.getUserIdentifier(); 632 t.traceBegin("ssm.on" + USER_COMPLETED_EVENT + "User-" + curUserId 633 + "_" + eventType + "_" + serviceName); 634 try { 635 long time = SystemClock.elapsedRealtime(); 636 service.onUserCompletedEvent(curUser, eventType); 637 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, 638 "on" + USER_COMPLETED_EVENT + "User-" + curUserId); 639 } catch (Exception e) { 640 logFailure(USER_COMPLETED_EVENT, curUser, serviceName, e); 641 throw e; 642 } finally { 643 t.traceEnd(); 644 } 645 }; 646 } 647 648 /** Logs the failure. That's all. Tests may rely on parsing it, so only modify carefully. */ 649 private void logFailure(String onWhat, TargetUser curUser, String serviceName, Exception ex) { 650 Slog.wtf(TAG, "SystemService failure: Failure reporting " + onWhat + " of user " 651 + curUser + " to service " + serviceName, ex); 652 } 653 654 /** Sets the safe mode flag for services to query. */ 655 void setSafeMode(boolean safeMode) { 656 mSafeMode = safeMode; 657 } 658 659 /** 660 * Returns whether we are booting into safe mode. 661 * 662 * @return safe mode flag 663 */ 664 public boolean isSafeMode() { 665 return mSafeMode; 666 } 667 668 /** 669 * @return true if runtime was restarted, false if it's normal boot 670 */ 671 public boolean isRuntimeRestarted() { 672 return mRuntimeRestarted; 673 } 674 675 /** 676 * @return Time when SystemServer was started, in elapsed realtime. 677 */ 678 public long getRuntimeStartElapsedTime() { 679 return mRuntimeStartElapsedTime; 680 } 681 682 /** 683 * @return Time when SystemServer was started, in uptime. 684 */ 685 public long getRuntimeStartUptime() { 686 return mRuntimeStartUptime; 687 } 688 689 void setStartInfo(boolean runtimeRestarted, 690 long runtimeStartElapsedTime, long runtimeStartUptime) { 691 mRuntimeRestarted = runtimeRestarted; 692 mRuntimeStartElapsedTime = runtimeStartElapsedTime; 693 mRuntimeStartUptime = runtimeStartUptime; 694 } 695 696 private void warnIfTooLong(long duration, SystemService service, String operation) { 697 if (duration > SERVICE_CALL_WARN_TIME_MS) { 698 Slog.w(TAG, "Service " + service.getClass().getName() + " took " + duration + " ms in " 699 + operation); 700 } 701 } 702 703 /** 704 * Ensures that the system directory exist creating one if needed. 705 * 706 * @return The system directory. 707 * @deprecated Use {@link Environment#getDataSystemCeDirectory()} 708 * or {@link Environment#getDataSystemDeDirectory()} instead. 709 */ 710 @Deprecated 711 public static File ensureSystemDir() { 712 if (sSystemDir == null) { 713 File dataDir = Environment.getDataDirectory(); 714 sSystemDir = new File(dataDir, "system"); 715 sSystemDir.mkdirs(); 716 } 717 return sSystemDir; 718 } 719 720 @Override 721 public String getDumpableName() { 722 return SystemServiceManager.class.getSimpleName(); 723 } 724 725 @Override 726 public void dump(PrintWriter pw, String[] args) { 727 pw.printf("Current phase: %d\n", mCurrentPhase); 728 synchronized (mTargetUsers) { 729 if (mCurrentUser != null) { 730 pw.print("Current user: "); 731 mCurrentUser.dump(pw); 732 pw.println(); 733 } else { 734 pw.println("Current user not set!"); 735 } 736 737 final int targetUsersSize = mTargetUsers.size(); 738 if (targetUsersSize > 0) { 739 pw.printf("%d target users: ", targetUsersSize); 740 for (int i = 0; i < targetUsersSize; i++) { 741 mTargetUsers.valueAt(i).dump(pw); 742 if (i != targetUsersSize - 1) pw.print(", "); 743 } 744 pw.println(); 745 } else { 746 pw.println("No target users"); 747 } 748 } 749 final int startedLen = mServices.size(); 750 String prefix = " "; 751 if (startedLen > 0) { 752 pw.printf("%d started services:\n", startedLen); 753 for (int i = 0; i < startedLen; i++) { 754 final SystemService service = mServices.get(i); 755 pw.print(prefix); pw.println(service.getClass().getCanonicalName()); 756 } 757 } else { 758 pw.println("No started services"); 759 } 760 } 761 } 762