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