blob: 74bb7d7e90f18297eccb5df9ac5f1a226943d7cf [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 {
Wei Wanga62b4a72020-06-01 13:53:48 -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 Wanga62b4a72020-06-01 13:53:48 -0700206 t.traceBegin("OnBootPhase_" + phase + "_" + 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);
felipealfc530402020-05-11 10:20:43 -0700225 SystemServerInitThreadPool.shutdown();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800226 }
227 }
228
Keun-young Park4136d2d2017-05-08 14:51:59 -0700229 /**
230 * @return true if system has completed the boot; false otherwise.
231 */
232 public boolean isBootCompleted() {
233 return mCurrentPhase >= SystemService.PHASE_BOOT_COMPLETED;
234 }
235
Felipe Leme137e7812019-06-10 11:38:05 -0700236 /**
Felipe Lemee5434c32019-08-13 09:28:33 -0700237 * Called at the beginning of {@code ActivityManagerService.systemReady()}.
238 */
239 public void preSystemReady() {
240 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
241 }
242
243 private @NonNull UserInfo getUserInfo(@UserIdInt int userHandle) {
244 if (mUserManagerInternal == null) {
245 throw new IllegalStateException("mUserManagerInternal not set yet");
246 }
247 final UserInfo userInfo = mUserManagerInternal.getUserInfo(userHandle);
248 if (userInfo == null) {
249 throw new IllegalStateException("No UserInfo for " + userHandle);
250 }
251 return userInfo;
252 }
253
254 /**
Felipe Leme137e7812019-06-10 11:38:05 -0700255 * Starts the given user.
256 */
Felipe Lemee5434c32019-08-13 09:28:33 -0700257 public void startUser(final @NonNull TimingsTraceAndSlog t, final @UserIdInt int userHandle) {
Felipe Leme501a5142019-08-15 16:23:47 -0700258 onUser(t, START, userHandle);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700259 }
260
Felipe Leme137e7812019-06-10 11:38:05 -0700261 /**
262 * Unlocks the given user.
263 */
264 public void unlockUser(final @UserIdInt int userHandle) {
Felipe Leme339b7142020-02-21 11:05:49 -0800265 onUser(UNLOCKING, userHandle);
266 }
267
268 /**
269 * Called after the user was unlocked.
270 */
271 public void onUserUnlocked(final @UserIdInt int userHandle) {
272 onUser(UNLOCKED, userHandle);
Jeff Sharkeybedbaa92015-12-02 16:42:25 -0700273 }
274
Felipe Leme137e7812019-06-10 11:38:05 -0700275 /**
276 * Switches to the given user.
277 */
Felipe Leme501a5142019-08-15 16:23:47 -0700278 public void switchUser(final @UserIdInt int from, final @UserIdInt int to) {
279 onUser(TimingsTraceAndSlog.newAsyncLog(), SWITCH, to, from);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700280 }
281
Felipe Leme137e7812019-06-10 11:38:05 -0700282 /**
283 * Stops the given user.
284 */
285 public void stopUser(final @UserIdInt int userHandle) {
Felipe Leme501a5142019-08-15 16:23:47 -0700286 onUser(STOP, userHandle);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700287 }
288
Felipe Leme137e7812019-06-10 11:38:05 -0700289 /**
290 * Cleans up the given user.
291 */
292 public void cleanupUser(final @UserIdInt int userHandle) {
Felipe Leme501a5142019-08-15 16:23:47 -0700293 onUser(CLEANUP, userHandle);
Felipe Leme3e99d402019-08-15 14:42:32 -0700294 }
295
Felipe Leme501a5142019-08-15 16:23:47 -0700296 private void onUser(@NonNull String onWhat, @UserIdInt int userHandle) {
297 onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, userHandle);
Felipe Leme3e99d402019-08-15 14:42:32 -0700298 }
299
300 private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
Felipe Leme501a5142019-08-15 16:23:47 -0700301 @UserIdInt int userHandle) {
302 onUser(t, onWhat, userHandle, UserHandle.USER_NULL);
303 }
304
305 private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
306 @UserIdInt int curUserId, @UserIdInt int prevUserId) {
307 t.traceBegin("ssm." + onWhat + "User-" + curUserId);
308 Slog.i(TAG, "Calling on" + onWhat + "User " + curUserId);
Makoto Onukic8815902020-01-08 13:55:25 -0800309 final TargetUser curUser = new TargetUser(getUserInfo(curUserId));
310 final TargetUser prevUser = prevUserId == UserHandle.USER_NULL ? null
311 : new TargetUser(getUserInfo(prevUserId));
Dianne Hackborn91097de2014-04-04 18:02:06 -0700312 final int serviceLen = mServices.size();
313 for (int i = 0; i < serviceLen; i++) {
314 final SystemService service = mServices.get(i);
Felipe Leme137e7812019-06-10 11:38:05 -0700315 final String serviceName = service.getClass().getName();
Felipe Leme339b7142020-02-21 11:05:49 -0800316 boolean supported = service.isUserSupported(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700317
318 // Must check if either curUser or prevUser is supported (for example, if switching from
319 // unsupported to supported, we still need to notify the services)
Makoto Onukic8815902020-01-08 13:55:25 -0800320 if (!supported && prevUser != null) {
Felipe Leme339b7142020-02-21 11:05:49 -0800321 supported = service.isUserSupported(prevUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700322 }
323
324 if (!supported) {
325 if (DEBUG) {
326 Slog.d(TAG, "Skipping " + onWhat + "User-" + curUserId + " on service "
327 + serviceName + " because it's not supported (curUser: "
Makoto Onukic8815902020-01-08 13:55:25 -0800328 + curUser + ", prevUser:" + prevUser + ")");
Felipe Leme501a5142019-08-15 16:23:47 -0700329 } else {
330 Slog.i(TAG, "Skipping " + onWhat + "User-" + curUserId + " on "
331 + serviceName);
332 }
333 continue;
334 }
Wei Wanga62b4a72020-06-01 13:53:48 -0700335 t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + "_" + serviceName);
Wei Wangc3a76d02017-07-14 11:39:30 -0700336 long time = SystemClock.elapsedRealtime();
Dianne Hackborn91097de2014-04-04 18:02:06 -0700337 try {
Felipe Leme501a5142019-08-15 16:23:47 -0700338 switch (onWhat) {
339 case SWITCH:
Felipe Leme339b7142020-02-21 11:05:49 -0800340 service.onUserSwitching(prevUser, curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700341 break;
342 case START:
Felipe Leme339b7142020-02-21 11:05:49 -0800343 service.onUserStarting(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700344 break;
Felipe Leme339b7142020-02-21 11:05:49 -0800345 case UNLOCKING:
346 service.onUserUnlocking(curUser);
347 break;
348 case UNLOCKED:
349 service.onUserUnlocked(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700350 break;
351 case STOP:
Felipe Leme339b7142020-02-21 11:05:49 -0800352 service.onUserStopping(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700353 break;
354 case CLEANUP:
Felipe Leme339b7142020-02-21 11:05:49 -0800355 service.onUserStopped(curUser);
Felipe Leme501a5142019-08-15 16:23:47 -0700356 break;
357 default:
358 throw new IllegalArgumentException(onWhat + " what?");
359 }
Dianne Hackborn91097de2014-04-04 18:02:06 -0700360 } catch (Exception ex) {
Makoto Onukic8815902020-01-08 13:55:25 -0800361 Slog.wtf(TAG, "Failure reporting " + onWhat + " of user " + curUser
Felipe Leme137e7812019-06-10 11:38:05 -0700362 + " to service " + serviceName, ex);
Dianne Hackborn91097de2014-04-04 18:02:06 -0700363 }
Felipe Leme501a5142019-08-15 16:23:47 -0700364 warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
365 "on" + onWhat + "User-" + curUserId);
Felipe Leme3e99d402019-08-15 14:42:32 -0700366 t.traceEnd(); // what on service
Dianne Hackborn91097de2014-04-04 18:02:06 -0700367 }
Felipe Leme3e99d402019-08-15 14:42:32 -0700368 t.traceEnd(); // main entry
Dianne Hackborn91097de2014-04-04 18:02:06 -0700369 }
370
Amith Yamasani91588252013-11-22 08:25:26 -0800371 /** Sets the safe mode flag for services to query. */
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800372 void setSafeMode(boolean safeMode) {
Amith Yamasani91588252013-11-22 08:25:26 -0800373 mSafeMode = safeMode;
374 }
375
376 /**
377 * Returns whether we are booting into safe mode.
378 * @return safe mode flag
379 */
380 public boolean isSafeMode() {
381 return mSafeMode;
382 }
383
Adam Lesinski182f73f2013-12-05 16:48:06 -0800384 /**
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800385 * @return true if runtime was restarted, false if it's normal boot
386 */
387 public boolean isRuntimeRestarted() {
388 return mRuntimeRestarted;
389 }
390
Makoto Onukie8edbcf2018-03-02 16:49:29 -0800391 /**
392 * @return Time when SystemServer was started, in elapsed realtime.
393 */
394 public long getRuntimeStartElapsedTime() {
395 return mRuntimeStartElapsedTime;
396 }
397
398 /**
399 * @return Time when SystemServer was started, in uptime.
400 */
401 public long getRuntimeStartUptime() {
402 return mRuntimeStartUptime;
403 }
404
405 void setStartInfo(boolean runtimeRestarted,
406 long runtimeStartElapsedTime, long runtimeStartUptime) {
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800407 mRuntimeRestarted = runtimeRestarted;
Makoto Onukie8edbcf2018-03-02 16:49:29 -0800408 mRuntimeStartElapsedTime = runtimeStartElapsedTime;
409 mRuntimeStartUptime = runtimeStartUptime;
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800410 }
411
Fyodor Kupolov701a85f2017-04-25 12:52:08 -0700412 private void warnIfTooLong(long duration, SystemService service, String operation) {
413 if (duration > SERVICE_CALL_WARN_TIME_MS) {
414 Slog.w(TAG, "Service " + service.getClass().getName() + " took " + duration + " ms in "
415 + operation);
416 }
417 }
Fyodor Kupolov1d87e402017-01-10 18:34:10 -0800418
419 /**
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700420 * Ensures that the system directory exist creating one if needed.
421 * @deprecated Use {@link Environment#getDataSystemCeDirectory()}
422 * or {@link Environment#getDataSystemDeDirectory()} instead.
423 * @return The system directory.
424 */
425 @Deprecated
426 public static File ensureSystemDir() {
427 if (sSystemDir == null) {
428 File dataDir = Environment.getDataDirectory();
429 sSystemDir = new File(dataDir, "system");
430 sSystemDir.mkdirs();
431 }
432 return sSystemDir;
433 }
434
435 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -0800436 * Outputs the state of this manager to the System log.
437 */
438 public void dump() {
439 StringBuilder builder = new StringBuilder();
440 builder.append("Current phase: ").append(mCurrentPhase).append("\n");
441 builder.append("Services:\n");
442 final int startedLen = mServices.size();
443 for (int i = 0; i < startedLen; i++) {
444 final SystemService service = mServices.get(i);
445 builder.append("\t")
446 .append(service.getClass().getSimpleName())
447 .append("\n");
448 }
449
450 Slog.e(TAG, builder.toString());
451 }
Adam Lesinski182f73f2013-12-05 16:48:06 -0800452}