[[375159]] Preface Today, we will continue to improve the architecture of the Android system and talk about the ActivityManagerService, which plays an important role in the App startup process. As the name suggests, this component is definitely used to manage Activity services. In fact, it is not only Activity, it is also responsible for the startup, switching, scheduling, etc. of the four major components. How is it started and how is it managed? Let’s take a look. (Code based on Android 9.0) Start the service As mentioned in the SystemServer chapter, system services are generally started through the SystemServer process, and AMS is no exception. - //SystemServer.java
- private void startBootstrapServices() {
- //...
-
- // Activity manager runs the show.
- traceBeginAndSlog( "StartActivityManager" );
- mActivityManagerService = mSystemServiceManager.startService(
- ActivityManagerService.Lifecycle.class).getService();
- mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
- mActivityManagerService.setInstaller(installer);
- traceEnd();
- }
-
- //Reflection is used in the middle, as mentioned before.
-
-
- public void startService(@NonNull final SystemService service) {
- // Register it.
- mServices.add (service);
- // Start it.
- long time = SystemClock.elapsedRealtime();
- try {
- service.onStart();
- } catch (RuntimeException ex) {
- throw new RuntimeException( "Failed to start service " + service.getClass().getName()
- + ": onStart threw an exception" , ex);
- }
- }
-
-
- //ActivityManagerService.java
- public static final class Lifecycle extends SystemService {
- private final ActivityManagerService mService;
-
- public Lifecycle(Context context) {
- super(context);
- mService = new ActivityManagerService(context);
- }
-
- @Override
- public void onStart() {
- mService.start();
- }
-
- @Override
- public void onBootPhase( int phase) {
- mService.mBootPhase = phase;
- if (phase == PHASE_SYSTEM_SERVICES_READY) {
- mService.mBatteryStatsService.systemServicesReady();
- mService.mServices.systemServicesReady();
- }
- }
-
- @Override
- public void onCleanupUser( int userId) {
- mService.mBatteryStatsService.onCleanupUser(userId);
- }
-
- public ActivityManagerService getService() {
- return mService;
- }
- }
It can be seen that AMS is started by calling the onStart method in the inner class of ActivityManagerService.Lifecycle, and the start method of AMS is called. Let's take a quick look at the instantiation method and start method of AMS: - public ActivityManagerService(Context systemContext) {
- mContext = systemContext;
-
- mFactoryTest = FactoryTest.getMode();
- mSystemThread = ActivityThread.currentActivityThread();
- mUiContext = mSystemThread.getSystemUiContext();
-
-
- mHandlerThread = new ServiceThread(TAG,
- THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
- mHandlerThread.start();
- mHandler = new MainHandler(mHandlerThread.getLooper());
- mUiHandler = mInjector.getUiHandler(this);
-
- //...
-
- mServices = new ActiveServices(this);
- mProviderMap = new ProviderMap(this);
- mAppErrors = new AppErrors(mUiContext, this);
-
-
- // TODO: Move creation of battery stats service outside of activity manager service.
- mBatteryStatsService = new BatteryStatsService(systemContext, systemDir, mHandler);
- mBatteryStatsService.getActiveStatistics().readLocked();
- mBatteryStatsService.scheduleWriteToDisk();
- mOnBattery = DEBUG_POWER? true
- : mBatteryStatsService.getActiveStatistics().getIsOnBattery();
- mBatteryStatsService.getActiveStatistics().setCallback(this);
-
-
- mStackSupervisor = createStackSupervisor();
- mStackSupervisor.onConfigurationChanged(mTempConfig);
-
- mActivityStartController = new ActivityStartController(this);
- mRecentTasks = createRecentTasks();
- mStackSupervisor.setRecentTasks(mRecentTasks);
- mLockTaskController = new LockTaskController(mContext, mStackSupervisor, mHandler);
- mLifecycleManager = new ClientLifecycleManager();
-
- mProcessCpuThread = new Thread( "CpuTracker" )
- //...
-
- }
-
-
- private void start() {
- removeAllProcessGroups();
- mProcessCpuThread.start();
-
- mBatteryStatsService.publish();
- mAppOpsService.publish(mContext);
- Slog.d( "AppOps" , "AppOpsService published" );
- LocalServices.addService(ActivityManagerInternal.class, new LocalService());
- // Wait for the synchronized block started in mProcessCpuThread,
- // so that any other access to mProcessCpuTracker from main thread
- // will be blocked during mProcessCpuTracker initialization.
- try {
- mProcessCpuInitLatch.await();
- } catch (InterruptedException e) {
- Slog.wtf(TAG, "Interrupted wait during start" , e);
- Thread.currentThread().interrupt();
- throw new IllegalStateException( "Interrupted wait during start" );
- }
- }
The code is very long, I only captured a part of it. In the constructor, some objects are initialized, such as Context, ActivityThrad, Handler, CPU monitoring thread, and some objects such as ActivityStackSupervisor and ActivityStarter that will be used later. In the start method, the CPU monitoring thread is started, and then the battery status service and permission management service are registered. Initial work After AMS is started, it will secretly do some work when SystemServer starts the three major services. We can see it by searching for the mActivityManagerService variable: - private void startBootstrapServices() {
- //1. Initialize the power manager
- mActivityManagerService.initPowerManagement();
- //2. Set up an application instance for the system process and start it.
- mActivityManagerService.setSystemProcess();
- }
-
- private void startCoreServices() {
- // Start UsageStatsManager to query the usage of the application
- mSystemServiceManager.startService(UsageStatsService.class);
- mActivityManagerService.setUsageStatsManager(
- LocalServices.getService(UsageStatsManagerInternal.class));
- traceEnd();
- }
-
- private void startOtherServices() {
-
- //Install system Providers
- mActivityManagerService.installSystemProviders();
-
- //Start WMS and set WMS relationship for AMS
- wm = WindowManagerService.main(context, inputManager,
- mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
- !mFirstBoot, mOnlyCore, new PhoneWindowManager());
- mActivityManagerService.setWindowManager(wm);
-
- //...
- }
-
-
-
- public void setSystemProcess() {
- try {
- ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true ,
- DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
- }
- }
In the second step, the setSystemProcess method will register AMS with the ServiceManager, so that if you need to use AMS later, you can obtain it through the ServiceManager, which will be discussed below. That’s all I have to say about the startup. It’s all rather boring content, so I won’t go into detail. It’s enough to give you an impression so that if you need related knowledge in the future, you will know where to find it. AMS work content from the start-up process In order to understand the specific work of AMS, we start from the startup process of Activity. As mentioned in the app startup process above, the startActivityForResult method will go to the mInstrumentation.execStartActivity method: - //mInstrumentation.execStartActivity
- int result = ActivityManager.getService()
- .startActivity(whoThread, who.getBasePackageName(), intent,
- intent.resolveTypeIfNeeded(who.getContentResolver()),
- token, target != null ? target.mEmbeddedID : null ,
- requestCode, 0, null , options);
- checkStartActivityResult(result, intent);
-
-
- public static IActivityManager getService() {
- return IActivityManagerSingleton.get();
- }
-
- private static final Singleton<IActivityManager> IActivityManagerSingleton =
- new Singleton<IActivityManager>() {
- @Override
- protected IActivityManager create () {
- final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
- final IActivityManager am = IActivityManager.Stub.asInterface(b);
- return am;
- }
- };
As you can see, we need to get the IBinder type reference of AMS in the end. Is ServiceManager.getService(Context.ACTIVITY_SERVICE) familiar? Yes, it is the setSystemProcess method that was specifically called to register AMS in ServiceManager. Then when we want to use the methods of related services, we get the reference of the corresponding service through ServerManager. Here, we get the IActivityManager object. IActivityManager is actually the agent of AMS in the current process. The logic here is to communicate between processes through AIDL. Because these services, including the AMS we are talking about today, are in the SystemServer process, and we actually use them in our own application process, so inter-process communication is involved. Here, the Binder mechanism is used for communication. Binder, ServiceManager, this is a complete set of Binder communication processes. Not only AMS, but also other services such as WMS basically use the Binder mechanism for inter-process communication. For specific content, you can look forward to the Binder chapter mentioned later. Next, let's look at the startup process. The startActivity method of AMS is called through Binder, and then the startActivity method of ActivityStarter is called. In this method, we find a new class: - //ActivityStarter.java
- private int startActivity(...){
- ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
- callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
- resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null ,
- mSupervisor, checkedOptions, sourceRecord);
- if (outActivity != null ) {
- outActivity[0] = r;
- }
-
- //...
-
- return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
- true /* doResume */, checkedOptions, inTask, outActivity);
- }
ActivityRecord This class is translated as Activity record, so it is guessed to be related to Activity. Let's click on it to see what it contains: - final ActivityManagerService service; // owner
- final IApplicationToken.Stub appToken; // window manager token
-
- final ActivityInfo info; // all about me
- ApplicationInfo appInfo; // information about activity's app
- final int userId; // Which user is this running for ?
- final String packageName; // the package implementing intent's component
- final String processName; // process where this component wants to run
- final String taskAffinity; // as per ActivityInfo.taskAffinity
-
- private int icon; // resource identifier of activity's icon.
- private int logo; // resource identifier of activity's logo.
- private int theme; // resource identifier of activity's theme.
- int launchMode; // the launch mode activity attribute.
I have retained some commonly used attributes, and you should be able to tell what they are, such as the theme of the current Activity - theme, the token of the current Activity - apptoken, and the package name of the current Activity - packageName. So this ActivityRecord actually saves and records all the information of the Activity. Next, let's look at the process. The startActivityUnchecked method will be executed later. In this method, we can see a new class - TaskRecord. TaskRecord - private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
- ActivityRecord[] outActivity) {
-
- if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
- && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
- newTask = true ;
- result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
- } else if (mSourceRecord != null ) {
- result = setTaskFromSourceRecord();
- } else if (mInTask != null ) {
- result = setTaskFromInTask();
- } else {
- // This not being started from an existing activity, and not part of a new task...
- // just put it in the top task, though these days this case should never happen.
- setTaskToCurrentTopOrCreateNewTask();
- }
-
- }
-
- // Create a new task stack
- private void setTaskToCurrentTopOrCreateNewTask() {
- //...
- final ActivityRecord prev = mTargetStack.getTopActivity();
- final TaskRecord task = (prev != null ) ? prev.getTask() : mTargetStack.createTaskRecord(
- mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
- mIntent, null , null , true , mStartActivity, mSourceRecord, mOptions);
- addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask" );
- mTargetStack.positionChildWindowContainerAtTop(task);
- }
-
- //Add Ac to the top of the stack
- private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
- if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {
- parent.addActivityToTop(mStartActivity);
- } else {
- mStartActivity.reparent(parent, parent.mActivities. size () /* top */, reason);
- }
- }
From the code, we can see that when the Activity we start needs a new task stack (for example, the startup mode is FLAG_ACTIVITY_NEW_TASK), we will go to the setTaskToCurrentTopOrCreateNewTask method, create a new TaskRecord class, and add the current Activity to the top of the stack through the addActivityToTop method. So this TaskRecord class is a task stack class. Its function is to maintain all the Activities in the stack. Let’s take a look at the variables in this class: - final int taskId; // Unique identifier for this task.
-
- /** List of all activities in the task arranged in history order */
- final ArrayList<ActivityRecord> mActivities;
-
- /** Current stack. Setter must always be used to update the value. */
- private ActivityStack mStack;
Here are some interceptions, you can find the task id - taskId, all the ActivityRecords of the task stack - mActivities, and this one I don’t know what it is but I know it is the housekeeper used to manage all Activities and task stacks - ActivityStack. ActivityStack If you go further in the startup process, you will reach the resumeFocusedStackTopActivityLocked method of ActivityStackSupervisor: - //ActivityStackSupervisor.java
-
- /** The stack containing the launcher app. Assumed to always be attached to
- * Display.DEFAULT_DISPLAY. */
- ActivityStack mHomeStack;
-
- /** The stack currently receiving input or launching the next activity. */
- ActivityStack mFocusedStack;
-
- /** If this is the same as mFocusedStack then the activity on the top of the focused stack has
- * been resumed. If stacks are changing position this will hold the old stack until the new
- * stack becomes resumed after which it will be set to mFocusedStack. */
- private ActivityStack mLastFocusedStack;
-
-
- public ActivityStackSupervisor(ActivityManagerService service, Looper looper) {
- mService = service;
- mLooper = looper;
- mHandler = new ActivityStackSupervisorHandler(looper);
- }
-
-
- boolean resumeFocusedStackTopActivityLocked(
- ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
-
-
- if (targetStack != null && isFocusedStack(targetStack)) {
- return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
- }
-
- final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
- if (r == null || !r.isState(RESUMED)) {
- mFocusedStack.resumeTopActivityUncheckedLocked( null , null );
- } else if (r.isState(RESUMED)) {
- // Kick off any lingering app transitions form the MoveTaskToFront operation.
- mFocusedStack.executeAppTransition(targetOptions);
- }
-
- return false ;
- }
ActivityStackSupervisor is a class that manages ActivityStack and is created in the AMS construction method. In this class, you can see some task stacks, such as mHomeStack, which contains the Activity of the Launcher APP. Then take a look at what good things are stored in ActivityStack, the big housekeeper: - enum ActivityState {
- INITIALIZING,
- RESUMED,
- PAUSING,
- PAUSED,
- STOPPING,
- STOPPED,
- FINISHING,
- DESTROYING,
- DESTROYED
- }
-
-
-
- private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
-
- final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
-
- ActivityRecord mPausingActivity = null ;
-
- ActivityRecord mLastPausedActivity = null ;
You can see that in ActivityStack: - There is an enumeration ActivityState that stores all the states of the Activity.
- There are some TaskRecord and ActivityRecord lists, such as mTaskHistory - a list of task stacks that have not been destroyed, and mLRUActivities - an ActivityRecord list whose head is the least recently used Activity calculated by LRU.
- There are also ActivityRecords corresponding to some special states of Activities, such as the paused Activity and the last paused Activity.
Finally, the startup process will go to the startProcessLocked method of AMS, then communicate with the Zygote process and fork the process. I won’t go into details later. Summarize So far, we have touched upon the three important components of AMS, namely: - ActivityRecord that manages all the information of Activity.
- Manages the task stack TaskRecord of one or more ActivityRecord.
- ActivityStack, a manager that manages one or more task stacks.
Let’s draw a picture to summarize: In fact, there are many logics in AMS. Not only Activity, but also some startup scheduling processes of the other three components are completed through AMS, as well as content related to Activity task stack (including taskAffinity, allowTaskReparenting), which will be discussed in detail later. This article is reprinted from the WeChat public account "Ma Shang Ji Mu", which can be followed through the following QR code. To reprint this article, please contact the WeChat public account "Ma Shang Ji Mu". |