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