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