• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SystemServiceManager(Context context)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")
startService(String className)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")
startService(Class<T> serviceClass)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      */
startBootPhase(final int phase)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 
startUser(final int userHandle)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 
unlockUser(final int userHandle)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 
switchUser(final int userHandle)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 
stopUser(final int userHandle)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 
cleanupUser(final int userHandle)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. */
setSafeMode(boolean safeMode)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      */
isSafeMode()244     public boolean isSafeMode() {
245         return mSafeMode;
246     }
247 
248     /**
249      * Outputs the state of this manager to the System log.
250      */
dump()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