• 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.content.Context;
23 import android.content.pm.UserInfo;
24 import android.os.Build;
25 import android.os.Environment;
26 import android.os.SystemClock;
27 import android.os.Trace;
28 import android.util.ArrayMap;
29 import android.util.EventLog;
30 import android.util.IndentingPrintWriter;
31 import android.util.Slog;
32 import android.util.SparseArray;
33 
34 import com.android.internal.annotations.GuardedBy;
35 import com.android.internal.os.ClassLoaderFactory;
36 import com.android.internal.util.Preconditions;
37 import com.android.server.SystemService.TargetUser;
38 import com.android.server.am.EventLogTags;
39 import com.android.server.pm.UserManagerInternal;
40 import com.android.server.utils.TimingsTraceAndSlog;
41 
42 import dalvik.system.PathClassLoader;
43 
44 import java.io.File;
45 import java.lang.reflect.Constructor;
46 import java.lang.reflect.InvocationTargetException;
47 import java.util.ArrayList;
48 
49 /**
50  * Manages creating, starting, and other lifecycle events of
51  * {@link com.android.server.SystemService system services}.
52  *
53  * {@hide}
54  */
55 public final class SystemServiceManager implements Dumpable {
56     private static final String TAG = SystemServiceManager.class.getSimpleName();
57     private static final boolean DEBUG = false;
58     private static final int SERVICE_CALL_WARN_TIME_MS = 50;
59 
60     // Constants used on onUser(...)
61     // NOTE: do not change their values, as they're used on Trace calls and changes might break
62     // performance tests that rely on them.
63     private static final String USER_STARTING = "Start"; // Logged as onStartUser
64     private static final String USER_UNLOCKING = "Unlocking"; // Logged as onUnlockingUser
65     private static final String USER_UNLOCKED = "Unlocked"; // Logged as onUnlockedUser
66     private static final String USER_SWITCHING = "Switch"; // Logged as onSwitchUser
67     private static final String USER_STOPPING = "Stop"; // Logged as onStopUser
68     private static final String USER_STOPPED = "Cleanup"; // Logged as onCleanupUser
69 
70     private static File sSystemDir;
71     private final Context mContext;
72     private boolean mSafeMode;
73     private boolean mRuntimeRestarted;
74     private long mRuntimeStartElapsedTime;
75     private long mRuntimeStartUptime;
76 
77     // Services that should receive lifecycle events.
78     private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
79 
80     // Map of paths to PathClassLoader, so we don't load the same path multiple times.
81     private final ArrayMap<String, PathClassLoader> mLoadedPaths = new ArrayMap<>();
82 
83     private int mCurrentPhase = -1;
84 
85     private UserManagerInternal mUserManagerInternal;
86 
87     /**
88      * Map of started {@link TargetUser TargetUsers} by user id; users are added on start and
89      * removed after they're completely shut down.
90      */
91     @GuardedBy("mTargetUsers")
92     private final SparseArray<TargetUser> mTargetUsers = new SparseArray<>();
93 
94     /**
95      * Reference to the current user, it's used to set the {@link TargetUser} on
96      * {@link #onUserSwitching(int, int)} as the previous user might have been removed already.
97      */
98     @GuardedBy("mTargetUsers")
99     private @Nullable TargetUser mCurrentUser;
100 
SystemServiceManager(Context context)101     SystemServiceManager(Context context) {
102         mContext = context;
103     }
104 
105     /**
106      * Starts a service by class name.
107      *
108      * @return The service instance.
109      */
startService(String className)110     public SystemService startService(String className) {
111         final Class<SystemService> serviceClass = loadClassFromLoader(className,
112                 this.getClass().getClassLoader());
113         return startService(serviceClass);
114     }
115 
116     /**
117      * Starts a service by class name and a path that specifies the jar where the service lives.
118      *
119      * @return The service instance.
120      */
startServiceFromJar(String className, String path)121     public SystemService startServiceFromJar(String className, String path) {
122         PathClassLoader pathClassLoader = mLoadedPaths.get(path);
123         if (pathClassLoader == null) {
124             // NB: the parent class loader should always be the system server class loader.
125             // Changing it has implications that require discussion with the mainline team.
126             pathClassLoader = (PathClassLoader) ClassLoaderFactory.createClassLoader(
127                     path, null /* librarySearchPath */, null /* libraryPermittedPath */,
128                     this.getClass().getClassLoader(), Build.VERSION.SDK_INT,
129                     true /* isNamespaceShared */, null /* classLoaderName */);
130             mLoadedPaths.put(path, pathClassLoader);
131         }
132         final Class<SystemService> serviceClass = loadClassFromLoader(className, pathClassLoader);
133         return startService(serviceClass);
134     }
135 
136     /*
137      * Loads and initializes a class from the given classLoader. Returns the class.
138      */
139     @SuppressWarnings("unchecked")
loadClassFromLoader(String className, ClassLoader classLoader)140     private static Class<SystemService> loadClassFromLoader(String className,
141             ClassLoader classLoader) {
142         try {
143             return (Class<SystemService>) Class.forName(className, true, classLoader);
144         } catch (ClassNotFoundException ex) {
145             throw new RuntimeException("Failed to create service " + className
146                     + " from class loader " + classLoader.toString() + ": service class not "
147                     + "found, usually indicates that the caller should "
148                     + "have called PackageManager.hasSystemFeature() to check whether the "
149                     + "feature is available on this device before trying to start the "
150                     + "services that implement it. Also ensure that the correct path for the "
151                     + "classloader is supplied, if applicable.", ex);
152         }
153     }
154 
155     /**
156      * Creates and starts a system service. The class must be a subclass of
157      * {@link com.android.server.SystemService}.
158      *
159      * @param serviceClass A Java class that implements the SystemService interface.
160      * @return The service instance, never null.
161      * @throws RuntimeException if the service fails to start.
162      */
startService(Class<T> serviceClass)163     public <T extends SystemService> T startService(Class<T> serviceClass) {
164         try {
165             final String name = serviceClass.getName();
166             Slog.i(TAG, "Starting " + name);
167             Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
168 
169             // Create the service.
170             if (!SystemService.class.isAssignableFrom(serviceClass)) {
171                 throw new RuntimeException("Failed to create " + name
172                         + ": service must extend " + SystemService.class.getName());
173             }
174             final T service;
175             try {
176                 Constructor<T> constructor = serviceClass.getConstructor(Context.class);
177                 service = constructor.newInstance(mContext);
178             } catch (InstantiationException ex) {
179                 throw new RuntimeException("Failed to create service " + name
180                         + ": service could not be instantiated", ex);
181             } catch (IllegalAccessException ex) {
182                 throw new RuntimeException("Failed to create service " + name
183                         + ": service must have a public constructor with a Context argument", ex);
184             } catch (NoSuchMethodException ex) {
185                 throw new RuntimeException("Failed to create service " + name
186                         + ": service must have a public constructor with a Context argument", ex);
187             } catch (InvocationTargetException ex) {
188                 throw new RuntimeException("Failed to create service " + name
189                         + ": service constructor threw an exception", ex);
190             }
191 
192             startService(service);
193             return service;
194         } finally {
195             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
196         }
197     }
198 
startService(@onNull final SystemService service)199     public void startService(@NonNull final SystemService service) {
200         // Register it.
201         mServices.add(service);
202         // Start it.
203         long time = SystemClock.elapsedRealtime();
204         try {
205             service.onStart();
206         } catch (RuntimeException ex) {
207             throw new RuntimeException("Failed to start service " + service.getClass().getName()
208                     + ": onStart threw an exception", ex);
209         }
210         warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
211     }
212 
213     /**
214      * Starts the specified boot phase for all system services that have been started up to
215      * this point.
216      *
217      * @param t trace logger
218      * @param phase The boot phase to start.
219      */
startBootPhase(@onNull TimingsTraceAndSlog t, int phase)220     public void startBootPhase(@NonNull TimingsTraceAndSlog t, int phase) {
221         if (phase <= mCurrentPhase) {
222             throw new IllegalArgumentException("Next phase must be larger than previous");
223         }
224         mCurrentPhase = phase;
225 
226         Slog.i(TAG, "Starting phase " + mCurrentPhase);
227         try {
228             t.traceBegin("OnBootPhase_" + phase);
229             final int serviceLen = mServices.size();
230             for (int i = 0; i < serviceLen; i++) {
231                 final SystemService service = mServices.get(i);
232                 long time = SystemClock.elapsedRealtime();
233                 t.traceBegin("OnBootPhase_" + phase + "_" + service.getClass().getName());
234                 try {
235                     service.onBootPhase(mCurrentPhase);
236                 } catch (Exception ex) {
237                     throw new RuntimeException("Failed to boot service "
238                             + service.getClass().getName()
239                             + ": onBootPhase threw an exception during phase "
240                             + mCurrentPhase, ex);
241                 }
242                 warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onBootPhase");
243                 t.traceEnd();
244             }
245         } finally {
246             t.traceEnd();
247         }
248 
249         if (phase == SystemService.PHASE_BOOT_COMPLETED) {
250             final long totalBootTime = SystemClock.uptimeMillis() - mRuntimeStartUptime;
251             t.logDuration("TotalBootTime", totalBootTime);
252             SystemServerInitThreadPool.shutdown();
253         }
254     }
255 
256     /**
257      * @return true if system has completed the boot; false otherwise.
258      */
isBootCompleted()259     public boolean isBootCompleted() {
260         return mCurrentPhase >= SystemService.PHASE_BOOT_COMPLETED;
261     }
262 
263     /**
264      * Called at the beginning of {@code ActivityManagerService.systemReady()}.
265      */
preSystemReady()266     public void preSystemReady() {
267         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
268     }
269 
getTargetUser(@serIdInt int userId)270     private @NonNull TargetUser getTargetUser(@UserIdInt int userId) {
271         final TargetUser targetUser;
272         synchronized (mTargetUsers) {
273             targetUser = mTargetUsers.get(userId);
274         }
275         Preconditions.checkState(targetUser != null, "No TargetUser for " + userId);
276         return targetUser;
277     }
278 
newTargetUser(@serIdInt int userId)279     private @NonNull TargetUser newTargetUser(@UserIdInt int userId) {
280         final UserInfo userInfo = mUserManagerInternal.getUserInfo(userId);
281         Preconditions.checkState(userInfo != null, "No UserInfo for " + userId);
282         return new TargetUser(userInfo);
283     }
284 
285     /**
286      * Starts the given user.
287      */
onUserStarting(@onNull TimingsTraceAndSlog t, @UserIdInt int userId)288     public void onUserStarting(@NonNull TimingsTraceAndSlog t, @UserIdInt int userId) {
289         EventLog.writeEvent(EventLogTags.SSM_USER_STARTING, userId);
290 
291         final TargetUser targetUser = newTargetUser(userId);
292         synchronized (mTargetUsers) {
293             mTargetUsers.put(userId, targetUser);
294         }
295 
296         onUser(t, USER_STARTING, /* prevUser= */ null, targetUser);
297     }
298 
299     /**
300      * Unlocks the given user.
301      */
onUserUnlocking(@serIdInt int userId)302     public void onUserUnlocking(@UserIdInt int userId) {
303         EventLog.writeEvent(EventLogTags.SSM_USER_UNLOCKING, userId);
304         onUser(USER_UNLOCKING, userId);
305     }
306 
307     /**
308      * Called after the user was unlocked.
309      */
onUserUnlocked(@serIdInt int userId)310     public void onUserUnlocked(@UserIdInt int userId) {
311         EventLog.writeEvent(EventLogTags.SSM_USER_UNLOCKED, userId);
312         onUser(USER_UNLOCKED, userId);
313     }
314 
315     /**
316      * Switches to the given user.
317      */
onUserSwitching(@serIdInt int from, @UserIdInt int to)318     public void onUserSwitching(@UserIdInt int from, @UserIdInt int to) {
319         EventLog.writeEvent(EventLogTags.SSM_USER_SWITCHING, from, to);
320         final TargetUser curUser, prevUser;
321         synchronized (mTargetUsers) {
322             if (mCurrentUser == null) {
323                 if (DEBUG) {
324                     Slog.d(TAG, "First user switch: from " + from + " to " + to);
325                 }
326                 prevUser = newTargetUser(from);
327             } else {
328                 if (from != mCurrentUser.getUserIdentifier()) {
329                     Slog.wtf(TAG, "switchUser(" + from + "," + to + "): mCurrentUser is "
330                             + mCurrentUser + ", it should be " + from);
331                 }
332                 prevUser = mCurrentUser;
333             }
334             curUser = mCurrentUser = getTargetUser(to);
335             if (DEBUG) {
336                 Slog.d(TAG, "Set mCurrentUser to " + mCurrentUser);
337             }
338         }
339         onUser(TimingsTraceAndSlog.newAsyncLog(), USER_SWITCHING, prevUser, curUser);
340     }
341 
342     /**
343      * Stops the given user.
344      */
onUserStopping(@serIdInt int userId)345     public void onUserStopping(@UserIdInt int userId) {
346         EventLog.writeEvent(EventLogTags.SSM_USER_STOPPING, userId);
347         onUser(USER_STOPPING, userId);
348     }
349 
350     /**
351      * Cleans up the given user.
352      */
onUserStopped(@serIdInt int userId)353     public void onUserStopped(@UserIdInt int userId) {
354         EventLog.writeEvent(EventLogTags.SSM_USER_STOPPED, userId);
355         onUser(USER_STOPPED, userId);
356 
357         // Remove cached TargetUser
358         synchronized (mTargetUsers) {
359             mTargetUsers.remove(userId);
360         }
361     }
362 
onUser(@onNull String onWhat, @UserIdInt int userId)363     private void onUser(@NonNull String onWhat, @UserIdInt int userId) {
364         onUser(TimingsTraceAndSlog.newAsyncLog(), onWhat, /* prevUser= */ null,
365                 getTargetUser(userId));
366     }
367 
onUser(@onNull TimingsTraceAndSlog t, @NonNull String onWhat, @Nullable TargetUser prevUser, @NonNull TargetUser curUser)368     private void onUser(@NonNull TimingsTraceAndSlog t, @NonNull String onWhat,
369             @Nullable TargetUser prevUser, @NonNull TargetUser curUser) {
370         final int curUserId = curUser.getUserIdentifier();
371         // NOTE: do not change label below, or it might break performance tests that rely on it.
372         t.traceBegin("ssm." + onWhat + "User-" + curUserId);
373         Slog.i(TAG, "Calling on" + onWhat + "User " + curUserId
374                 + (prevUser != null ? " (from " + prevUser + ")" : ""));
375         final int serviceLen = mServices.size();
376         for (int i = 0; i < serviceLen; i++) {
377             final SystemService service = mServices.get(i);
378             final String serviceName = service.getClass().getName();
379             boolean supported = service.isUserSupported(curUser);
380 
381             // Must check if either curUser or prevUser is supported (for example, if switching from
382             // unsupported to supported, we still need to notify the services)
383             if (!supported && prevUser != null) {
384                 supported = service.isUserSupported(prevUser);
385             }
386 
387             if (!supported) {
388                 if (DEBUG) {
389                     Slog.d(TAG, "Skipping " + onWhat + "User-" + curUserId + " on service "
390                             + serviceName + " because it's not supported (curUser: "
391                             + curUser + ", prevUser:" + prevUser + ")");
392                 } else {
393                     Slog.i(TAG,  "Skipping " + onWhat + "User-" + curUserId + " on "
394                             + serviceName);
395                 }
396                 continue;
397             }
398             t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + "_" + serviceName);
399             long time = SystemClock.elapsedRealtime();
400             try {
401                 switch (onWhat) {
402                     case USER_SWITCHING:
403                         service.onUserSwitching(prevUser, curUser);
404                         break;
405                     case USER_STARTING:
406                         service.onUserStarting(curUser);
407                         break;
408                     case USER_UNLOCKING:
409                         service.onUserUnlocking(curUser);
410                         break;
411                     case USER_UNLOCKED:
412                         service.onUserUnlocked(curUser);
413                         break;
414                     case USER_STOPPING:
415                         service.onUserStopping(curUser);
416                         break;
417                     case USER_STOPPED:
418                         service.onUserStopped(curUser);
419                         break;
420                     default:
421                         throw new IllegalArgumentException(onWhat + " what?");
422                 }
423             } catch (Exception ex) {
424                 Slog.wtf(TAG, "Failure reporting " + onWhat + " of user " + curUser
425                         + " to service " + serviceName, ex);
426             }
427             warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
428                     "on" + onWhat + "User-" + curUserId);
429             t.traceEnd(); // what on service
430         }
431         t.traceEnd(); // main entry
432     }
433 
434     /** Sets the safe mode flag for services to query. */
setSafeMode(boolean safeMode)435     void setSafeMode(boolean safeMode) {
436         mSafeMode = safeMode;
437     }
438 
439     /**
440      * Returns whether we are booting into safe mode.
441      * @return safe mode flag
442      */
isSafeMode()443     public boolean isSafeMode() {
444         return mSafeMode;
445     }
446 
447     /**
448      * @return true if runtime was restarted, false if it's normal boot
449      */
isRuntimeRestarted()450     public boolean isRuntimeRestarted() {
451         return mRuntimeRestarted;
452     }
453 
454     /**
455      * @return Time when SystemServer was started, in elapsed realtime.
456      */
getRuntimeStartElapsedTime()457     public long getRuntimeStartElapsedTime() {
458         return mRuntimeStartElapsedTime;
459     }
460 
461     /**
462      * @return Time when SystemServer was started, in uptime.
463      */
getRuntimeStartUptime()464     public long getRuntimeStartUptime() {
465         return mRuntimeStartUptime;
466     }
467 
setStartInfo(boolean runtimeRestarted, long runtimeStartElapsedTime, long runtimeStartUptime)468     void setStartInfo(boolean runtimeRestarted,
469             long runtimeStartElapsedTime, long runtimeStartUptime) {
470         mRuntimeRestarted = runtimeRestarted;
471         mRuntimeStartElapsedTime = runtimeStartElapsedTime;
472         mRuntimeStartUptime = runtimeStartUptime;
473     }
474 
warnIfTooLong(long duration, SystemService service, String operation)475     private void warnIfTooLong(long duration, SystemService service, String operation) {
476         if (duration > SERVICE_CALL_WARN_TIME_MS) {
477             Slog.w(TAG, "Service " + service.getClass().getName() + " took " + duration + " ms in "
478                     + operation);
479         }
480     }
481 
482     /**
483      * Ensures that the system directory exist creating one if needed.
484      * @deprecated Use {@link Environment#getDataSystemCeDirectory()}
485      * or {@link Environment#getDataSystemDeDirectory()} instead.
486      * @return The system directory.
487      */
488     @Deprecated
ensureSystemDir()489     public static File ensureSystemDir() {
490         if (sSystemDir == null) {
491             File dataDir = Environment.getDataDirectory();
492             sSystemDir = new File(dataDir, "system");
493             sSystemDir.mkdirs();
494         }
495         return sSystemDir;
496     }
497 
498     @Override
dump(IndentingPrintWriter pw, String[] args)499     public void dump(IndentingPrintWriter pw, String[] args) {
500         pw.printf("Current phase: %d\n", mCurrentPhase);
501         synchronized (mTargetUsers) {
502             if (mCurrentUser != null) {
503                 pw.print("Current user: "); mCurrentUser.dump(pw); pw.println();
504             } else {
505                 pw.println("Current user not set!");
506             }
507 
508             final int targetUsersSize = mTargetUsers.size();
509             if (targetUsersSize > 0) {
510                 pw.printf("%d target users: ", targetUsersSize);
511                 for (int i = 0; i < targetUsersSize; i++) {
512                     mTargetUsers.valueAt(i).dump(pw);
513                     if (i != targetUsersSize - 1) pw.print(", ");
514                 }
515                 pw.println();
516             } else {
517                 pw.println("No target users");
518             }
519         }
520         final int startedLen = mServices.size();
521         if (startedLen > 0) {
522             pw.printf("%d started services:\n", startedLen);
523             pw.increaseIndent();
524             for (int i = 0; i < startedLen; i++) {
525                 final SystemService service = mServices.get(i);
526                 pw.println(service.getClass().getCanonicalName());
527             }
528             pw.decreaseIndent();
529         } else {
530             pw.println("No started services");
531         }
532     }
533 }
534