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