• 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.annotation.Nullable;
21 import android.annotation.UserIdInt;
22 import android.app.ActivityManager;
23 import android.content.Context;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageInfo;
26 import android.content.pm.UserInfo;
27 import android.os.Environment;
28 import android.os.SystemClock;
29 import android.os.Trace;
30 import android.os.UserHandle;
31 import android.util.ArraySet;
32 import android.util.Dumpable;
33 import android.util.EventLog;
34 import android.util.Slog;
35 import android.util.SparseArray;
36 
37 import com.android.internal.annotations.GuardedBy;
38 import com.android.internal.os.SystemServerClassLoaderFactory;
39 import com.android.internal.util.Preconditions;
40 import com.android.server.SystemService.TargetUser;
41 import com.android.server.SystemService.UserCompletedEventType;
42 import com.android.server.am.EventLogTags;
43 import com.android.server.pm.ApexManager;
44 import com.android.server.pm.UserManagerInternal;
45 import com.android.server.utils.TimingsTraceAndSlog;
46 
47 import dalvik.system.PathClassLoader;
48 
49 import java.io.File;
50 import java.io.PrintWriter;
51 import java.lang.reflect.Constructor;
52 import java.lang.reflect.InvocationTargetException;
53 import java.nio.file.Path;
54 import java.nio.file.Paths;
55 import java.util.ArrayList;
56 import java.util.Collections;
57 import java.util.List;
58 import java.util.Set;
59 import java.util.concurrent.ExecutorService;
60 import java.util.concurrent.Executors;
61 import java.util.concurrent.TimeUnit;
62 
63 /**
64  * Manages creating, starting, and other lifecycle events of
65  * {@link com.android.server.SystemService system services}.
66  *
67  * {@hide}
68  */
69 public final class SystemServiceManager implements Dumpable {
70     private static final String TAG = SystemServiceManager.class.getSimpleName();
71     private static final boolean DEBUG = false;
72     private static final int SERVICE_CALL_WARN_TIME_MS = 50;
73 
74     // Constants used on onUser(...)
75     // NOTE: do not change their values, as they're used on Trace calls and changes might break
76     // performance tests that rely on them.
77     private static final String USER_STARTING = "Start"; // Logged as onStartUser
78     private static final String USER_UNLOCKING = "Unlocking"; // Logged as onUnlockingUser
79     private static final String USER_UNLOCKED = "Unlocked"; // Logged as onUnlockedUser
80     private static final String USER_SWITCHING = "Switch"; // Logged as onSwitchUser
81     private static final String USER_STOPPING = "Stop"; // Logged as onStopUser
82     private static final String USER_STOPPED = "Cleanup"; // Logged as onCleanupUser
83     private static final String USER_COMPLETED_EVENT = "CompletedEvent"; // onCompletedEventUser
84 
85     // Whether to use multiple threads to run user lifecycle phases in parallel.
86     private static boolean sUseLifecycleThreadPool = true;
87     // The default number of threads to use if lifecycle thread pool is enabled.
88     private static final int DEFAULT_MAX_USER_POOL_THREADS = 3;
89     // The number of threads to use if lifecycle thread pool is enabled, dependent on the number of
90     // available cores on the device.
91     private final int mNumUserPoolThreads;
92     // Maximum time to wait for a particular lifecycle phase to finish.
93     private static final long USER_POOL_SHUTDOWN_TIMEOUT_SECONDS = 30;
94     // Indirectly indicates how many services belong in the bootstrap and core service categories.
95     // This is used to decide which services the user lifecycle phases should be parallelized for.
96     private static volatile int sOtherServicesStartIndex;
97 
98     private static File sSystemDir;
99     private final Context mContext;
100     private boolean mSafeMode;
101     private boolean mRuntimeRestarted;
102     private long mRuntimeStartElapsedTime;
103     private long mRuntimeStartUptime;
104 
105     // Services that should receive lifecycle events.
106     private List<SystemService> mServices;
107     private Set<String> mServiceClassnames;
108 
109     private int mCurrentPhase = -1;
110 
111     private UserManagerInternal mUserManagerInternal;
112 
113     /**
114      * Map of started {@link TargetUser TargetUsers} by user id; users are added on start and
115      * removed after they're completely shut down.
116      */
117     @GuardedBy("mTargetUsers")
118     private final SparseArray<TargetUser> mTargetUsers = new SparseArray<>();
119 
120     /**
121      * Reference to the current user, it's used to set the {@link TargetUser} on
122      * {@link #onUserSwitching(int, int)} as the previous user might have been removed already.
123      */
124     @GuardedBy("mTargetUsers")
125     private @Nullable TargetUser mCurrentUser;
126 
SystemServiceManager(Context context)127     SystemServiceManager(Context context) {
128         mContext = context;
129         mServices = new ArrayList<>();
130         mServiceClassnames = new ArraySet<>();
131         // Disable using the thread pool for low ram devices
132         sUseLifecycleThreadPool = sUseLifecycleThreadPool
133                 && !ActivityManager.isLowRamDeviceStatic();
134         mNumUserPoolThreads = Math.min(Runtime.getRuntime().availableProcessors(),
135                 DEFAULT_MAX_USER_POOL_THREADS);
136     }
137 
138     /**
139      * Starts a service by class name.
140      *
141      * @return The service instance.
142      */
startService(String className)143     public SystemService startService(String className) {
144         final Class<SystemService> serviceClass = loadClassFromLoader(className,
145                 this.getClass().getClassLoader());
146         return startService(serviceClass);
147     }
148 
149     /**
150      * Starts a service by class name and a path that specifies the jar where the service lives.
151      *
152      * @return The service instance.
153      */
startServiceFromJar(String className, String path)154     public SystemService startServiceFromJar(String className, String path) {
155         PathClassLoader pathClassLoader =
156                 SystemServerClassLoaderFactory.getOrCreateClassLoader(
157                         path, this.getClass().getClassLoader(), isJarInTestApex(path));
158         final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader);
159         return startService(serviceClass);
160     }
161 
162     /**
163      * Returns true if the jar is in a test APEX.
164      */
isJarInTestApex(String pathStr)165     private static boolean isJarInTestApex(String pathStr) {
166         Path path = Paths.get(pathStr);
167         if (path.getNameCount() >= 2 && path.getName(0).toString().equals("apex")) {
168             String apexModuleName = path.getName(1).toString();
169             ApexManager apexManager = ApexManager.getInstance();
170             String packageName = apexManager.getActivePackageNameForApexModuleName(apexModuleName);
171             PackageInfo packageInfo = apexManager.getPackageInfo(
172                     packageName, ApexManager.MATCH_ACTIVE_PACKAGE);
173             if (packageInfo != null) {
174                 return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;
175             }
176         }
177         return false;
178     }
179 
180     /*
181      * Loads and initializes a class from the given classLoader. Returns the class.
182      */
183     @SuppressWarnings("unchecked")
loadClassFromLoader(String className, ClassLoader classLoader)184     private static Class<SystemService> loadClassFromLoader(String className,
185             ClassLoader classLoader) {
186         try {
187             return (Class<SystemService>) Class.forName(className, true, classLoader);
188         } catch (ClassNotFoundException ex) {
189             throw new RuntimeException("Failed to create service " + className
190                     + " from class loader " + classLoader.toString() + ": service class not "
191                     + "found, usually indicates that the caller should "
192                     + "have called PackageManager.hasSystemFeature() to check whether the "
193                     + "feature is available on this device before trying to start the "
194                     + "services that implement it. Also ensure that the correct path for the "
195                     + "classloader is supplied, if applicable.", ex);
196         }
197     }
198 
199     /**
200      * Creates and starts a system service. The class must be a subclass of
201      * {@link com.android.server.SystemService}.
202      *
203      * @param serviceClass A Java class that implements the SystemService interface.
204      * @return The service instance, never null.
205      * @throws RuntimeException if the service fails to start.
206      */
startService(Class<T> serviceClass)207     public <T extends SystemService> T startService(Class<T> serviceClass) {
208         try {
209             final String name = serviceClass.getName();
210             Slog.i(TAG, "Starting " + name);
211             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
212 
213             // Create the service.
214             if (!SystemService.class.isAssignableFrom(serviceClass)) {
215                 throw new RuntimeException("Failed to create " + name
216                         + ": service must extend " + SystemService.class.getName());
217             }
218             final T service;
219             try {
220                 Constructor<T> constructor = serviceClass.getConstructor(Context.class);
221                 service = constructor.newInstance(mContext);
222             } catch (InstantiationException ex) {
223                 throw new RuntimeException("Failed to create service " + name
224                         + ": service could not be instantiated", ex);
225             } catch (IllegalAccessException ex) {
226                 throw new RuntimeException("Failed to create service " + name
227                         + ": service must have a public constructor with a Context argument", ex);
228             } catch (NoSuchMethodException ex) {
229                 throw new RuntimeException("Failed to create service " + name
230                         + ": service must have a public constructor with a Context argument", ex);
231             } catch (InvocationTargetException ex) {
232                 throw new RuntimeException("Failed to create service " + name
233                         + ": service constructor threw an exception", ex);
234             }
235 
236             startService(service);
237             return service;
238         } finally {
239             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
240         }
241     }
242 
startService(@onNull final SystemService service)243     public void startService(@NonNull final SystemService service) {
244         // Check if already started
245         String className = service.getClass().getName();
246         if (mServiceClassnames.contains(className)) {
247             Slog.i(TAG, "Not starting an already started service " + className);
248             return;
249         }
250         mServiceClassnames.add(className);
251 
252         // Register it.
253         mServices.add(service);
254 
255         // Start it.
256         long time = SystemClock.elapsedRealtime();
257         try {
258             service.onStart();
259         } catch (RuntimeException ex) {
260             throw new RuntimeException("Failed to start service " + service.getClass().getName()
261                     + ": onStart threw an exception", ex);
262         }
263         warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
264     }
265 
266     /** Disallow starting new services after this call. */
sealStartedServices()267     void sealStartedServices() {
268         mServiceClassnames = Collections.emptySet();
269         mServices = Collections.unmodifiableList(mServices);
270     }
271 
272     /**
273      * Starts the specified boot phase for all system services that have been started up to
274      * this point.
275      *
276      * @param t     trace logger
277      * @param phase The boot phase to start.
278      */
startBootPhase(@onNull TimingsTraceAndSlog t, int phase)279     public void startBootPhase(@NonNull TimingsTraceAndSlog t, int phase) {
280         if (phase <= mCurrentPhase) {
281             throw new IllegalArgumentException("Next phase must be larger than previous");
282         }
283         mCurrentPhase = phase;
284 
285         Slog.i(TAG, "Starting phase " + mCurrentPhase);
286         try {
287             t.traceBegin("OnBootPhase_" + phase);
288             final int serviceLen = mServices.size();
289             for (int i = 0; i < serviceLen; i++) {
290                 final SystemService service = mServices.get(i);
291                 long time = SystemClock.elapsedRealtime();
292                 t.traceBegin("OnBootPhase_" + phase + "_" + service.getClass().getName());
293                 try {
294                     service.onBootPhase(mCurrentPhase);
295                 } catch (Exception ex) {
296                     throw new RuntimeException("Failed to boot service "
297                             + service.getClass().getName()
298                             + ": onBootPhase threw an exception during phase "
299                             + mCurrentPhase, ex);
300                 }
301                 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
302                 t.traceEnd();
303             }
304         } finally {
305             t.traceEnd();
306         }
307 
308         if (phase == SystemService.PHASE_BOOT_COMPLETED) {
309             final long totalBootTime = SystemClock.uptimeMillis() - mRuntimeStartUptime;
310             t.logDuration("TotalBootTime", totalBootTime);
311             SystemServerInitThreadPool.shutdown();
312         }
313     }
314 
315     /**
316      * @return true if system has completed the boot; false otherwise.
317      */
isBootCompleted()318     public boolean isBootCompleted() {
319         return mCurrentPhase >= SystemService.PHASE_BOOT_COMPLETED;
320     }
321 
322     /**
323      * Called from SystemServer to indicate that services in the other category are now starting.
324      * This is used to keep track of how many services are in the bootstrap and core service
325      * categories for the purposes of user lifecycle parallelization.
326      */
updateOtherServicesStartIndex()327     public void updateOtherServicesStartIndex() {
328         // Only update the index if the boot phase has not been completed yet
329         if (!isBootCompleted()) {
330             sOtherServicesStartIndex = mServices.size();
331         }
332     }
333 
334     /**
335      * Called at the beginning of {@code ActivityManagerService.systemReady()}.
336      */
preSystemReady()337     public void preSystemReady() {
338         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
339     }
340 
getTargetUser(@serIdInt int userId)341     private @NonNull TargetUser getTargetUser(@UserIdInt int userId) {
342         final TargetUser targetUser;
343         synchronized (mTargetUsers) {
344             targetUser = mTargetUsers.get(userId);
345         }
346         Preconditions.checkState(targetUser != null, "No TargetUser for " + userId);
347         return targetUser;
348     }
349 
newTargetUser(@serIdInt int userId)350     private @NonNull TargetUser newTargetUser(@UserIdInt int userId) {
351         final UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);
352         Preconditions.checkState(userInfo != null, "No UserInfo for " + userId);
353         return new TargetUser(userInfo);
354     }
355 
356     /**
357      * Starts the given user.
358      */
onUserStarting(@onNull TimingsTraceAndSlog t, @UserIdInt int userId)359     public void onUserStarting(@NonNull TimingsTraceAndSlog t, @UserIdInt int userId) {
360         final TargetUser targetUser = newTargetUser(userId);
361         synchronized (mTargetUsers) {
362             // On Automotive / Headless System User Mode, the system user will be started twice:
363             // - Once by some external or local service that switches the system user to
364             //   the background.
365             // - Once by the ActivityManagerService, when the system is marked ready.
366             // These two events are not synchronized and the order of execution is
367             // non-deterministic. To avoid starting the system user twice, verify whether
368             // the system user has already been started by checking the mTargetUsers.
369             // TODO(b/242195409): this workaround shouldn't be necessary once we move
370             // the headless-user start logic to UserManager-land.
371             if (userId == UserHandle.USER_SYSTEM && mTargetUsers.contains(userId)) {
372                 Slog.e(TAG, "Skipping starting system user twice");
373                 return;
374             }
375             mTargetUsers.put(userId, targetUser);
376         }
377         EventLog.writeEvent(EventLogTags.SSM_USER_STARTING, userId);
378         onUser(t, USER_STARTING, /* prevUser= */ null, targetUser);
379     }
380 
381     /**
382      * Unlocks the given user.
383      */
onUserUnlocking(@serIdInt int userId)384     public void onUserUnlocking(@UserIdInt int userId) {
385         EventLog.writeEvent(EventLogTags.SSM_USER_UNLOCKING, userId);
386         onUser(USER_UNLOCKING, userId);
387     }
388 
389     /**
390      * Called after the user was unlocked.
391      */
onUserUnlocked(@serIdInt int userId)392     public void onUserUnlocked(@UserIdInt int userId) {
393         EventLog.writeEvent(EventLogTags.SSM_USER_UNLOCKED, userId);
394         onUser(USER_UNLOCKED, userId);
395     }
396 
397     /**
398      * Switches to the given user.
399      */
onUserSwitching(@serIdInt int from, @UserIdInt int to)400     public void onUserSwitching(@UserIdInt int from, @UserIdInt int to) {
401         EventLog.writeEvent(EventLogTags.SSM_USER_SWITCHING, from, to);
402         final TargetUser curUser, prevUser;
403         synchronized (mTargetUsers) {
404             if (mCurrentUser == null) {
405                 if (DEBUG) {
406                     Slog.d(TAG, "First user switch: from " + from + " to " + to);
407                 }
408                 prevUser = newTargetUser(from);
409             } else {
410                 if (from != mCurrentUser.getUserIdentifier()) {
411                     Slog.wtf(TAG, "switchUser(" + from + "," + to + "): mCurrentUser is "
412                             + mCurrentUser + ", it should be " + from);
413                 }
414                 prevUser = mCurrentUser;
415             }
416             curUser = mCurrentUser = getTargetUser(to);
417             if (DEBUG) {
418                 Slog.d(TAG, "Set mCurrentUser to " + mCurrentUser);
419             }
420         }
421         onUser(TimingsTraceAndSlog.newAsyncLog(), USER_SWITCHING, prevUser, curUser);
422     }
423 
424     /**
425      * Stops the given user.
426      */
onUserStopping(@serIdInt int userId)427     public void onUserStopping(@UserIdInt int userId) {
428         EventLog.writeEvent(EventLogTags.SSM_USER_STOPPING, userId);
429         onUser(USER_STOPPING, userId);
430     }
431 
432     /**
433      * Cleans up the given user.
434      */
onUserStopped(@serIdInt int userId)435     public void onUserStopped(@UserIdInt int userId) {
436         EventLog.writeEvent(EventLogTags.SSM_USER_STOPPED, userId);
437         onUser(USER_STOPPED, userId);
438 
439         // Remove cached TargetUser
440         synchronized (mTargetUsers) {
441             mTargetUsers.remove(userId);
442         }
443     }
444 
445     /**
446      * Called some time <i>after</i> an onUser... event has completed, for the events delineated in
447      * {@link UserCompletedEventType}.
448      *
449      * @param eventFlags the events that completed, per {@link UserCompletedEventType}, or 0.
450      * @see SystemService#onUserCompletedEvent
451      */
onUserCompletedEvent(@serIdInt int userId, @UserCompletedEventType.EventTypesFlag int eventFlags)452     public void onUserCompletedEvent(@UserIdInt int userId,
453             @UserCompletedEventType.EventTypesFlag int eventFlags) {
454         EventLog.writeEvent(EventLogTags.SSM_USER_COMPLETED_EVENT, userId, eventFlags);
455         if (eventFlags == 0) {
456             return;
457         }
458         onUser(TimingsTraceAndSlog.newAsyncLog(),
459                 USER_COMPLETED_EVENT,
460                 /* prevUser= */ null,
461                 getTargetUser(userId),
462                 new UserCompletedEventType(eventFlags));
463     }
464 
onUser(@onNull String onWhat, @UserIdInt int userId)465     private void onUser(@NonNull String onWhat, @UserIdInt int userId) {
466         onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, /* prevUser= */ null,
467                 getTargetUser(userId));
468     }
469 
onUser(@onNull TimingsTraceAndSlog t, @NonNull String onWhat, @Nullable TargetUser prevUser, @NonNull TargetUser curUser)470     private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
471             @Nullable TargetUser prevUser, @NonNull TargetUser curUser) {
472         onUser(t, onWhat, prevUser, curUser, /* completedEventType=*/ null);
473     }
474 
onUser(@onNull TimingsTraceAndSlog t, @NonNull String onWhat, @Nullable TargetUser prevUser, @NonNull TargetUser curUser, @Nullable UserCompletedEventType completedEventType)475     private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
476             @Nullable TargetUser prevUser, @NonNull TargetUser curUser,
477             @Nullable UserCompletedEventType completedEventType) {
478         final int curUserId = curUser.getUserIdentifier();
479         // NOTE: do not change label below, or it might break performance tests that rely on it.
480         t.traceBegin("ssm." + onWhat + "User-" + curUserId);
481         Slog.i(TAG, "Calling on" + onWhat + "User " + curUserId
482                 + (prevUser != null ? " (from " + prevUser + ")" : ""));
483 
484         final boolean useThreadPool = useThreadPool(curUserId, onWhat);
485         final ExecutorService threadPool =
486                 useThreadPool ? Executors.newFixedThreadPool(mNumUserPoolThreads) : null;
487 
488         final int serviceLen = mServices.size();
489         for (int i = 0; i < serviceLen; i++) {
490             final SystemService service = mServices.get(i);
491             final String serviceName = service.getClass().getName();
492             boolean supported = service.isUserSupported(curUser);
493 
494             // Must check if either curUser or prevUser is supported (for example, if switching from
495             // unsupported to supported, we still need to notify the services)
496             if (!supported && prevUser != null) {
497                 supported = service.isUserSupported(prevUser);
498             }
499 
500             if (!supported) {
501                 if (DEBUG) {
502                     Slog.d(TAG, "Skipping " + onWhat + "User-" + curUserId + " on service "
503                             + serviceName + " because it's not supported (curUser: "
504                             + curUser + ", prevUser:" + prevUser + ")");
505                 } else {
506                     Slog.i(TAG, "Skipping " + onWhat + "User-" + curUserId + " on "
507                             + serviceName);
508                 }
509                 continue;
510             }
511             final boolean submitToThreadPool = useThreadPool && useThreadPoolForService(onWhat, i);
512             if (!submitToThreadPool) {
513                 t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + "_" + serviceName);
514             }
515             long time = SystemClock.elapsedRealtime();
516             try {
517                 switch (onWhat) {
518                     case USER_SWITCHING:
519                         service.onUserSwitching(prevUser, curUser);
520                         break;
521                     case USER_STARTING:
522                         if (submitToThreadPool) {
523                             threadPool.submit(getOnUserStartingRunnable(t, service, curUser));
524                         } else {
525                             service.onUserStarting(curUser);
526                         }
527                         break;
528                     case USER_UNLOCKING:
529                         service.onUserUnlocking(curUser);
530                         break;
531                     case USER_UNLOCKED:
532                         service.onUserUnlocked(curUser);
533                         break;
534                     case USER_STOPPING:
535                         service.onUserStopping(curUser);
536                         break;
537                     case USER_STOPPED:
538                         service.onUserStopped(curUser);
539                         break;
540                     case USER_COMPLETED_EVENT:
541                         threadPool.submit(getOnUserCompletedEventRunnable(
542                                 t, service, serviceName, curUser, completedEventType));
543                         break;
544                     default:
545                         throw new IllegalArgumentException(onWhat + " what?");
546                 }
547             } catch (Exception ex) {
548                 logFailure(onWhat, curUser, serviceName, ex);
549             }
550             if (!submitToThreadPool) {
551                 warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
552                         "on" + onWhat + "User-" + curUserId);
553                 t.traceEnd(); // what on service
554             }
555         }
556         if (useThreadPool) {
557             boolean terminated = false;
558             threadPool.shutdown();
559             try {
560                 terminated = threadPool.awaitTermination(
561                         USER_POOL_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
562             } catch (InterruptedException e) {
563                 Slog.wtf(TAG, "User lifecycle thread pool was interrupted while awaiting completion"
564                         + " of " + onWhat + " of user " + curUser, e);
565                 if (!onWhat.equals(USER_COMPLETED_EVENT)) {
566                     Slog.e(TAG, "Couldn't terminate, disabling thread pool. "
567                             + "Please capture a bug report.");
568                     sUseLifecycleThreadPool = false;
569                 }
570             }
571             if (!terminated) {
572                 Slog.wtf(TAG, "User lifecycle thread pool was not terminated.");
573             }
574         }
575         t.traceEnd(); // main entry
576     }
577 
578     /**
579      * Whether the given onWhat should use a thread pool.
580      * IMPORTANT: changing the logic to return true won't necessarily make it multi-threaded.
581      *            There needs to be a corresponding logic change in onUser() to actually submit
582      *            to a threadPool for the given onWhat.
583      */
useThreadPool(int userId, @NonNull String onWhat)584     private boolean useThreadPool(int userId, @NonNull String onWhat) {
585         switch (onWhat) {
586             case USER_STARTING:
587                 // Limit the lifecycle parallelization to all users other than the system user
588                 // and only for the user start lifecycle phase for now.
589                 return sUseLifecycleThreadPool && userId != UserHandle.USER_SYSTEM;
590             case USER_COMPLETED_EVENT:
591                 return true;
592             default:
593                 return false;
594         }
595     }
596 
useThreadPoolForService(@onNull String onWhat, int serviceIndex)597     private boolean useThreadPoolForService(@NonNull String onWhat, int serviceIndex) {
598         switch (onWhat) {
599             case USER_STARTING:
600                 // Only submit this service to the thread pool if it's in the "other" category.
601                 return serviceIndex >= sOtherServicesStartIndex;
602             case USER_COMPLETED_EVENT:
603                 return true;
604             default:
605                 return false;
606         }
607     }
608 
getOnUserStartingRunnable(TimingsTraceAndSlog oldTrace, SystemService service, TargetUser curUser)609     private Runnable getOnUserStartingRunnable(TimingsTraceAndSlog oldTrace, SystemService service,
610             TargetUser curUser) {
611         return () -> {
612             final TimingsTraceAndSlog t = new TimingsTraceAndSlog(oldTrace);
613             final String serviceName = service.getClass().getName();
614             final int curUserId = curUser.getUserIdentifier();
615             t.traceBegin("ssm.on" + USER_STARTING + "User-" + curUserId + "_" + serviceName);
616             try {
617                 long time = SystemClock.elapsedRealtime();
618                 service.onUserStarting(curUser);
619                 warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
620                         "on" + USER_STARTING + "User-" + curUserId);
621             } catch (Exception e) {
622                 logFailure(USER_STARTING, curUser, serviceName, e);
623                 Slog.e(TAG, "Disabling thread pool - please capture a bug report.");
624                 sUseLifecycleThreadPool = false;
625             } finally {
626                 t.traceEnd();
627             }
628         };
629     }
630 
getOnUserCompletedEventRunnable(TimingsTraceAndSlog oldTrace, SystemService service, String serviceName, TargetUser curUser, UserCompletedEventType eventType)631     private Runnable getOnUserCompletedEventRunnable(TimingsTraceAndSlog oldTrace,
632             SystemService service, String serviceName, TargetUser curUser,
633             UserCompletedEventType eventType) {
634         return () -> {
635             final TimingsTraceAndSlog t = new TimingsTraceAndSlog(oldTrace);
636             final int curUserId = curUser.getUserIdentifier();
637             t.traceBegin("ssm.on" + USER_COMPLETED_EVENT + "User-" + curUserId
638                     + "_" + eventType + "_" + serviceName);
639             try {
640                 long time = SystemClock.elapsedRealtime();
641                 service.onUserCompletedEvent(curUser, eventType);
642                 warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
643                         "on" + USER_COMPLETED_EVENT + "User-" + curUserId);
644             } catch (Exception e) {
645                 logFailure(USER_COMPLETED_EVENT, curUser, serviceName, e);
646                 throw e;
647             } finally {
648                 t.traceEnd();
649             }
650         };
651     }
652 
653     /** Logs the failure. That's all. Tests may rely on parsing it, so only modify carefully. */
654     private void logFailure(String onWhat, TargetUser curUser, String serviceName, Exception ex) {
655         Slog.wtf(TAG, "SystemService failure: Failure reporting " + onWhat + " of user "
656                 + curUser + " to service " + serviceName, ex);
657     }
658 
659     /** Sets the safe mode flag for services to query. */
660     void setSafeMode(boolean safeMode) {
661         mSafeMode = safeMode;
662     }
663 
664     /**
665      * Returns whether we are booting into safe mode.
666      *
667      * @return safe mode flag
668      */
669     public boolean isSafeMode() {
670         return mSafeMode;
671     }
672 
673     /**
674      * @return true if runtime was restarted, false if it's normal boot
675      */
676     public boolean isRuntimeRestarted() {
677         return mRuntimeRestarted;
678     }
679 
680     /**
681      * @return Time when SystemServer was started, in elapsed realtime.
682      */
683     public long getRuntimeStartElapsedTime() {
684         return mRuntimeStartElapsedTime;
685     }
686 
687     /**
688      * @return Time when SystemServer was started, in uptime.
689      */
690     public long getRuntimeStartUptime() {
691         return mRuntimeStartUptime;
692     }
693 
694     void setStartInfo(boolean runtimeRestarted,
695             long runtimeStartElapsedTime, long runtimeStartUptime) {
696         mRuntimeRestarted = runtimeRestarted;
697         mRuntimeStartElapsedTime = runtimeStartElapsedTime;
698         mRuntimeStartUptime = runtimeStartUptime;
699     }
700 
701     private void warnIfTooLong(long duration, SystemService service, String operation) {
702         if (duration > SERVICE_CALL_WARN_TIME_MS) {
703             Slog.w(TAG, "Service " + service.getClass().getName() + " took " + duration + " ms in "
704                     + operation);
705         }
706     }
707 
708     /**
709      * Ensures that the system directory exist creating one if needed.
710      *
711      * @return The system directory.
712      * @deprecated Use {@link Environment#getDataSystemCeDirectory()}
713      * or {@link Environment#getDataSystemDeDirectory()} instead.
714      */
715     @Deprecated
716     public static File ensureSystemDir() {
717         if (sSystemDir == null) {
718             File dataDir = Environment.getDataDirectory();
719             sSystemDir = new File(dataDir, "system");
720             sSystemDir.mkdirs();
721         }
722         return sSystemDir;
723     }
724 
725     @Override
726     public String getDumpableName() {
727         return SystemServiceManager.class.getSimpleName();
728     }
729 
730     @Override
731     public void dump(PrintWriter pw, String[] args) {
732         pw.printf("Current phase: %d\n", mCurrentPhase);
733         synchronized (mTargetUsers) {
734             if (mCurrentUser != null) {
735                 pw.print("Current user: ");
736                 mCurrentUser.dump(pw);
737                 pw.println();
738             } else {
739                 pw.println("Current user not set!");
740             }
741 
742             final int targetUsersSize = mTargetUsers.size();
743             if (targetUsersSize > 0) {
744                 pw.printf("%d target users: ", targetUsersSize);
745                 for (int i = 0; i < targetUsersSize; i++) {
746                     mTargetUsers.valueAt(i).dump(pw);
747                     if (i != targetUsersSize - 1) pw.print(", ");
748                 }
749                 pw.println();
750             } else {
751                 pw.println("No target users");
752             }
753         }
754         final int startedLen = mServices.size();
755         String prefix = "  ";
756         if (startedLen > 0) {
757             pw.printf("%d started services:\n", startedLen);
758             for (int i = 0; i < startedLen; i++) {
759                 final SystemService service = mServices.get(i);
760                 pw.print(prefix); pw.println(service.getClass().getCanonicalName());
761             }
762         } else {
763             pw.println("No started services");
764         }
765     }
766 }
767