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