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