blob: d2e12b52ba35740599e75378c26434eeaeb100ba [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;
Felipe Leme137e7812019-06-10 11:38:05 -070020import android.annotation.UserIdInt;
Adam Lesinski182f73f2013-12-05 16:48:06 -080021import android.content.Context;
Felipe Lemee5434c32019-08-13 09:28:33 -070022import android.content.pm.UserInfo;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070023import android.os.Environment;
Wei Wangc3a76d02017-07-14 11:39:30 -070024import android.os.SystemClock;
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +090025import android.os.Trace;
Felipe Leme501a5142019-08-15 16:23:47 -070026import android.os.UserHandle;
Felipe Lemee5434c32019-08-13 09:28:33 -070027import android.os.UserManagerInternal;
Tej Singhb2d68842020-01-08 15:03:38 -080028import android.util.ArrayMap;
Adam Lesinski182f73f2013-12-05 16:48:06 -080029import android.util.Slog;
30
Makoto Onukic8815902020-01-08 13:55:25 -080031import com.android.server.SystemService.TargetUser;
Felipe Leme137e7812019-06-10 11:38:05 -070032import com.android.server.utils.TimingsTraceAndSlog;
33
Tej Singhb2d68842020-01-08 15:03:38 -080034import dalvik.system.PathClassLoader;
35
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070036import java.io.File;
Jeff Brownb880d882014-02-10 19:47:07 -080037import java.lang.reflect.Constructor;
38import java.lang.reflect.InvocationTargetException;
Adam Lesinski182f73f2013-12-05 16:48:06 -080039import java.util.ArrayList;
40
41/**
Adam Lesinskib102b2c2013-12-20 11:46:14 -080042 * Manages creating, starting, and other lifecycle events of
Jeff Brownb880d882014-02-10 19:47:07 -080043 * {@link com.android.server.SystemService system services}.
Adam Lesinskib102b2c2013-12-20 11:46:14 -080044 *
45 * {@hide}
Adam Lesinski182f73f2013-12-05 16:48:06 -080046 */
47public class SystemServiceManager {
48 private static final String TAG = "SystemServiceManager";
Felipe Leme501a5142019-08-15 16:23:47 -070049 private static final boolean DEBUG = false;
Fyodor Kupolov701a85f2017-04-25 12:52:08 -070050 private static final int SERVICE_CALL_WARN_TIME_MS = 50;
Adam Lesinski182f73f2013-12-05 16:48:06 -080051
Felipe Leme501a5142019-08-15 16:23:47 -070052 // Constants used on onUser(...)
53 private static final String START = "Start";
Felipe Leme339b7142020-02-21 11:05:49 -080054 private static final String UNLOCKING = "Unlocking";
55 private static final String UNLOCKED = "Unlocked";
Felipe Leme501a5142019-08-15 16:23:47 -070056 private static final String SWITCH = "Switch";
57 private static final String STOP = "Stop";
58 private static final String CLEANUP = "Cleanup";
59
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -070060 private static File sSystemDir;
Adam Lesinski182f73f2013-12-05 16:48:06 -080061 private final Context mContext;
Amith Yamasani91588252013-11-22 08:25:26 -080062 private boolean mSafeMode;
Fyodor Kupolov1d87e402017-01-10 18:34:10 -080063 private boolean mRuntimeRestarted;
Makoto Onukie8edbcf2018-03-02 16:49:29 -080064 private long mRuntimeStartElapsedTime;
65 private long mRuntimeStartUptime;
Adam Lesinski182f73f2013-12-05 16:48:06 -080066
67 // Services that should receive lifecycle events.
68 private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
69
Tej Singhb2d68842020-01-08 15:03:38 -080070 // Map of paths to PathClassLoader, so we don't load the same path multiple times.
71 private final ArrayMap<String, PathClassLoader> mLoadedPaths = new ArrayMap<>();
72
Adam Lesinski182f73f2013-12-05 16:48:06 -080073 private int mCurrentPhase = -1;
74
Felipe Lemee5434c32019-08-13 09:28:33 -070075 private UserManagerInternal mUserManagerInternal;
76
Fyodor Kupolov1d87e402017-01-10 18:34:10 -080077 SystemServiceManager(Context context) {
Adam Lesinski182f73f2013-12-05 16:48:06 -080078 mContext = context;
79 }
80
Jeff Brown6f357d32014-01-15 20:40:55 -080081 /**
Adam Lesinski2cb6c602014-02-14 17:19:56 -080082 * Starts a service by class name.
Jeff Brown6f357d32014-01-15 20:40:55 -080083 *
Adam Lesinski2cb6c602014-02-14 17:19:56 -080084 * @return The service instance.
Jeff Brown6f357d32014-01-15 20:40:55 -080085 */
Jeff Brown2c43c332014-06-12 22:38:59 -070086 public SystemService startService(String className) {
Tej Singhb2d68842020-01-08 15:03:38 -080087 final Class<SystemService> serviceClass = loadClassFromLoader(className,
88 this.getClass().getClassLoader());
89 return startService(serviceClass);
90 }
91
92 /**
93 * Starts a service by class name and a path that specifies the jar where the service lives.
94 *
95 * @return The service instance.
96 */
97 public SystemService startServiceFromJar(String className, String path) {
98 PathClassLoader pathClassLoader = mLoadedPaths.get(path);
99 if (pathClassLoader == null) {
100 // NB: the parent class loader should always be the system server class loader.
101 // Changing it has implications that require discussion with the mainline team.
102 pathClassLoader = new PathClassLoader(path, this.getClass().getClassLoader());
103 mLoadedPaths.put(path, pathClassLoader);
104 }
105 final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader);
106 return startService(serviceClass);
107 }
108
109 /*
110 * Loads and initializes a class from the given classLoader. Returns the class.
111 */
112 @SuppressWarnings("unchecked")
113 private static Class<SystemService> loadClassFromLoader(String className,
114 ClassLoader classLoader) {
Jeff Brown2c43c332014-06-12 22:38:59 -0700115 try {
Tej Singhb2d68842020-01-08 15:03:38 -0800116 return (Class<SystemService>) Class.forName(className, true, classLoader);
Jeff Brown2c43c332014-06-12 22:38:59 -0700117 } catch (ClassNotFoundException ex) {
Jeff Brown2c43c332014-06-12 22:38:59 -0700118 throw new RuntimeException("Failed to create service " + className
Tej Singhb2d68842020-01-08 15:03:38 -0800119 + " from class loader " + classLoader.toString() + ": service class not "
120 + "found, usually indicates that the caller should "
Jeff Brown2c43c332014-06-12 22:38:59 -0700121 + "have called PackageManager.hasSystemFeature() to check whether the "
122 + "feature is available on this device before trying to start the "
Tej Singhb2d68842020-01-08 15:03:38 -0800123 + "services that implement it. Also ensure that the correct path for the "
124 + "classloader is supplied, if applicable.", ex);
Jeff Brown2c43c332014-06-12 22:38:59 -0700125 }
Amith Yamasani91588252013-11-22 08:25:26 -0800126 }
127
Adam Lesinski182f73f2013-12-05 16:48:06 -0800128 /**
129 * Creates and starts a system service. The class must be a subclass of
130 * {@link com.android.server.SystemService}.
131 *
132 * @param serviceClass A Java class that implements the SystemService interface.
Jeff Brown6f357d32014-01-15 20:40:55 -0800133 * @return The service instance, never null.
Adam Lesinski182f73f2013-12-05 16:48:06 -0800134 * @throws RuntimeException if the service fails to start.
135 */
Jeff Brown6f357d32014-01-15 20:40:55 -0800136 public <T extends SystemService> T startService(Class<T> serviceClass) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800137 try {
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900138 final String name = serviceClass.getName();
139 Slog.i(TAG, "Starting " + name);
140 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800141
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900142 // Create the service.
143 if (!SystemService.class.isAssignableFrom(serviceClass)) {
144 throw new RuntimeException("Failed to create " + name
145 + ": service must extend " + SystemService.class.getName());
146 }
147 final T service;
148 try {
149 Constructor<T> constructor = serviceClass.getConstructor(Context.class);
150 service = constructor.newInstance(mContext);
151 } catch (InstantiationException ex) {
152 throw new RuntimeException("Failed to create service " + name
153 + ": service could not be instantiated", ex);
154 } catch (IllegalAccessException ex) {
155 throw new RuntimeException("Failed to create service " + name
156 + ": service must have a public constructor with a Context argument", ex);
157 } catch (NoSuchMethodException ex) {
158 throw new RuntimeException("Failed to create service " + name
159 + ": service must have a public constructor with a Context argument", ex);
160 } catch (InvocationTargetException ex) {
161 throw new RuntimeException("Failed to create service " + name
162 + ": service constructor threw an exception", ex);
163 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800164
MÃ¥rten Kongstad2e0d0f32016-06-02 09:35:31 +0200165 startService(service);
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900166 return service;
167 } finally {
168 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800169 }
170 }
171
MÃ¥rten Kongstad2e0d0f32016-06-02 09:35:31 +0200172 public void startService(@NonNull final SystemService service) {
173 // Register it.
174 mServices.add(service);
175 // Start it.
Wei Wangc3a76d02017-07-14 11:39:30 -0700176 long time = SystemClock.elapsedRealtime();
MÃ¥rten Kongstad2e0d0f32016-06-02 09:35:31 +0200177 try {
178 service.onStart();
179 } catch (RuntimeException ex) {
180 throw new RuntimeException("Failed to start service " + service.getClass().getName()
181 + ": onStart threw an exception", ex);
182 }
Wei Wangc3a76d02017-07-14 11:39:30 -0700183 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
MÃ¥rten Kongstad2e0d0f32016-06-02 09:35:31 +0200184 }
185
Adam Lesinski182f73f2013-12-05 16:48:06 -0800186 /**
187 * Starts the specified boot phase for all system services that have been started up to
188 * this point.
189 *
Felipe Leme137e7812019-06-10 11:38:05 -0700190 * @param t trace logger
Adam Lesinski182f73f2013-12-05 16:48:06 -0800191 * @param phase The boot phase to start.
192 */
Felipe Leme137e7812019-06-10 11:38:05 -0700193 public void startBootPhase(@NonNull TimingsTraceAndSlog t, int phase) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800194 if (phase <= mCurrentPhase) {
195 throw new IllegalArgumentException("Next phase must be larger than previous");
196 }
197 mCurrentPhase = phase;
198
199 Slog.i(TAG, "Starting phase " + mCurrentPhase);
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900200 try {
Felipe Leme137e7812019-06-10 11:38:05 -0700201 t.traceBegin("OnBootPhase " + phase);
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900202 final int serviceLen = mServices.size();
203 for (int i = 0; i < serviceLen; i++) {
204 final SystemService service = mServices.get(i);
Wei Wangc3a76d02017-07-14 11:39:30 -0700205 long time = SystemClock.elapsedRealtime();
Wei Wang6d14a832020-03-04 13:31:44 -0800206 t.traceBegin("OnBootPhase " + service.getClass().getName());
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900207 try {
208 service.onBootPhase(mCurrentPhase);
209 } catch (Exception ex) {
210 throw new RuntimeException("Failed to boot service "
211 + service.getClass().getName()
212 + ": onBootPhase threw an exception during phase "
213 + mCurrentPhase, ex);
214 }
Wei Wangc3a76d02017-07-14 11:39:30 -0700215 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
Felipe Leme137e7812019-06-10 11:38:05 -0700216 t.traceEnd();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800217 }
Yasuhiro Matsuda1ab43d52015-06-30 17:07:32 +0900218 } finally {
Felipe Leme137e7812019-06-10 11:38:05 -0700219 t.traceEnd();
220 }
221
222 if (phase == SystemService.PHASE_BOOT_COMPLETED) {
223 final long totalBootTime = SystemClock.uptimeMillis() - mRuntimeStartUptime;
224 t.logDuration("TotalBootTime", totalBootTime);
Adam Lesinski182f73f2013-12-05 16:48:06 -0800225 }
226 }
227
Keun-young Park4136d2d2017-05-08 14:51:59 -0700228 /**
229 * @return true if system has completed the boot; false otherwise.
230 */
231 public boolean isBootCompleted() {
232 return mCurrentPhase >= SystemService.PHASE_BOOT_COMPLETED;
233 }
234
Felipe Leme137e7812019-06-10 11:38:05 -0700235 /**
Felipe Lemee5434c32019-08-13 09:28:33 -0700236 * Called at the beginning of {@code ActivityManagerService.systemReady()}.
237 */
238 public void preSystemReady() {
239 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
240 }
241
242 private @NonNull UserInfo getUserInfo(@UserIdInt int userHandle) {
243 if (mUserManagerInternal == null) {
244 throw new IllegalStateException("mUserManagerInternal not set yet");
245 }
246 final UserInfo userInfo = mUserManagerInternal.getUserInfo(userHandle);
247 if (userInfo == null) {
248 throw new IllegalStateException("No UserInfo for " + userHandle);
249 }
250 return userInfo;
251 }
252
253 /**
Felipe Leme137e7812019-06-10 11:38:05 -0700254 * Starts the given user.
255 */
Felipe Lemee5434c32019-08-13 09:28:33 -0700256 public void startUser(final @NonNull TimingsTraceAndSlog t, final @UserIdInt int userHandle) {
Felipe Leme501a5142019-08-15 16:23:47 -0700257 onUser(t, START, userHandle);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700258 }
259
Felipe Leme137e7812019-06-10 11:38:05 -0700260 /**
261 * Unlocks the given user.
262 */
263 public void unlockUser(final @UserIdInt int userHandle) {
Felipe Leme339b7142020-02-21 11:05:49 -0800264 onUser(UNLOCKING, userHandle);
265 }
266
267 /**
268 * Called after the user was unlocked.
269 */
270 public void onUserUnlocked(final @UserIdInt int userHandle) {
271 onUser(UNLOCKED, userHandle);
Jeff Sharkeybedbaa92015-12-02 16:42:25 -0700272 }
273
Felipe Leme137e7812019-06-10 11:38:05 -0700274 /**
275 * Switches to the given user.
276 */
Felipe Leme501a5142019-08-15 16:23:47 -0700277 public void switchUser(final @UserIdInt int from, final @UserIdInt int to) {
278 onUser(TimingsTraceAndSlog.newAsyncLog(), SWITCH, to, from);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700279 }
280
Felipe Leme137e7812019-06-10 11:38:05 -0700281 /**
282 * Stops the given user.
283 */
284 public void stopUser(final @UserIdInt int userHandle) {
Felipe Leme501a5142019-08-15 16:23:47 -0700285 onUser(STOP, userHandle);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700286 }
287
Felipe Leme137e7812019-06-10 11:38:05 -0700288 /**
289 * Cleans up the given user.
290 */
291 public void cleanupUser(final @UserIdInt int userHandle) {
Felipe Leme501a5142019-08-15 16:23:47 -0700292 onUser(CLEANUP, userHandle);
Felipe Leme3e99d402019-08-15 14:42:32 -0700293 }
294
Felipe Leme501a5142019-08-15 16:23:47 -0700295 private void onUser(@NonNull String onWhat, @UserIdInt int userHandle) {
296 onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, userHandle);
Felipe Leme3e99d402019-08-15 14:42:32 -0700297 }
298
299 private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
Felipe Leme501a5142019-08-15 16:23:47 -0700300 @UserIdInt int userHandle) {
301 onUser(t, onWhat, userHandle, UserHandle.USER_NULL);
302 }
303
304 private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
305 @UserIdInt int curUserId, @UserIdInt int prevUserId) {
306 t.traceBegin("ssm." + onWhat + "User-" + curUserId);
307 Slog.i(TAG, "Calling on" + onWhat + "User " + curUserId);
Makoto Onukic8815902020-01-08 13:55:25 -0800308 final TargetUser curUser = new TargetUser(getUserInfo(curUserId));
309 final TargetUser prevUser = prevUserId == UserHandle.USER_NULL ? null
310 : new TargetUser(getUserInfo(prevUserId));
Dianne Hackborn91097de2014-04-04 18:02:06 -0700311 final int serviceLen = mServices.size();
312 for (int i = 0; i < serviceLen; i++) {
313 final SystemService service = mServices.get(i);
Felipe Leme137e7812019-06-10 11:38:05 -0700314 final String serviceName = service.getClass().getName();
Felipe Leme339b7142020-02-21 11:05:49 -0800315 boolean supported = service.isUserSupported(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700316
317 // Must check if either curUser or prevUser is supported (for example, if switching from
318 // unsupported to supported, we still need to notify the services)
Makoto Onukic8815902020-01-08 13:55:25 -0800319 if (!supported && prevUser != null) {
Felipe Leme339b7142020-02-21 11:05:49 -0800320 supported = service.isUserSupported(prevUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700321 }
322
323 if (!supported) {
324 if (DEBUG) {
325 Slog.d(TAG, "Skipping " + onWhat + "User-" + curUserId + " on service "
326 + serviceName + " because it's not supported (curUser: "
Makoto Onukic8815902020-01-08 13:55:25 -0800327 + curUser + ", prevUser:" + prevUser + ")");
Felipe Leme501a5142019-08-15 16:23:47 -0700328 } else {
329 Slog.i(TAG, "Skipping " + onWhat + "User-" + curUserId + " on "
330 + serviceName);
331 }
332 continue;
333 }
334 t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + " " + serviceName);
Wei Wangc3a76d02017-07-14 11:39:30 -0700335 long time = SystemClock.elapsedRealtime();
Dianne Hackborn91097de2014-04-04 18:02:06 -0700336 try {
Felipe Leme501a5142019-08-15 16:23:47 -0700337 switch (onWhat) {
338 case SWITCH:
Felipe Leme339b7142020-02-21 11:05:49 -0800339 service.onUserSwitching(prevUser, curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700340 break;
341 case START:
Felipe Leme339b7142020-02-21 11:05:49 -0800342 service.onUserStarting(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700343 break;
Felipe Leme339b7142020-02-21 11:05:49 -0800344 case UNLOCKING:
345 service.onUserUnlocking(curUser);
346 break;
347 case UNLOCKED:
348 service.onUserUnlocked(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700349 break;
350 case STOP:
Felipe Leme339b7142020-02-21 11:05:49 -0800351 service.onUserStopping(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700352 break;
353 case CLEANUP:
Felipe Leme339b7142020-02-21 11:05:49 -0800354 service.onUserStopped(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700355 break;
356 default:
357 throw new IllegalArgumentException(onWhat + " what?");
358 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700359 } catch (Exception ex) {
Makoto Onukic8815902020-01-08 13:55:25 -0800360 Slog.wtf(TAG, "Failure reporting " + onWhat + " of user " + curUser
Felipe Leme137e7812019-06-10 11:38:05 -0700361 + " to service " + serviceName, ex);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700362 }
Felipe Leme501a5142019-08-15 16:23:47 -0700363 warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
364 "on" + onWhat + "User-" + curUserId);
Felipe Leme3e99d402019-08-15 14:42:32 -0700365 t.traceEnd(); // what on service
Dianne Hackborn91097de2014-04-04 18:02:06 -0700366 }
Felipe Leme3e99d402019-08-15 14:42:32 -0700367 t.traceEnd(); // main entry
Dianne Hackborn91097de2014-04-04 18:02:06 -0700368 }
369
Amith Yamasani91588252013-11-22 08:25:26 -0800370 /** Sets the safe mode flag for services to query. */
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800371 void setSafeMode(boolean safeMode) {
Amith Yamasani91588252013-11-22 08:25:26 -0800372 mSafeMode = safeMode;
373 }
374
375 /**
376 * Returns whether we are booting into safe mode.
377 * @return safe mode flag
378 */
379 public boolean isSafeMode() {
380 return mSafeMode;
381 }
382
Adam Lesinski182f73f2013-12-05 16:48:06 -0800383 /**
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800384 * @return true if runtime was restarted, false if it's normal boot
385 */
386 public boolean isRuntimeRestarted() {
387 return mRuntimeRestarted;
388 }
389
Makoto Onukie8edbcf2018-03-02 16:49:29 -0800390 /**
391 * @return Time when SystemServer was started, in elapsed realtime.
392 */
393 public long getRuntimeStartElapsedTime() {
394 return mRuntimeStartElapsedTime;
395 }
396
397 /**
398 * @return Time when SystemServer was started, in uptime.
399 */
400 public long getRuntimeStartUptime() {
401 return mRuntimeStartUptime;
402 }
403
404 void setStartInfo(boolean runtimeRestarted,
405 long runtimeStartElapsedTime, long runtimeStartUptime) {
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800406 mRuntimeRestarted = runtimeRestarted;
Makoto Onukie8edbcf2018-03-02 16:49:29 -0800407 mRuntimeStartElapsedTime = runtimeStartElapsedTime;
408 mRuntimeStartUptime = runtimeStartUptime;
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800409 }
410
Fyodor Kupolov701a85f2017-04-25 12:52:08 -0700411 private void warnIfTooLong(long duration, SystemService service, String operation) {
412 if (duration > SERVICE_CALL_WARN_TIME_MS) {
413 Slog.w(TAG, "Service " + service.getClass().getName() + " took " + duration + " ms in "
414 + operation);
415 }
416 }
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800417
418 /**
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700419 * Ensures that the system directory exist creating one if needed.
420 * @deprecated Use {@link Environment#getDataSystemCeDirectory()}
421 * or {@link Environment#getDataSystemDeDirectory()} instead.
422 * @return The system directory.
423 */
424 @Deprecated
425 public static File ensureSystemDir() {
426 if (sSystemDir == null) {
427 File dataDir = Environment.getDataDirectory();
428 sSystemDir = new File(dataDir, "system");
429 sSystemDir.mkdirs();
430 }
431 return sSystemDir;
432 }
433
434 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -0800435 * Outputs the state of this manager to the System log.
436 */
437 public void dump() {
438 StringBuilder builder = new StringBuilder();
439 builder.append("Current phase: ").append(mCurrentPhase).append("\n");
440 builder.append("Services:\n");
441 final int startedLen = mServices.size();
442 for (int i = 0; i < startedLen; i++) {
443 final SystemService service = mServices.get(i);
444 builder.append("\t")
445 .append(service.getClass().getSimpleName())
446 .append("\n");
447 }
448
449 Slog.e(TAG, builder.toString());
450 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800451}