blob: c5b4966ddcf273419a339a31a96bddd47e95a0c3 [file] [log] [blame]
Adam Lesinski182f73f2013-12-05 16:48:06 -08001/*
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
17package com.android.server;
18
MÃ¥rten Kongstad2e0d0f32016-06-02 09:35:31 +020019import android.annotation.NonNull;
Adam Lesinski182f73f2013-12-05 16:48:06 -080020import android.content.Context;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070021import android.os.Environment;
Wei Wangc3a76d02017-07-14 11:39:30 -070022import android.os.SystemClock;
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +090023import android.os.Trace;
Adam Lesinski182f73f2013-12-05 16:48:06 -080024import android.util.Slog;
25
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070026import java.io.File;
Jeff Brownb880d882014-02-10 19:47:07 -080027import java.lang.reflect.Constructor;
28import java.lang.reflect.InvocationTargetException;
Adam Lesinski182f73f2013-12-05 16:48:06 -080029import java.util.ArrayList;
30
31/**
Adam Lesinskib102b2c2013-12-20 11:46:14 -080032 * Manages creating, starting, and other lifecycle events of
Jeff Brownb880d882014-02-10 19:47:07 -080033 * {@link com.android.server.SystemService system services}.
Adam Lesinskib102b2c2013-12-20 11:46:14 -080034 *
35 * {@hide}
Adam Lesinski182f73f2013-12-05 16:48:06 -080036 */
37public class SystemServiceManager {
38 private static final String TAG = "SystemServiceManager";
Fyodor Kupolov701a85f2017-04-25 12:52:08 -070039 private static final int SERVICE_CALL_WARN_TIME_MS = 50;
Adam Lesinski182f73f2013-12-05 16:48:06 -080040
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070041 private static File sSystemDir;
Adam Lesinski182f73f2013-12-05 16:48:06 -080042 private final Context mContext;
Amith Yamasani91588252013-11-22 08:25:26 -080043 private boolean mSafeMode;
Fyodor Kupolov1d87e402017-01-10 18:34:10 -080044 private boolean mRuntimeRestarted;
Makoto Onukie8edbcf2018-03-02 16:49:29 -080045 private long mRuntimeStartElapsedTime;
46 private long mRuntimeStartUptime;
Adam Lesinski182f73f2013-12-05 16:48:06 -080047
48 // Services that should receive lifecycle events.
49 private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
50
51 private int mCurrentPhase = -1;
52
Fyodor Kupolov1d87e402017-01-10 18:34:10 -080053 SystemServiceManager(Context context) {
Adam Lesinski182f73f2013-12-05 16:48:06 -080054 mContext = context;
55 }
56
Jeff Brown6f357d32014-01-15 20:40:55 -080057 /**
Adam Lesinski2cb6c602014-02-14 17:19:56 -080058 * Starts a service by class name.
Jeff Brown6f357d32014-01-15 20:40:55 -080059 *
Adam Lesinski2cb6c602014-02-14 17:19:56 -080060 * @return The service instance.
Jeff Brown6f357d32014-01-15 20:40:55 -080061 */
62 @SuppressWarnings("unchecked")
Jeff Brown2c43c332014-06-12 22:38:59 -070063 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);
Amith Yamasani91588252013-11-22 08:25:26 -080076 }
77
Adam Lesinski182f73f2013-12-05 16:48:06 -080078 /**
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.
Jeff Brown6f357d32014-01-15 20:40:55 -080083 * @return The service instance, never null.
Adam Lesinski182f73f2013-12-05 16:48:06 -080084 * @throws RuntimeException if the service fails to start.
85 */
Jeff Brown6f357d32014-01-15 20:40:55 -080086 @SuppressWarnings("unchecked")
87 public <T extends SystemService> T startService(Class<T> serviceClass) {
Adam Lesinski182f73f2013-12-05 16:48:06 -080088 try {
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +090089 final String name = serviceClass.getName();
90 Slog.i(TAG, "Starting " + name);
91 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
Adam Lesinski182f73f2013-12-05 16:48:06 -080092
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +090093 // 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 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800115
MÃ¥rten Kongstad2e0d0f32016-06-02 09:35:31 +0200116 startService(service);
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900117 return service;
118 } finally {
119 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800120 }
121 }
122
MÃ¥rten Kongstad2e0d0f32016-06-02 09:35:31 +0200123 public void startService(@NonNull final SystemService service) {
124 // Register it.
125 mServices.add(service);
126 // Start it.
Wei Wangc3a76d02017-07-14 11:39:30 -0700127 long time = SystemClock.elapsedRealtime();
MÃ¥rten Kongstad2e0d0f32016-06-02 09:35:31 +0200128 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 }
Wei Wangc3a76d02017-07-14 11:39:30 -0700134 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
MÃ¥rten Kongstad2e0d0f32016-06-02 09:35:31 +0200135 }
136
Adam Lesinski182f73f2013-12-05 16:48:06 -0800137 /**
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 */
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);
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900150 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);
Wei Wangc3a76d02017-07-14 11:39:30 -0700155 long time = SystemClock.elapsedRealtime();
Philip Cuadra4345c0d2016-08-17 18:02:24 -0700156 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, service.getClass().getName());
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900157 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 }
Wei Wangc3a76d02017-07-14 11:39:30 -0700165 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
Philip Cuadra4345c0d2016-08-17 18:02:24 -0700166 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800167 }
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900168 } finally {
169 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800170 }
171 }
172
Keun-young Park4136d2d2017-05-08 14:51:59 -0700173 /**
174 * @return true if system has completed the boot; false otherwise.
175 */
176 public boolean isBootCompleted() {
177 return mCurrentPhase >= SystemService.PHASE_BOOT_COMPLETED;
178 }
179
Dianne Hackborn91097de2014-04-04 18:02:06 -0700180 public void startUser(final int userHandle) {
Fyodor Kupolov701a85f2017-04-25 12:52:08 -0700181 Slog.i(TAG, "Calling onStartUser u" + userHandle);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700182 final int serviceLen = mServices.size();
183 for (int i = 0; i < serviceLen; i++) {
184 final SystemService service = mServices.get(i);
Philip Cuadraca3329c2016-06-24 12:02:06 -0700185 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStartUser "
186 + service.getClass().getName());
Wei Wangc3a76d02017-07-14 11:39:30 -0700187 long time = SystemClock.elapsedRealtime();
Dianne Hackborn91097de2014-04-04 18:02:06 -0700188 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 }
Wei Wangc3a76d02017-07-14 11:39:30 -0700194 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStartUser ");
Philip Cuadraca3329c2016-06-24 12:02:06 -0700195 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700196 }
197 }
198
Jeff Sharkeybedbaa92015-12-02 16:42:25 -0700199 public void unlockUser(final int userHandle) {
Fyodor Kupolov701a85f2017-04-25 12:52:08 -0700200 Slog.i(TAG, "Calling onUnlockUser u" + userHandle);
Jeff Sharkeybedbaa92015-12-02 16:42:25 -0700201 final int serviceLen = mServices.size();
202 for (int i = 0; i < serviceLen; i++) {
203 final SystemService service = mServices.get(i);
Philip Cuadraca3329c2016-06-24 12:02:06 -0700204 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onUnlockUser "
205 + service.getClass().getName());
Wei Wangc3a76d02017-07-14 11:39:30 -0700206 long time = SystemClock.elapsedRealtime();
Jeff Sharkeybedbaa92015-12-02 16:42:25 -0700207 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 }
Wei Wangc3a76d02017-07-14 11:39:30 -0700213 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onUnlockUser ");
Philip Cuadraca3329c2016-06-24 12:02:06 -0700214 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Jeff Sharkeybedbaa92015-12-02 16:42:25 -0700215 }
216 }
217
Dianne Hackborn91097de2014-04-04 18:02:06 -0700218 public void switchUser(final int userHandle) {
Fyodor Kupolov701a85f2017-04-25 12:52:08 -0700219 Slog.i(TAG, "Calling switchUser u" + userHandle);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700220 final int serviceLen = mServices.size();
221 for (int i = 0; i < serviceLen; i++) {
222 final SystemService service = mServices.get(i);
Philip Cuadraca3329c2016-06-24 12:02:06 -0700223 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onSwitchUser "
224 + service.getClass().getName());
Wei Wangc3a76d02017-07-14 11:39:30 -0700225 long time = SystemClock.elapsedRealtime();
Dianne Hackborn91097de2014-04-04 18:02:06 -0700226 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 }
Wei Wangc3a76d02017-07-14 11:39:30 -0700232 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onSwitchUser");
Philip Cuadraca3329c2016-06-24 12:02:06 -0700233 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700234 }
235 }
236
237 public void stopUser(final int userHandle) {
Fyodor Kupolov701a85f2017-04-25 12:52:08 -0700238 Slog.i(TAG, "Calling onStopUser u" + userHandle);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700239 final int serviceLen = mServices.size();
240 for (int i = 0; i < serviceLen; i++) {
241 final SystemService service = mServices.get(i);
Philip Cuadraca3329c2016-06-24 12:02:06 -0700242 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onStopUser "
243 + service.getClass().getName());
Wei Wangc3a76d02017-07-14 11:39:30 -0700244 long time = SystemClock.elapsedRealtime();
Dianne Hackborn91097de2014-04-04 18:02:06 -0700245 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 }
Wei Wangc3a76d02017-07-14 11:39:30 -0700251 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStopUser");
Philip Cuadraca3329c2016-06-24 12:02:06 -0700252 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700253 }
254 }
255
256 public void cleanupUser(final int userHandle) {
Fyodor Kupolov701a85f2017-04-25 12:52:08 -0700257 Slog.i(TAG, "Calling onCleanupUser u" + userHandle);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700258 final int serviceLen = mServices.size();
259 for (int i = 0; i < serviceLen; i++) {
260 final SystemService service = mServices.get(i);
Philip Cuadraca3329c2016-06-24 12:02:06 -0700261 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "onCleanupUser "
262 + service.getClass().getName());
Wei Wangc3a76d02017-07-14 11:39:30 -0700263 long time = SystemClock.elapsedRealtime();
Dianne Hackborn91097de2014-04-04 18:02:06 -0700264 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 }
Wei Wangc3a76d02017-07-14 11:39:30 -0700270 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onCleanupUser");
Philip Cuadraca3329c2016-06-24 12:02:06 -0700271 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700272 }
273 }
274
Amith Yamasani91588252013-11-22 08:25:26 -0800275 /** Sets the safe mode flag for services to query. */
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800276 void setSafeMode(boolean safeMode) {
Amith Yamasani91588252013-11-22 08:25:26 -0800277 mSafeMode = safeMode;
278 }
279
280 /**
281 * Returns whether we are booting into safe mode.
282 * @return safe mode flag
283 */
284 public boolean isSafeMode() {
285 return mSafeMode;
286 }
287
Adam Lesinski182f73f2013-12-05 16:48:06 -0800288 /**
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800289 * @return true if runtime was restarted, false if it's normal boot
290 */
291 public boolean isRuntimeRestarted() {
292 return mRuntimeRestarted;
293 }
294
Makoto Onukie8edbcf2018-03-02 16:49:29 -0800295 /**
296 * @return Time when SystemServer was started, in elapsed realtime.
297 */
298 public long getRuntimeStartElapsedTime() {
299 return mRuntimeStartElapsedTime;
300 }
301
302 /**
303 * @return Time when SystemServer was started, in uptime.
304 */
305 public long getRuntimeStartUptime() {
306 return mRuntimeStartUptime;
307 }
308
309 void setStartInfo(boolean runtimeRestarted,
310 long runtimeStartElapsedTime, long runtimeStartUptime) {
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800311 mRuntimeRestarted = runtimeRestarted;
Makoto Onukie8edbcf2018-03-02 16:49:29 -0800312 mRuntimeStartElapsedTime = runtimeStartElapsedTime;
313 mRuntimeStartUptime = runtimeStartUptime;
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800314 }
315
Fyodor Kupolov701a85f2017-04-25 12:52:08 -0700316 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 }
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800322
323 /**
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700324 * 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
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 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -0800340 * Outputs the state of this manager to the System log.
341 */
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 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800356}