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