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