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.content.Context; 23 import android.content.pm.UserInfo; 24 import android.os.Build; 25 import android.os.Environment; 26 import android.os.SystemClock; 27 import android.os.Trace; 28 import android.util.ArrayMap; 29 import android.util.EventLog; 30 import android.util.IndentingPrintWriter; 31 import android.util.Slog; 32 import android.util.SparseArray; 33 34 import com.android.internal.annotations.GuardedBy; 35 import com.android.internal.os.ClassLoaderFactory; 36 import com.android.internal.util.Preconditions; 37 import com.android.server.SystemService.TargetUser; 38 import com.android.server.am.EventLogTags; 39 import com.android.server.pm.UserManagerInternal; 40 import com.android.server.utils.TimingsTraceAndSlog; 41 42 import dalvik.system.PathClassLoader; 43 44 import java.io.File; 45 import java.lang.reflect.Constructor; 46 import java.lang.reflect.InvocationTargetException; 47 import java.util.ArrayList; 48 49 /** 50 * Manages creating, starting, and other lifecycle events of 51 * {@link com.android.server.SystemService system services}. 52 * 53 * {@hide} 54 */ 55 public final class SystemServiceManager implements Dumpable { 56 private static final String TAG = SystemServiceManager.class.getSimpleName(); 57 private static final boolean DEBUG = false; 58 private static final int SERVICE_CALL_WARN_TIME_MS = 50; 59 60 // Constants used on onUser(...) 61 // NOTE: do not change their values, as they're used on Trace calls and changes might break 62 // performance tests that rely on them. 63 private static final String USER_STARTING = "Start"; // Logged as onStartUser 64 private static final String USER_UNLOCKING = "Unlocking"; // Logged as onUnlockingUser 65 private static final String USER_UNLOCKED = "Unlocked"; // Logged as onUnlockedUser 66 private static final String USER_SWITCHING = "Switch"; // Logged as onSwitchUser 67 private static final String USER_STOPPING = "Stop"; // Logged as onStopUser 68 private static final String USER_STOPPED = "Cleanup"; // Logged as onCleanupUser 69 70 private static File sSystemDir; 71 private final Context mContext; 72 private boolean mSafeMode; 73 private boolean mRuntimeRestarted; 74 private long mRuntimeStartElapsedTime; 75 private long mRuntimeStartUptime; 76 77 // Services that should receive lifecycle events. 78 private final ArrayList<SystemService> mServices = new ArrayList<SystemService>(); 79 80 // Map of paths to PathClassLoader, so we don't load the same path multiple times. 81 private final ArrayMap<String, PathClassLoader> mLoadedPaths = new ArrayMap<>(); 82 83 private int mCurrentPhase = -1; 84 85 private UserManagerInternal mUserManagerInternal; 86 87 /** 88 * Map of started {@link TargetUser TargetUsers} by user id; users are added on start and 89 * removed after they're completely shut down. 90 */ 91 @GuardedBy("mTargetUsers") 92 private final SparseArray<TargetUser> mTargetUsers = new SparseArray<>(); 93 94 /** 95 * Reference to the current user, it's used to set the {@link TargetUser} on 96 * {@link #onUserSwitching(int, int)} as the previous user might have been removed already. 97 */ 98 @GuardedBy("mTargetUsers") 99 private @Nullable TargetUser mCurrentUser; 100 SystemServiceManager(Context context)101 SystemServiceManager(Context context) { 102 mContext = context; 103 } 104 105 /** 106 * Starts a service by class name. 107 * 108 * @return The service instance. 109 */ startService(String className)110 public SystemService startService(String className) { 111 final Class<SystemService> serviceClass = loadClassFromLoader(className, 112 this.getClass().getClassLoader()); 113 return startService(serviceClass); 114 } 115 116 /** 117 * Starts a service by class name and a path that specifies the jar where the service lives. 118 * 119 * @return The service instance. 120 */ startServiceFromJar(String className, String path)121 public SystemService startServiceFromJar(String className, String path) { 122 PathClassLoader pathClassLoader = mLoadedPaths.get(path); 123 if (pathClassLoader == null) { 124 // NB: the parent class loader should always be the system server class loader. 125 // Changing it has implications that require discussion with the mainline team. 126 pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader( 127 path, null /* librarySearchPath */, null /* libraryPermittedPath */, 128 this.getClass().getClassLoader(), Build.VERSION.SDK_INT, 129 true /* isNamespaceShared */, null /* classLoaderName */); 130 mLoadedPaths.put(path, pathClassLoader); 131 } 132 final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader); 133 return startService(serviceClass); 134 } 135 136 /* 137 * Loads and initializes a class from the given classLoader. Returns the class. 138 */ 139 @SuppressWarnings("unchecked") loadClassFromLoader(String className, ClassLoader classLoader)140 private static Class<SystemService> loadClassFromLoader(String className, 141 ClassLoader classLoader) { 142 try { 143 return (Class<SystemService>) Class.forName(className, true, classLoader); 144 } catch (ClassNotFoundException ex) { 145 throw new RuntimeException("Failed to create service " + className 146 + " from class loader " + classLoader.toString() + ": service class not " 147 + "found, usually indicates that the caller should " 148 + "have called PackageManager.hasSystemFeature() to check whether the " 149 + "feature is available on this device before trying to start the " 150 + "services that implement it. Also ensure that the correct path for the " 151 + "classloader is supplied, if applicable.", ex); 152 } 153 } 154 155 /** 156 * Creates and starts a system service. The class must be a subclass of 157 * {@link com.android.server.SystemService}. 158 * 159 * @param serviceClass A Java class that implements the SystemService interface. 160 * @return The service instance, never null. 161 * @throws RuntimeException if the service fails to start. 162 */ startService(Class<T> serviceClass)163 public <T extends SystemService> T startService(Class<T> serviceClass) { 164 try { 165 final String name = serviceClass.getName(); 166 Slog.i(TAG, "Starting " + name); 167 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name); 168 169 // Create the service. 170 if (!SystemService.class.isAssignableFrom(serviceClass)) { 171 throw new RuntimeException("Failed to create " + name 172 + ": service must extend " + SystemService.class.getName()); 173 } 174 final T service; 175 try { 176 Constructor<T> constructor = serviceClass.getConstructor(Context.class); 177 service = constructor.newInstance(mContext); 178 } catch (InstantiationException ex) { 179 throw new RuntimeException("Failed to create service " + name 180 + ": service could not be instantiated", ex); 181 } catch (IllegalAccessException ex) { 182 throw new RuntimeException("Failed to create service " + name 183 + ": service must have a public constructor with a Context argument", ex); 184 } catch (NoSuchMethodException ex) { 185 throw new RuntimeException("Failed to create service " + name 186 + ": service must have a public constructor with a Context argument", ex); 187 } catch (InvocationTargetException ex) { 188 throw new RuntimeException("Failed to create service " + name 189 + ": service constructor threw an exception", ex); 190 } 191 192 startService(service); 193 return service; 194 } finally { 195 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 196 } 197 } 198 startService(@onNull final SystemService service)199 public void startService(@NonNull final SystemService service) { 200 // Register it. 201 mServices.add(service); 202 // Start it. 203 long time = SystemClock.elapsedRealtime(); 204 try { 205 service.onStart(); 206 } catch (RuntimeException ex) { 207 throw new RuntimeException("Failed to start service " + service.getClass().getName() 208 + ": onStart threw an exception", ex); 209 } 210 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart"); 211 } 212 213 /** 214 * Starts the specified boot phase for all system services that have been started up to 215 * this point. 216 * 217 * @param t trace logger 218 * @param phase The boot phase to start. 219 */ startBootPhase(@onNull TimingsTraceAndSlog t, int phase)220 public void startBootPhase(@NonNull TimingsTraceAndSlog t, int phase) { 221 if (phase <= mCurrentPhase) { 222 throw new IllegalArgumentException("Next phase must be larger than previous"); 223 } 224 mCurrentPhase = phase; 225 226 Slog.i(TAG, "Starting phase " + mCurrentPhase); 227 try { 228 t.traceBegin("OnBootPhase_" + phase); 229 final int serviceLen = mServices.size(); 230 for (int i = 0; i < serviceLen; i++) { 231 final SystemService service = mServices.get(i); 232 long time = SystemClock.elapsedRealtime(); 233 t.traceBegin("OnBootPhase_" + phase + "_" + service.getClass().getName()); 234 try { 235 service.onBootPhase(mCurrentPhase); 236 } catch (Exception ex) { 237 throw new RuntimeException("Failed to boot service " 238 + service.getClass().getName() 239 + ": onBootPhase threw an exception during phase " 240 + mCurrentPhase, ex); 241 } 242 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase"); 243 t.traceEnd(); 244 } 245 } finally { 246 t.traceEnd(); 247 } 248 249 if (phase == SystemService.PHASE_BOOT_COMPLETED) { 250 final long totalBootTime = SystemClock.uptimeMillis() - mRuntimeStartUptime; 251 t.logDuration("TotalBootTime", totalBootTime); 252 SystemServerInitThreadPool.shutdown(); 253 } 254 } 255 256 /** 257 * @return true if system has completed the boot; false otherwise. 258 */ isBootCompleted()259 public boolean isBootCompleted() { 260 return mCurrentPhase >= SystemService.PHASE_BOOT_COMPLETED; 261 } 262 263 /** 264 * Called at the beginning of {@code ActivityManagerService.systemReady()}. 265 */ preSystemReady()266 public void preSystemReady() { 267 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); 268 } 269 getTargetUser(@serIdInt int userId)270 private @NonNull TargetUser getTargetUser(@UserIdInt int userId) { 271 final TargetUser targetUser; 272 synchronized (mTargetUsers) { 273 targetUser = mTargetUsers.get(userId); 274 } 275 Preconditions.checkState(targetUser != null, "No TargetUser for " + userId); 276 return targetUser; 277 } 278 newTargetUser(@serIdInt int userId)279 private @NonNull TargetUser newTargetUser(@UserIdInt int userId) { 280 final UserInfo userInfo = mUserManagerInternal.getUserInfo(userId); 281 Preconditions.checkState(userInfo != null, "No UserInfo for " + userId); 282 return new TargetUser(userInfo); 283 } 284 285 /** 286 * Starts the given user. 287 */ onUserStarting(@onNull TimingsTraceAndSlog t, @UserIdInt int userId)288 public void onUserStarting(@NonNull TimingsTraceAndSlog t, @UserIdInt int userId) { 289 EventLog.writeEvent(EventLogTags.SSM_USER_STARTING, userId); 290 291 final TargetUser targetUser = newTargetUser(userId); 292 synchronized (mTargetUsers) { 293 mTargetUsers.put(userId, targetUser); 294 } 295 296 onUser(t, USER_STARTING, /* prevUser= */ null, targetUser); 297 } 298 299 /** 300 * Unlocks the given user. 301 */ onUserUnlocking(@serIdInt int userId)302 public void onUserUnlocking(@UserIdInt int userId) { 303 EventLog.writeEvent(EventLogTags.SSM_USER_UNLOCKING, userId); 304 onUser(USER_UNLOCKING, userId); 305 } 306 307 /** 308 * Called after the user was unlocked. 309 */ onUserUnlocked(@serIdInt int userId)310 public void onUserUnlocked(@UserIdInt int userId) { 311 EventLog.writeEvent(EventLogTags.SSM_USER_UNLOCKED, userId); 312 onUser(USER_UNLOCKED, userId); 313 } 314 315 /** 316 * Switches to the given user. 317 */ onUserSwitching(@serIdInt int from, @UserIdInt int to)318 public void onUserSwitching(@UserIdInt int from, @UserIdInt int to) { 319 EventLog.writeEvent(EventLogTags.SSM_USER_SWITCHING, from, to); 320 final TargetUser curUser, prevUser; 321 synchronized (mTargetUsers) { 322 if (mCurrentUser == null) { 323 if (DEBUG) { 324 Slog.d(TAG, "First user switch: from " + from + " to " + to); 325 } 326 prevUser = newTargetUser(from); 327 } else { 328 if (from != mCurrentUser.getUserIdentifier()) { 329 Slog.wtf(TAG, "switchUser(" + from + "," + to + "): mCurrentUser is " 330 + mCurrentUser + ", it should be " + from); 331 } 332 prevUser = mCurrentUser; 333 } 334 curUser = mCurrentUser = getTargetUser(to); 335 if (DEBUG) { 336 Slog.d(TAG, "Set mCurrentUser to " + mCurrentUser); 337 } 338 } 339 onUser(TimingsTraceAndSlog.newAsyncLog(), USER_SWITCHING, prevUser, curUser); 340 } 341 342 /** 343 * Stops the given user. 344 */ onUserStopping(@serIdInt int userId)345 public void onUserStopping(@UserIdInt int userId) { 346 EventLog.writeEvent(EventLogTags.SSM_USER_STOPPING, userId); 347 onUser(USER_STOPPING, userId); 348 } 349 350 /** 351 * Cleans up the given user. 352 */ onUserStopped(@serIdInt int userId)353 public void onUserStopped(@UserIdInt int userId) { 354 EventLog.writeEvent(EventLogTags.SSM_USER_STOPPED, userId); 355 onUser(USER_STOPPED, userId); 356 357 // Remove cached TargetUser 358 synchronized (mTargetUsers) { 359 mTargetUsers.remove(userId); 360 } 361 } 362 onUser(@onNull String onWhat, @UserIdInt int userId)363 private void onUser(@NonNull String onWhat, @UserIdInt int userId) { 364 onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, /* prevUser= */ null, 365 getTargetUser(userId)); 366 } 367 onUser(@onNull TimingsTraceAndSlog t, @NonNull String onWhat, @Nullable TargetUser prevUser, @NonNull TargetUser curUser)368 private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat, 369 @Nullable TargetUser prevUser, @NonNull TargetUser curUser) { 370 final int curUserId = curUser.getUserIdentifier(); 371 // NOTE: do not change label below, or it might break performance tests that rely on it. 372 t.traceBegin("ssm." + onWhat + "User-" + curUserId); 373 Slog.i(TAG, "Calling on" + onWhat + "User " + curUserId 374 + (prevUser != null ? " (from " + prevUser + ")" : "")); 375 final int serviceLen = mServices.size(); 376 for (int i = 0; i < serviceLen; i++) { 377 final SystemService service = mServices.get(i); 378 final String serviceName = service.getClass().getName(); 379 boolean supported = service.isUserSupported(curUser); 380 381 // Must check if either curUser or prevUser is supported (for example, if switching from 382 // unsupported to supported, we still need to notify the services) 383 if (!supported && prevUser != null) { 384 supported = service.isUserSupported(prevUser); 385 } 386 387 if (!supported) { 388 if (DEBUG) { 389 Slog.d(TAG, "Skipping " + onWhat + "User-" + curUserId + " on service " 390 + serviceName + " because it's not supported (curUser: " 391 + curUser + ", prevUser:" + prevUser + ")"); 392 } else { 393 Slog.i(TAG, "Skipping " + onWhat + "User-" + curUserId + " on " 394 + serviceName); 395 } 396 continue; 397 } 398 t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + "_" + serviceName); 399 long time = SystemClock.elapsedRealtime(); 400 try { 401 switch (onWhat) { 402 case USER_SWITCHING: 403 service.onUserSwitching(prevUser, curUser); 404 break; 405 case USER_STARTING: 406 service.onUserStarting(curUser); 407 break; 408 case USER_UNLOCKING: 409 service.onUserUnlocking(curUser); 410 break; 411 case USER_UNLOCKED: 412 service.onUserUnlocked(curUser); 413 break; 414 case USER_STOPPING: 415 service.onUserStopping(curUser); 416 break; 417 case USER_STOPPED: 418 service.onUserStopped(curUser); 419 break; 420 default: 421 throw new IllegalArgumentException(onWhat + " what?"); 422 } 423 } catch (Exception ex) { 424 Slog.wtf(TAG, "Failure reporting " + onWhat + " of user " + curUser 425 + " to service " + serviceName, ex); 426 } 427 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, 428 "on" + onWhat + "User-" + curUserId); 429 t.traceEnd(); // what on service 430 } 431 t.traceEnd(); // main entry 432 } 433 434 /** Sets the safe mode flag for services to query. */ setSafeMode(boolean safeMode)435 void setSafeMode(boolean safeMode) { 436 mSafeMode = safeMode; 437 } 438 439 /** 440 * Returns whether we are booting into safe mode. 441 * @return safe mode flag 442 */ isSafeMode()443 public boolean isSafeMode() { 444 return mSafeMode; 445 } 446 447 /** 448 * @return true if runtime was restarted, false if it's normal boot 449 */ isRuntimeRestarted()450 public boolean isRuntimeRestarted() { 451 return mRuntimeRestarted; 452 } 453 454 /** 455 * @return Time when SystemServer was started, in elapsed realtime. 456 */ getRuntimeStartElapsedTime()457 public long getRuntimeStartElapsedTime() { 458 return mRuntimeStartElapsedTime; 459 } 460 461 /** 462 * @return Time when SystemServer was started, in uptime. 463 */ getRuntimeStartUptime()464 public long getRuntimeStartUptime() { 465 return mRuntimeStartUptime; 466 } 467 setStartInfo(boolean runtimeRestarted, long runtimeStartElapsedTime, long runtimeStartUptime)468 void setStartInfo(boolean runtimeRestarted, 469 long runtimeStartElapsedTime, long runtimeStartUptime) { 470 mRuntimeRestarted = runtimeRestarted; 471 mRuntimeStartElapsedTime = runtimeStartElapsedTime; 472 mRuntimeStartUptime = runtimeStartUptime; 473 } 474 warnIfTooLong(long duration, SystemService service, String operation)475 private void warnIfTooLong(long duration, SystemService service, String operation) { 476 if (duration > SERVICE_CALL_WARN_TIME_MS) { 477 Slog.w(TAG, "Service " + service.getClass().getName() + " took " + duration + " ms in " 478 + operation); 479 } 480 } 481 482 /** 483 * Ensures that the system directory exist creating one if needed. 484 * @deprecated Use {@link Environment#getDataSystemCeDirectory()} 485 * or {@link Environment#getDataSystemDeDirectory()} instead. 486 * @return The system directory. 487 */ 488 @Deprecated ensureSystemDir()489 public static File ensureSystemDir() { 490 if (sSystemDir == null) { 491 File dataDir = Environment.getDataDirectory(); 492 sSystemDir = new File(dataDir, "system"); 493 sSystemDir.mkdirs(); 494 } 495 return sSystemDir; 496 } 497 498 @Override dump(IndentingPrintWriter pw, String[] args)499 public void dump(IndentingPrintWriter pw, String[] args) { 500 pw.printf("Current phase: %d\n", mCurrentPhase); 501 synchronized (mTargetUsers) { 502 if (mCurrentUser != null) { 503 pw.print("Current user: "); mCurrentUser.dump(pw); pw.println(); 504 } else { 505 pw.println("Current user not set!"); 506 } 507 508 final int targetUsersSize = mTargetUsers.size(); 509 if (targetUsersSize > 0) { 510 pw.printf("%d target users: ", targetUsersSize); 511 for (int i = 0; i < targetUsersSize; i++) { 512 mTargetUsers.valueAt(i).dump(pw); 513 if (i != targetUsersSize - 1) pw.print(", "); 514 } 515 pw.println(); 516 } else { 517 pw.println("No target users"); 518 } 519 } 520 final int startedLen = mServices.size(); 521 if (startedLen > 0) { 522 pw.printf("%d started services:\n", startedLen); 523 pw.increaseIndent(); 524 for (int i = 0; i < startedLen; i++) { 525 final SystemService service = mServices.get(i); 526 pw.println(service.getClass().getCanonicalName()); 527 } 528 pw.decreaseIndent(); 529 } else { 530 pw.println("No started services"); 531 } 532 } 533 } 534