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 try { 160 service.onStartUser(userHandle); 161 } catch (Exception ex) { 162 Slog.wtf(TAG, "Failure reporting start of user " + userHandle 163 + " to service " + service.getClass().getName(), ex); 164 } 165 } 166 } 167 168 public void unlockUser(final int userHandle) { 169 final int serviceLen = mServices.size(); 170 for (int i = 0; i < serviceLen; i++) { 171 final SystemService service = mServices.get(i); 172 try { 173 service.onUnlockUser(userHandle); 174 } catch (Exception ex) { 175 Slog.wtf(TAG, "Failure reporting unlock of user " + userHandle 176 + " to service " + service.getClass().getName(), ex); 177 } 178 } 179 } 180 181 public void switchUser(final int userHandle) { 182 final int serviceLen = mServices.size(); 183 for (int i = 0; i < serviceLen; i++) { 184 final SystemService service = mServices.get(i); 185 try { 186 service.onSwitchUser(userHandle); 187 } catch (Exception ex) { 188 Slog.wtf(TAG, "Failure reporting switch of user " + userHandle 189 + " to service " + service.getClass().getName(), ex); 190 } 191 } 192 } 193 194 public void stopUser(final int userHandle) { 195 final int serviceLen = mServices.size(); 196 for (int i = 0; i < serviceLen; i++) { 197 final SystemService service = mServices.get(i); 198 try { 199 service.onStopUser(userHandle); 200 } catch (Exception ex) { 201 Slog.wtf(TAG, "Failure reporting stop of user " + userHandle 202 + " to service " + service.getClass().getName(), ex); 203 } 204 } 205 } 206 207 public void cleanupUser(final int userHandle) { 208 final int serviceLen = mServices.size(); 209 for (int i = 0; i < serviceLen; i++) { 210 final SystemService service = mServices.get(i); 211 try { 212 service.onCleanupUser(userHandle); 213 } catch (Exception ex) { 214 Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle 215 + " to service " + service.getClass().getName(), ex); 216 } 217 } 218 } 219 220 /** Sets the safe mode flag for services to query. */ 221 public void setSafeMode(boolean safeMode) { 222 mSafeMode = safeMode; 223 } 224 225 /** 226 * Returns whether we are booting into safe mode. 227 * @return safe mode flag 228 */ 229 public boolean isSafeMode() { 230 return mSafeMode; 231 } 232 233 /** 234 * Outputs the state of this manager to the System log. 235 */ 236 public void dump() { 237 StringBuilder builder = new StringBuilder(); 238 builder.append("Current phase: ").append(mCurrentPhase).append("\n"); 239 builder.append("Services:\n"); 240 final int startedLen = mServices.size(); 241 for (int i = 0; i < startedLen; i++) { 242 final SystemService service = mServices.get(i); 243 builder.append("\t") 244 .append(service.getClass().getSimpleName()) 245 .append("\n"); 246 } 247 248 Slog.e(TAG, builder.toString()); 249 } 250 } 251