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