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