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.content.Context; 21 import android.os.Environment; 22 import android.os.SystemClock; 23 import android.os.Trace; 24 import android.util.Slog; 25 import android.util.TimingsTraceLog; 26 27 import java.io.File; 28 import java.lang.reflect.Constructor; 29 import java.lang.reflect.InvocationTargetException; 30 import java.util.ArrayList; 31 32 /** 33 * Manages creating, starting, and other lifecycle events of 34 * {@link com.android.server.SystemService system services}. 35 * 36 * {@hide} 37 */ 38 public class SystemServiceManager { 39 private static final String TAG = "SystemServiceManager"; 40 private static final int SERVICE_CALL_WARN_TIME_MS = 50; 41 42 private static File sSystemDir; 43 private final Context mContext; 44 private boolean mSafeMode; 45 private boolean mRuntimeRestarted; 46 private long mRuntimeStartElapsedTime; 47 private long mRuntimeStartUptime; 48 49 // Services that should receive lifecycle events. 50 private final ArrayList<SystemService> mServices = new ArrayList<SystemService>(); 51 52 private int mCurrentPhase = -1; 53 SystemServiceManager(Context context)54 SystemServiceManager(Context context) { 55 mContext = context; 56 } 57 58 /** 59 * Starts a service by class name. 60 * 61 * @return The service instance. 62 */ 63 @SuppressWarnings("unchecked") startService(String className)64 public SystemService startService(String className) { 65 final Class<SystemService> serviceClass; 66 try { 67 serviceClass = (Class<SystemService>)Class.forName(className); 68 } catch (ClassNotFoundException ex) { 69 Slog.i(TAG, "Starting " + className); 70 throw new RuntimeException("Failed to create service " + className 71 + ": service class not found, usually indicates that the caller should " 72 + "have called PackageManager.hasSystemFeature() to check whether the " 73 + "feature is available on this device before trying to start the " 74 + "services that implement it", ex); 75 } 76 return startService(serviceClass); 77 } 78 79 /** 80 * Creates and starts a system service. The class must be a subclass of 81 * {@link com.android.server.SystemService}. 82 * 83 * @param serviceClass A Java class that implements the SystemService interface. 84 * @return The service instance, never null. 85 * @throws RuntimeException if the service fails to start. 86 */ 87 @SuppressWarnings("unchecked") startService(Class<T> serviceClass)88 public <T extends SystemService> T startService(Class<T> serviceClass) { 89 try { 90 final String name = serviceClass.getName(); 91 Slog.i(TAG, "Starting " + name); 92 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name); 93 94 // Create the service. 95 if (!SystemService.class.isAssignableFrom(serviceClass)) { 96 throw new RuntimeException("Failed to create " + name 97 + ": service must extend " + SystemService.class.getName()); 98 } 99 final T service; 100 try { 101 Constructor<T> constructor = serviceClass.getConstructor(Context.class); 102 service = constructor.newInstance(mContext); 103 } catch (InstantiationException ex) { 104 throw new RuntimeException("Failed to create service " + name 105 + ": service could not be instantiated", ex); 106 } catch (IllegalAccessException ex) { 107 throw new RuntimeException("Failed to create service " + name 108 + ": service must have a public constructor with a Context argument", ex); 109 } catch (NoSuchMethodException ex) { 110 throw new RuntimeException("Failed to create service " + name 111 + ": service must have a public constructor with a Context argument", ex); 112 } catch (InvocationTargetException ex) { 113 throw new RuntimeException("Failed to create service " + name 114 + ": service constructor threw an exception", ex); 115 } 116 117 startService(service); 118 return service; 119 } finally { 120 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 121 } 122 } 123 startService(@onNull final SystemService service)124 public void startService(@NonNull final SystemService service) { 125 // Register it. 126 mServices.add(service); 127 // Start it. 128 long time = SystemClock.elapsedRealtime(); 129 try { 130 service.onStart(); 131 } catch (RuntimeException ex) { 132 throw new RuntimeException("Failed to start service " + service.getClass().getName() 133 + ": onStart threw an exception", ex); 134 } 135 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart"); 136 } 137 138 /** 139 * Starts the specified boot phase for all system services that have been started up to 140 * this point. 141 * 142 * @param phase The boot phase to start. 143 */ startBootPhase(final int phase)144 public void startBootPhase(final int phase) { 145 if (phase <= mCurrentPhase) { 146 throw new IllegalArgumentException("Next phase must be larger than previous"); 147 } 148 mCurrentPhase = phase; 149 150 Slog.i(TAG, "Starting phase " + mCurrentPhase); 151 try { 152 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "OnBootPhase " + phase); 153 final int serviceLen = mServices.size(); 154 for (int i = 0; i < serviceLen; i++) { 155 final SystemService service = mServices.get(i); 156 long time = SystemClock.elapsedRealtime(); 157 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, service.getClass().getName()); 158 try { 159 service.onBootPhase(mCurrentPhase); 160 } catch (Exception ex) { 161 throw new RuntimeException("Failed to boot service " 162 + service.getClass().getName() 163 + ": onBootPhase threw an exception during phase " 164 + mCurrentPhase, ex); 165 } 166 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase"); 167 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 168 } 169 } finally { 170 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 171 } 172 } 173 174 /** 175 * @return true if system has completed the boot; false otherwise. 176 */ isBootCompleted()177 public boolean isBootCompleted() { 178 return mCurrentPhase >= SystemService.PHASE_BOOT_COMPLETED; 179 } 180 startUser(final int userHandle)181 public void startUser(final int userHandle) { 182 final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); 183 t.traceBegin("ssm.startUser-" + userHandle); 184 Slog.i(TAG, "Calling onStartUser u" + userHandle); 185 final int serviceLen = mServices.size(); 186 for (int i = 0; i < serviceLen; i++) { 187 final SystemService service = mServices.get(i); 188 t.traceBegin("onStartUser-" + userHandle + " " + service.getClass().getName()); 189 long time = SystemClock.elapsedRealtime(); 190 try { 191 service.onStartUser(userHandle); 192 } catch (Exception ex) { 193 Slog.wtf(TAG, "Failure reporting start of user " + userHandle 194 + " to service " + service.getClass().getName(), ex); 195 } 196 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStartUser "); 197 t.traceEnd(); 198 } 199 t.traceEnd(); 200 } 201 unlockUser(final int userHandle)202 public void unlockUser(final int userHandle) { 203 final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); 204 t.traceBegin("ssm.unlockUser-" + userHandle); 205 Slog.i(TAG, "Calling onUnlockUser u" + userHandle); 206 final int serviceLen = mServices.size(); 207 for (int i = 0; i < serviceLen; i++) { 208 final SystemService service = mServices.get(i); 209 t.traceBegin("onUnlockUser-" + userHandle + " " + service.getClass().getName()); 210 long time = SystemClock.elapsedRealtime(); 211 try { 212 service.onUnlockUser(userHandle); 213 } catch (Exception ex) { 214 Slog.wtf(TAG, "Failure reporting unlock of user " + userHandle 215 + " to service " + service.getClass().getName(), ex); 216 } 217 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onUnlockUser "); 218 t.traceEnd(); 219 } 220 t.traceEnd(); 221 } 222 switchUser(final int userHandle)223 public void switchUser(final int userHandle) { 224 final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); 225 t.traceBegin("ssm.switchUser-" + userHandle); 226 Slog.i(TAG, "Calling switchUser u" + userHandle); 227 final int serviceLen = mServices.size(); 228 for (int i = 0; i < serviceLen; i++) { 229 final SystemService service = mServices.get(i); 230 t.traceBegin("onSwitchUser-" + userHandle + " " + service.getClass().getName()); 231 long time = SystemClock.elapsedRealtime(); 232 try { 233 service.onSwitchUser(userHandle); 234 } catch (Exception ex) { 235 Slog.wtf(TAG, "Failure reporting switch of user " + userHandle 236 + " to service " + service.getClass().getName(), ex); 237 } 238 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onSwitchUser"); 239 t.traceEnd(); 240 } 241 t.traceEnd(); 242 } 243 stopUser(final int userHandle)244 public void stopUser(final int userHandle) { 245 final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); 246 t.traceBegin("ssm.stopUser-" + userHandle); 247 Slog.i(TAG, "Calling onStopUser u" + userHandle); 248 final int serviceLen = mServices.size(); 249 for (int i = 0; i < serviceLen; i++) { 250 final SystemService service = mServices.get(i); 251 t.traceBegin("onStopUser-" + userHandle + " " + service.getClass().getName()); 252 long time = SystemClock.elapsedRealtime(); 253 try { 254 service.onStopUser(userHandle); 255 } catch (Exception ex) { 256 Slog.wtf(TAG, "Failure reporting stop of user " + userHandle 257 + " to service " + service.getClass().getName(), ex); 258 } 259 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStopUser"); 260 t.traceEnd(); 261 } 262 t.traceEnd(); 263 } 264 cleanupUser(final int userHandle)265 public void cleanupUser(final int userHandle) { 266 final TimingsTraceLog t = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER); 267 t.traceBegin("ssm.cleanupUser-" + userHandle); 268 Slog.i(TAG, "Calling onCleanupUser u" + userHandle); 269 final int serviceLen = mServices.size(); 270 for (int i = 0; i < serviceLen; i++) { 271 final SystemService service = mServices.get(i); 272 t.traceBegin("onCleanupUser-" + userHandle + " " + service.getClass().getName()); 273 long time = SystemClock.elapsedRealtime(); 274 try { 275 service.onCleanupUser(userHandle); 276 } catch (Exception ex) { 277 Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle 278 + " to service " + service.getClass().getName(), ex); 279 } 280 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onCleanupUser"); 281 t.traceEnd(); 282 } 283 t.traceEnd(); 284 } 285 286 /** Sets the safe mode flag for services to query. */ setSafeMode(boolean safeMode)287 void setSafeMode(boolean safeMode) { 288 mSafeMode = safeMode; 289 } 290 291 /** 292 * Returns whether we are booting into safe mode. 293 * @return safe mode flag 294 */ isSafeMode()295 public boolean isSafeMode() { 296 return mSafeMode; 297 } 298 299 /** 300 * @return true if runtime was restarted, false if it's normal boot 301 */ isRuntimeRestarted()302 public boolean isRuntimeRestarted() { 303 return mRuntimeRestarted; 304 } 305 306 /** 307 * @return Time when SystemServer was started, in elapsed realtime. 308 */ getRuntimeStartElapsedTime()309 public long getRuntimeStartElapsedTime() { 310 return mRuntimeStartElapsedTime; 311 } 312 313 /** 314 * @return Time when SystemServer was started, in uptime. 315 */ getRuntimeStartUptime()316 public long getRuntimeStartUptime() { 317 return mRuntimeStartUptime; 318 } 319 setStartInfo(boolean runtimeRestarted, long runtimeStartElapsedTime, long runtimeStartUptime)320 void setStartInfo(boolean runtimeRestarted, 321 long runtimeStartElapsedTime, long runtimeStartUptime) { 322 mRuntimeRestarted = runtimeRestarted; 323 mRuntimeStartElapsedTime = runtimeStartElapsedTime; 324 mRuntimeStartUptime = runtimeStartUptime; 325 } 326 warnIfTooLong(long duration, SystemService service, String operation)327 private void warnIfTooLong(long duration, SystemService service, String operation) { 328 if (duration > SERVICE_CALL_WARN_TIME_MS) { 329 Slog.w(TAG, "Service " + service.getClass().getName() + " took " + duration + " ms in " 330 + operation); 331 } 332 } 333 334 /** 335 * Ensures that the system directory exist creating one if needed. 336 * @deprecated Use {@link Environment#getDataSystemCeDirectory()} 337 * or {@link Environment#getDataSystemDeDirectory()} instead. 338 * @return The system directory. 339 */ 340 @Deprecated ensureSystemDir()341 public static File ensureSystemDir() { 342 if (sSystemDir == null) { 343 File dataDir = Environment.getDataDirectory(); 344 sSystemDir = new File(dataDir, "system"); 345 sSystemDir.mkdirs(); 346 } 347 return sSystemDir; 348 } 349 350 /** 351 * Outputs the state of this manager to the System log. 352 */ dump()353 public void dump() { 354 StringBuilder builder = new StringBuilder(); 355 builder.append("Current phase: ").append(mCurrentPhase).append("\n"); 356 builder.append("Services:\n"); 357 final int startedLen = mServices.size(); 358 for (int i = 0; i < startedLen; i++) { 359 final SystemService service = mServices.get(i); 360 builder.append("\t") 361 .append(service.getClass().getSimpleName()) 362 .append("\n"); 363 } 364 365 Slog.e(TAG, builder.toString()); 366 } 367 } 368