1. Overview of Activity Manager
2. The mechanism and implementation of AMS
Activity Manager Service (AMS) is a system process provided by Android to manage the running status of Activity and other components.
The main role of AMS is:
1.Activity and other three components: running state management, process management and memory management (main)
2. Query component's current performance
3. Provide queries for system runtime
2. The mechanism and implementation of AMS
2.1 AMS directory structure
The main code of AMS is located in:
frameworks/base/core/java/android/app frameworks/base/services/core/java/com/android/server/am
2.2 Class Diagram of AMS
Activity Managerde consists of the following six parts:
1) Binder Interface: Interface for Interprocess Communication Provided by Ibinder and Binder
2) Service Interface: An interface that provides system services by Iinterface and IActivityManager, where IActivityManager is not converted through IActivityManager.aidl
3) Service Center: Activity Manager Native inherits from Binder and implements IactivityManager. It provides the transformation function between service interface and Binder interface, stores service proxy objects internally and provides getDefault() method to return to service proxy.
public abstract class ActivityManagerNative extends Binder implements IActivityManager { static public IActivityManager getDefault() { return gDefault.get(); } private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { protected IActivityManager create() { // Find the reference object of AMS from SM. activity is the name of AMS in SM. IBinder b = ServiceManager.getService("activity"); // Converting an AMS reference object to a proxy object IActivityManager am = asInterface(b); return am; } }; static public IActivityManager asInterface(IBinder obj) { if (obj == null) { return null; } IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor); if (in != null) { return in; } //obj is an AMS reference object return new ActivityManagerProxy(obj); } }
4) Service Agent: Implemented by Activity Manager Proxy to communicate with system services provided by Server. The ActivityManagerProxy class contains IBinder mRemote, which is initially pointed to a reference object of AMS in the construction method. The killUid() method shows that the interface provided by Activity Manager Proxy is initiated by this AMS reference object, completed by the remote AMS and returned the result.
public ActivityManagerProxy(IBinder remote) { mRemote = remote; } public void killUid(int appId, int userId, String reason) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeInt(appId); data.writeInt(userId); data.writeString(reason); mRemote.transact(KILL_UID_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); }
5) Client: Encapsulate part of the interface by Activity Manager for Client invocation. Activity Manager obtains the IActivityManager interface by calling ActivityManager Native. getDefault (), which is the reference of the ActivityManager Proxy object, and then calls the method of remote service through the proxy object.
//ActivityManager.java public List<RunningAppProcessInfo> getRunningAppProcesses() { try { return ActivityManagerNative.getDefault().getRunningAppProcesses(); } catch (RemoteException e) { return null; } }
6) Server: Implemented by Activity Manager Service, through system services on the server side.
2.2.1 Activity manages related class relationships
The box in the diagram can be understood as an inclusion relationship: for example, a Task Record contains multiple Activity Records; the wiring in the diagram can be understood as an equivalent relationship; for example, an Activity Record can be referenced by Task Record and Process Record, both of which manage Activity Record from different dimensions.
- Activity Record is the smallest unit of activity management, which corresponds to a user interface.
- TaskRecord is also a stack management structure. Each TaskRecord may have one or more Activity Records. ActiveyRecord at the top of the stack represents the currently visible interface.
- ActivityStack is a stack management structure. Each ActivityStack may have one or more TaskRecords. TaskRecords at the top of the stack represent the currently visible tasks.
- ActivityStack Supervisor manages multiple ActivityStacks, but currently there is only one Focused ActivityStack.
- ProcessRecord records all ActivityRecords belonging to a process, and ActivityRecords running in different TaskRecord s may belong to the same ProcessRecord.
2.2.2 Activity Management Related Data Structures
ActivityRecord
ActivityRecord is the basic unit of AMS scheduling activity. It needs to record the static characteristics of Activity defined in Android Manifest. xml, and also the state changes of Activity when it is scheduled, so ActivityRecord has many attributes.
attribute | describe |
---|---|
ActivityInfo | Information parsed from the < activity > tag, including launchMode, permission, task Affinity, etc. |
mActivityType | There are three types of Activity: Application_Activity_TYPE (application), HOME_Activity_TYPE (desktop), RECENTS_Activity_TYPE (recently used) |
appToken | Identification of Current ActivityRecord |
packageName | The package name currently belongs to, which is statically defined by <activity>. |
processName | Most of the current process names are statically defined by <activity>, but there are exceptions. |
taskAffinity | Activities with the same task Affinity are assigned to the same task stack |
intent | Start Intent for Current Activity |
launchedFromUid | Launch the UID of the current Activity, the UID of the initiator |
launchedFromPackage | Launch the package name of the current Activity, that is, the initiator's package name |
resultTo | In the current ActivityRecord view, resultTo represents the last ActivityRecord that started it, and when another ActivityRecord needs to be started, it passes itself as resultTo to the next ActivityRecord. |
state | The state of the ActivityRecord, with an initial value of ActivityState.INITIALIZING |
app | Host process of ActivityRecord |
task | Host Task Stack of ActivityRecord |
inHistory | Identify whether the current ActivityRecord has been placed on the task stack |
frontOfTask | Identify whether the current Activity Record is at the root of the task stack, that is, whether it is the first Activity Record to enter the task stack |
newIntents | Intent array for temporarily storing Intent that has not yet been scheduled to the application process Activity |
Since ActivityRecord is a basic data structure, its behavior is relatively small, mostly some functions used to determine and update the current status of ActivityRecord:
behavior | describe |
---|---|
putInHistory(), takeFromHistory(), isInHistory() | Based on the inHistory attribute, determine and update the status value of ActivityRecord in the task stack |
isHomeActivity(), isRecentsActivity(), isApplicationActivity() | Determine the type of Activity based on the mActivityType attribute |
setTask() | Setting up the Host Task Stack of ActivityRecord |
deliverNewIntentLocked() | Continue to distribute Intent to the current ActivityRecord. In some scenarios, ActivityRecord at the top of the task stack continues to accept new Intents (such as the same Activity launched in singleTop mode), which triggers the scheduling Activity.onNewIntent() function. |
addNewIntentLocked() | If Intent is not dispatched to the application process, an element is added to the newIntents array through this function. |
TaskRecord
TaskRecord is responsible for managing multiple Activity Records. TaskRecord is the task and task stack described in this paper. When starting Activity, you need to find the host task stack of Activity, and if it does not exist, you need to create a new one, which means that all Activity Records must have hosts. TaskRecord has a one-to-many relationship with ActivityRecord, whose properties include an array of ActivityRecords; at the same time, TaskRecord also needs to maintain the state of the task stack itself.
attribute | describe |
---|---|
taskid | Unique Identification of TaskRecord |
taskType | The type of task stack, which is equivalent to the type of ActivityRecord, is determined by the first ActivityRecord of the task stack. |
intent | The Intent of the first Activity launched in the current task stack will be recorded. If there is the same Intent later, it will match the Intent of the existing task stack. If it matches, there is no need to create a new TaskRecord. |
realActivity, origActivity | Activeness to start the task stack is represented by the CompentName. Real and orig are used to distinguish between activities with alias. If the Activity defined in Android Manifest. XML is an alias, then real is an alias of Activity, and orig is an alias of real Activity. |
affinity | TaskRecord records the affinity of Activity, which matches affinity from the existing task stack when it is subsequently launched, and if it matches, no new TaskRecord is required. |
rootAffinity | The affinity of the bottom Activity in the record task stack, once set, does not change |
mActivities | This is one of the most important attributes of TaskRecord. TaskRecord is a stack structure. The element of the stack is ActivityRecord. Its internal implementation is an array of mActivities. |
stack | ActivityStack where TaskRecord is currently located |
TaskRecord's behavior focuses on the management of TaskRecord itself: adding/deleting/changing/looking up elements in the task stack.
behavior | describe |
---|---|
getRootActivity(), getTopActivity() | Task stacks have roots and tops, which can be used to retrieve ActivityRecords at the roots and top, respectively. The process of acquisition is to traverse TaskRecord.mActivities, which is considered valid if the status of ActivityRecord is not finishing. |
topRunningActivityLocked() | Although it also traverses the task stack from top to bottom to get the top ActivityRecord, this function is different from getTopActivity(): the input parameter notTop indicates that the notTop activity Record needs to be excluded in the traversal process; |
addActivityToTop(), addActivityAtBottom() | Add ActivityRecord to the top or bottom of the task stack |
moveActivityToFrontLocked() | This function moves an ActivityRecord to the top of TaskRecord by deleting the existing one and adding a new one to the top of the stack. |
setFrontOfTask() | An attribute of ActivityRecord is frontOfTask, which indicates whether ActivityRecord is the root Activity of TaskRecord. This function sets the frontOfTask property of all ActivityRecords in TaskRecord, traverses from the bottom of the stack to the top. The frontOfTask property of the first ActivityRecord that is not in the finishing state is set to true, and the others are set to false. |
performClearTaskLocked() | Clear Activity Record from TaskRecord. When the Activity is started, the Intent.FLAG_ACTIVITY_CLEAR_TOP parameter is used, and other Activity Records above the Activity Record to be started are cleared in the host task stack. |
ActivityStack
ActivityStack is responsible for managing multiple task stacks (TaskRecords), which is a stack structure with elements in the stack being TaskRecords. Each activity will have a state at a specific time, such as display, destruction, etc. In the application process, these state changes are in the execution of Activity's life cycle function; in the system process, these state changes need to be driven by Activity Stack. Activity's state is defined by the enumeration class ActivityState:
enum ActivityState { INITIALIZING, RESUMED, PAUSING, PAUSED, STOPPING, STOPPED, FINISHING, DESTROYING, DESTROYED }
From INITIALIZING to DESTROYED, the defined state values indicate the direction of Activity life cycle.
attribute | describe |
---|---|
stackId | Each ActivityStack has a number, increasing from zero. The number is 0, indicating the ActivityStack where the desktop (Launcher) is located, called Home Stack. |
mTaskHistory | The TaskRecord array, the ActivityStack stack, is implemented through this array |
mPausingActivity | Activity in Pausing state when activity switch occurs |
mResumedActivity | Activity Record currently in Resumed state |
mStacks | ActivityStack is bound to a display device, such as a mobile phone screen, projector, etc. In AMS, the class ActivityDisplay is used to abstractly represent a display device, and ActivityDisplay.mStacks represents all ActivityStacks currently bound to the display device. When a binding operation is performed, the property ActivityStack.mStacks is assigned to ActivityDisplay.mStacks, otherwise, ActivityStack.mStacks is null. In short, when mStacks are not null, it means that the current ActivityStack is bound to a display device. |
The change of activity state is not only to assign a state value to ActivityRecord.state, but also to adjust the stack: the previous Activity will be destroyed or moved to the background, and the activity to be displayed will be moved to the top of the stack. This adjustment involves a lot of work.
behavior | describe |
---|---|
findTaskLocked() | The function is to find the Task Record where the target Activity Record (target) is located. If it is found, it returns the Active Record at the top of the stack. Otherwise, it returns null. |
findActivityLocked() | According to the parameters Intent and ActiveyInfo, you can get an Activity package name, which traverses all Activities in the ActivityStack from the top to the bottom of the stack, and returns if the package name matches successfully. |
moveToFront) | This function is used to move the current ActivityStack to the foreground and call some other decision functions in ActivityStack when it is executed. |
isAttached() | Used to determine whether the current ActivityStack has been bound to the display device |
isOnHomeDisplay() | Used to determine whether the current default display device (Display.DEFAULT_DISPLAY), usually, the default display device is the mobile phone screen. |
isHomeStack() | Used to determine whether the current Activity Stack is Home Stack, that is, whether the current display is a desktop (Launcher or Recent Task) |
moveTaskToFrontLocked() | This function is used to move the specified task stack to the front of the current ActivityStack. When the Activity status changes, the task stack in the existing ActivityStack needs to be adjusted, and the host task stack to be displayed needs to be moved to the front desk. |
insertTaskAtTop() | Insert tasks into the top of the ActivityStack stack |
ActivityStack also has a number of activities related to migrating Activity status:
startActivityLocked(), resumeTopActivityLocked(), completeResumeLocked(), startPausingLocked(), completePauseLocked(), stopActivityLocked(), activityPausedLocked(), finishActivityLocked(), activityDestroyed Locked (), which are closely related to the life cycle scheduling of Activity.
ActivityStackSupervisor
The responsibility of the ActivityStack Supervisor is to manage multiple ActivityStacks.
behavior | describe |
---|---|
setFocusedStack() | Set the current focus ActivityStack |
startHomeActivity() | Start the desktop |
ActivityStack Supervisor has many similar behaviors to ActivityStack functions, but it operates on multiple ActivityStacks. For example, findTaskLocked(), findActivityLocked(), topRunning ActivityLocked (), ensureActivities VisibleLocked (), etc.
ProcessRecord
AMS uses the data structure of ProcessRecord to maintain the state information of the process when it runs. When a system_process is created or applied, a ProcessRecord is initialized through AMS.
attribute | describe |
---|---|
BatteryStats | Interface of Electricity Statistics |
ApplicationInfo | Application Info for system processes is data parsed from the android package; Application Info for applications is data parsed from android Manifest. XML |
Process Name | Process name |
UID | The UID of the process. The UID of the system process is 1000(Process.SYSTEM_UID); the UID of the application process is allocated from 10000(Process.FIRST_APPLICATION_UID). |
maxAdj, curAdj, setAdj | Various OOM Adjustment Values |
lastPss, lastPssTime | Physical memory (PSS) is related. When objects are created or destroyed in the process, PSS-related properties are updated. |
activities, services, receivers | Android components in a process may need to be updated as the process runs. For example, when Activity is started, ProcessRecord.activies adds an instance; when destroyed, the corresponding instance is deleted from activities. |
pkgList | Packages running in process |
thread | This property is an object of type IApplicationThread |
ProcessRecord has two states of "Active" and "Inactive", which are activated only when it is bound to an actual process. When the binding is successful, the thread attribute is assigned to indicate that ProcessRecord has been activated. After activation, AMS can manage the application process through this interface, such as activating Activity, dispatching broadcast, etc.
behavior | describe |
---|---|
makeActive() | Set ProcessRecord to Activated State |
makeInactive() | Set ProcessRecord to an inactive state |
addPackage() | Adding packages to ProcessRecord |
2.3 ActvityManager Method Communication Model
Taking the getRunningAppProcesses method as an example, the sequence diagram is as follows:
2.4 AMS startup process
2.4.1 Phase 1: Start Activity Manager Service
AMS is one of the Java system services launched by System Server. In the system start-up stage, the AMS-related parts mainly include the following stages.
2.4.1 Phase 1: Start Activity Manager Service
//SystemServer.java private void startBootstrapServices() { // Activity manager runs the show. mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService(); mActivityManagerService.setSystemServiceManager(mSystemServiceManager); mActivityManagerService.setInstaller(installer); // Now that the power manager has been started, let the activity manager // initialize power management features. mActivityManagerService.initPowerManagement(); // Set up the Application instance for the system process and get started. mActivityManagerService.setSystemProcess(); }
You can see that the entry point of AMS is ActivityManagerService.Lifecycle.class.
//AMS.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(); } public ActivityManagerService getService() { return mService; } }
The class Lifecycle is an internal class of the ActivityManagerService class. You can see that an instance of ActivityManagerService is created in the Lifecycle constructor, and then the onStart() method calls the start() method of ActivityManagerService to start the AMS service.
//AMS.java public ActivityManagerService(Context systemContext) { mContext = systemContext; mFactoryTest = FactoryTest.getMode(); mSystemThread = ActivityThread.currentActivityThread(); Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass()); // Create threads for message processing // Service Thread is designed to provide looper runtime environment for system service mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/); mHandlerThread.start(); // Create Handler and associate looper mHandler = new MainHandler(mHandlerThread.getLooper()); // Create a thread named "android.ui" through the UiThread class, which also inherits from ServiceThread // That means creating a looper // AMS creates a UiHandler object that associates the Handler with Looepr in the android.ui thread mUiHandler = new UiHandler(); // Creating a front-end broadcast receiver that runs for more than 10 seconds will give up execution mFgBroadcastQueue = new BroadcastQueue(this, mHandler, "foreground", BROADCAST_FG_TIMEOUT, false); // Create a background broadcast receiver that runs for more than 60 seconds and abandons execution mBgBroadcastQueue = new BroadcastQueue(this, mHandler, "background", BROADCAST_BG_TIMEOUT, true); mBroadcastQueues[0] = mFgBroadcastQueue; mBroadcastQueues[1] = mBgBroadcastQueue; // Creating Objects to Manage Service mServices = new ActiveServices(this); // Create an object to manage component provider mProviderMap = new ProviderMap(this); File dataDir = Environment.getDataDirectory(); File systemDir = new File(dataDir, "system"); systemDir.mkdirs(); //Create the service BatteryStatsService mBatteryStatsService = new BatteryStatsService(systemDir, mHandler); mBatteryStatsService.getActiveStatistics().readLocked(); mBatteryStatsService.scheduleWriteToDisk(); mOnBattery = DEBUG_POWER ? true : mBatteryStatsService.getActiveStatistics().getIsOnBattery(); mBatteryStatsService.getActiveStatistics().setCallback(this); //Create a process statistics service with information stored in directory / data/system/procstats mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats")); // Privilege management, allowing users to manually revoke and grant permissions requested by an app // Recorded in / data/system/appops.xml // This service is widely used to check whether an app has an api to operate on mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler); // Open / data/system/urigrants.xml to manage URI permissions (related to content provid read and write) mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml")); // User 0 is the first and only user that runs at boot. mStartedUsers.put(UserHandle.USER_OWNER, new UserState(UserHandle.OWNER, true)); mUserLru.add(UserHandle.USER_OWNER); updateStartedUserArrayLocked(); ...... //Initialization of tracker for process CPU usage mProcessCpuTracker.init(); mCompatModePackages = new CompatModePackages(this, systemDir, mHandler); // Create Intent Firewall // Intent filtering security mechanism, when using intent to start activities, service s, and send broadcasts, will check whether it is allowed to execute through this mechanism? // Only when allowed can it be really implemented. mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler); mRecentTasks = new RecentTasks(this); // Objects that create Activity stacks mStackSupervisor = new ActivityStackSupervisor(this, mRecentTasks); mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, mRecentTasks); // Create threads that count cpu usage mProcessCpuThread = new Thread("CpuTracker") { @Override public void run() { ...... } }; // Adding services to Watchdog monitoring Watchdog.getInstance().addMonitor(this); Watchdog.getInstance().addThread(mHandler); }
It can be seen from the constructor code that besides the main thread, three threads have been created, one for AMS Handler message processing named after TAG, one for android.ui, processing ui handler, and the last for CpuTracker thread, which is used to count cpu usage.
In addition to creating threads, AMS has created four main components: Activity,Service, Broadcast and ContentProvider management objects and some internal objects.
Let's look at the AMS start() method:
//AMS.java private void start() { // Remove all process groups Process.removeAllProcessGroups(); //Start the CpuTracker thread mProcessCpuThread.start(); //Register Battery Statistics Service in SM mBatteryStatsService.publish(mContext); // Register AppOpsService into SM, which provides revocation and granting of android app privileges mAppOpsService.publish(mContext); Slog.d("AppOps", "AppOpsService published"); //Create Local Service and add it to Local Services LocalServices.addService(ActivityManagerInternal.class, new LocalService()); }
Note in the start() method that a service: LocalService is created and added to the Local Services that can only be used by the process.
2.4.2 Phase 2: Call the setSystemProcess method
System Server calls the AMS setSystemProcess() method immediately after starting AMS.
//SystemServer.java public void setSystemProcess() { try { // Add AMS to Service Manager with the name "activity" ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true); // Register a service named "procstats" in Service Manager for dump, which is to get process status information, such as the latest running time, etc. ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats); ServiceManager.addService("meminfo", new MemBinder(this));// Get process memory usage status ServiceManager.addService("gfxinfo", new GraphicsBinder(this));// Get the status of each process using a graphical accelerator card ServiceManager.addService("dbinfo", new DbBinder(this)); Get the database information of the process if (MONITOR_CPU_USAGE) { ServiceManager.addService("cpuinfo", new CpuBinder(this));// Getting process CPU information } ServiceManager.addService("permission", new PermissionController(this));// Used to check call permissions ServiceManager.addService("processinfo", new ProcessInfoService(this));// Used to get the status of the process. For example, is it a background process? //The services registered above can use adb shell dumpsys + service name to dump some system information //Query the Application Info information of the application named "android" package, namely framework-res.apk ApplicationInfo info = mContext.getPackageManager().getApplicationInfo("android", STOCK_PM_FLAGS); mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader()); synchronized (this) { //Here framework-res.apk is added to the process management system of AMS and stored in mPidsSelfLocked. ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0); app.persistent = true; app.pid = MY_PID; //Process ID of System Server app.maxAdj = ProcessList.SYSTEM_ADJ; app.makeActive(mSystemThread.getApplicationThread(), mProcessStats); synchronized (mPidsSelfLocked) { mPidsSelfLocked.put(app.pid, app); } //Add an app that needs to update Lru and OomAdj updateLruProcessLocked(app, false, null); updateOomAdjLocked(); } } catch (PackageManager.NameNotFoundException e) { throw new RuntimeException( "Unable to find android system package", e); } }
The functions of the setSystemProcess method can be roughly divided into three parts:
1) Registration service. First, AMS is registered with Service Manager, and then several services related to system performance debugging are registered with Service Manager. These performance-related services will eventually invoke AMS methods.
2) Query and process Application Info.
3) Create and process ProcessRecord. Call the newProcessRecordLocked method of AMS to create an object of type ProcessRecord and save the information of that object.
2.4.3 Phase 3: Call the installSystemProviders method
//AMS.java public final void installSystemProviders() { List<ProviderInfo> providers; synchronized (this) { ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID); providers = generateApplicationProvidersLocked(app); if (providers != null) { for (int i=providers.size()-1; i>=0; i--) { ProviderInfo pi = (ProviderInfo)providers.get(i); if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) { providers.remove(i); } } } } if (providers != null) { mSystemThread.installSystemProviders(providers); } mCoreSettingsObserver = new CoreSettingsObserver(this); }
2.4.4 Phase 4: Call the system Ready method
The main work of AMS's install System Providers method can be divided into the following two steps:
1) Call GeneeApplication Providers Locked to query the information of Content Provider running in the system process with the UID of SYSTEM_UID, that is Settings Provider.
2) Call ActivityThread. installSystem Providers to install Content Provider
2.4.4 Phase 4: Call the system Ready method
Note: Reasons that still exist after the recent mission restart
//AMS.java public void systemReady(final Runnable goingCallback) { ...... synchronized(this) { // The default value of mSystemReady is false, which is not executed here if (mSystemReady) { // If we're done calling all the receivers, run the next "boot phase" passed in by the SystemServer if (goingCallback != null) { goingCallback.run(); } return; } //Obtain idle controller, which is mainly used in the control of broadcasting transmission. mLocalDeviceIdleController = LocalServices.getService(DeviceIdleController.LocalService.class); //This part of the code is very important. Here is the profile of the user ID loaded into the system for later permission checking. This is more important information, especially in android. //In the case of multiple users, different privileges are granted according to the user's ID configuration. updateCurrentProfileIdsLocked(); //This is only after android 5.0. The main work of this part is to rebuild task s with persistent tags. Support with persistent in android 5.0 //Tagged tasks. When the system shuts down, the system stores its information in the xml file in the system's / data/system/recent_tasks directory. //The task is recreated through these files when the system restarts. mRecentTasks.clear(); mRecentTasks.addAll(mTaskPersister.restoreTasksLocked()); mRecentTasks.cleanupLocked(UserHandle.USER_ALL); mTaskPersister.startPersisting();
The data/system/recent_tasks/<task_id>_task.xml file is as follows:
Note: Send PRE_BOOT_COMPLETED broadcast
Continue the system Ready method:
Note: Send PRE_BOOT_COMPLETED broadcast
//AMS.systemReady // Check to see if there are any update receivers to run. if (!mDidUpdate) { if (mWaitingUpdate) { return; } final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>(); mWaitingUpdate = deliverPreBootCompleted(new Runnable() { public void run() { synchronized (ActivityManagerService.this) { mDidUpdate = true; } showBootMessage(mContext.getText(R.string.android_upgrading_complete),f alse); writeLastDonePreBootReceivers(doneReceivers);//Store qualified broadcasts in the data/system/called_pre_boots.dat file systemReady(goingCallback); } }, doneReceivers, UserHandle.USER_OWNER); if (mWaitingUpdate) { return; } mDidUpdate = true; } mAppOpsService.systemReady(); mSystemReady = true; }
The main part of this code is to complete some updates, such as reorganizing data, when the system module or the own app need to boot.
The delivery PreBootCompleted method is called to send a message to ACTION_PRE_BOOT_COMPLETED to notify these modules. This message will only be sent to system-level apps, not to third-party apps. The broadcast will only be processed once. Finally, set mSystem Ready to true.
Continue the system Ready method:
//AMS.systemReady ArrayList<ProcessRecord> procsToKill = null; synchronized(mPidsSelfLocked) { //mPidsSelfLocked stores current running application process information with pid as the key for (int i=mPidsSelfLocked.size()-1; i>=0; i--) { ProcessRecord proc = mPidsSelfLocked.valueAt(i); if (!isAllowedWhileBooting(proc.info)){ // Check whether the process has persistent flags if (procsToKill == null) { procsToKill = new ArrayList<ProcessRecord>(); } procsToKill.add(proc);// Join the list to be cleaned up } } } synchronized(this) { if (procsToKill != null) { for (int i=procsToKill.size()-1; i>=0; i--) { ProcessRecord proc = procsToKill.get(i); Slog.i(TAG, "Removing system update proc: " + proc); removeProcessLocked(proc, true, false, "system update done"); } } // Now that we have cleaned up any update processes, we are ready to start launching real processes and know that // we won't trample on them any more. mProcessesReady = true; }
Note: Skip the boot wizard method
The purpose of this code is to find the application processes that have been started and kill them. In the system startup phase, some processes will be pre-started due to upgrades and other reasons, and these processes need to be cleaned up here.
Note: Skip the boot wizard method
//AMS.systemReady Slog.i(TAG, "System now ready"); //Skip the boot Guide if(SystemProperties.getInt("ro.huaqin_mmitest_support",0) == 1 && (!HqframeworkStatic.isCitFlagWirted() || !HqframeworkStatic.isSNWrited())){ Slog.i(TAG, "Dismiss setupwizard for MMI auto test"); //Skip the boot wizard and set DEVICE_PROVISIONED to 1 Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1); Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1); } synchronized(this) { // Make sure we have no pre-ready processes sitting around. if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) { ......//Elimination of factory mode processing } } retrieveSettings(); loadResourcesOnSystemReady();
retrieveSettings mainly reads the following four configuration information from Settings:
debug_app: Application package name to debug
wait_for_debugger: If the value is 1, it means that the debugging app needs to wait for the debugger before it starts normally.
always_finish_activities: A value of 1 indicates that activity is no longer needed and that the system needs to clean them up immediately, which can be set in the setting developer option.
debug.force_rtl: A value of 1 indicates that the system is set to a right-to-left mode (some Western Asian languages, such as Hebrew).
//AMS.systemReady synchronized (this) { readGrantedUriPermissionsLocked(); } if (goingCallback != null) goingCallback.run();
Call the run method in the Runnable object defined in the System Server code
Note: Start the FRP service
//SystemServer.java mActivityManagerService.systemReady(new Runnable() { @Override public void run() { Slog.i(TAG, "Making services ready"); // M: Mobile Manager Service try { if (momF != null) momF.systemReady(); } catch (Throwable e) { reportWtf("making MobileManagerService ready", e); } mSystemServiceManager.startBootPhase( SystemService.PHASE_ACTIVITY_MANAGER_READY); try { mActivityManagerService.startObservingNativeCrashes(); } catch (Throwable e) { reportWtf("observing native crashes", e); } Slog.i(TAG, "WebViewFactory preparation"); WebViewFactory.prepareWebViewInSystemServer(); /// M: @{// Start FRP Service Intent FRPIntent = new Intent().setPackage("com.google.android.gms") .setAction("com.google.android.gms.auth.frp.FRP_BIND").addCategory("android.intent.category.DEFAULT"); context.startService(FRPIntent); ///M: @} try { startSystemUi(context); } catch (Throwable e) { reportWtf("starting System UI", e); } ...... Watchdog.getInstance().start();
This code mainly does the following work:
- Start the System UI Service service
- systemReady Method for Executing Other System Services
- Start software Watchdog
Note: FRP services in GMS packages are also started at this stage.
Continue the AMS.systemReady method
Note: Start desktop / Persist applications
//AMS.systemReady mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START, Integer.toString(mCurrentUserId), mCurrentUserId); mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START, Integer.toString(mCurrentUserId), mCurrentUserId); // Start the current user mSystemServiceManager.startUser(mCurrentUserId); synchronized (this) { if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) { try { List apps = AppGlobals.getPackageManager().getPersistentApplications(STOCK_PM_FLAGS); if (apps != null) { int N = apps.size(); int i; for (i=0; i<N; i++) { ApplicationInfo info = (ApplicationInfo)apps.get(i); if (info != null && !info.packageName.equals("android")) { //Start persisitent application addAppLocked(info, false, null /* ABI override */); } } } } catch (RemoteException ex) { // pm is in same process, this will never happen. } } /// M: power-off Alarm feature @{ // Start up initial activity. mBooting = true; if (!PowerOffAlarmUtility.isAlarmBoot()) { // Start the launcher desktop startHomeActivityLocked(mCurrentUserId, "systemReady"); } /// @} if (!Build.isBuildConsistent()) { Slog.e(TAG, "Build fingerprint is not consistent, warning user"); mUiHandler.obtainMessage(SHOW_FINGERPRINT_ERROR_MSG).sendToTarget(); } long ident = Binder.clearCallingIdentity(); try { Intent intent = new Intent(Intent.ACTION_USER_STARTED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId); intent = new Intent(Intent.ACTION_USER_STARTING); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId); broadcastIntentLocked(null, null, intent, null, new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { } }, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } catch (Throwable t) { Slog.wtf(TAG, "Failed sending first user broadcasts", t); } finally { Binder.restoreCallingIdentity(ident); } /// M: power-off Alarm feature @{ if (PowerOffAlarmUtility.isAlarmBoot()) { postFinishBooting(false, true); /// M: ALPS02042538 Avoid re-do odex after alarm snooze. markBootComplete(); Slog.v(TAG, "power off alarm enabled"); mPowerOffAlarmUtility.launchPowrOffAlarm(false, false); return; } /// @} mStackSupervisor.resumeTopActivitiesLocked(); sendUserSwitchBroadcastsLocked(-1, mCurrentUserId); } }
2.4.5 Phase 5: Transmission of BOOT_COMPLETED Broadcasting
The purpose of this code is to start the app with FLAG_PERSISTENT tag, and start the application by calling the addAppLocked method, which will be described in detail later when we analyze the process management of AMS. Then we start our familiar launcher by calling the startHomeActivityLocked method, which first looks for the current launcher starter and then starts the corresponding starter (because the user may download and install a third-party starter). After launcher starts, the system calls AMS.finishBooting() to send ACTION_BOOT_COMPLETE message to notify the app system of the completion of startup.
2.4.5 Phase 5: Transmission of BOOT_COMPLETED Broadcasting
final void finishBooting() { // Let system services know. mSystemServiceManager.startBootPhase(SystemService.PHASE_BOOT_COMPLETED); /// M: performance improvment, to avoid executing addBootEvent. mBootProfIsEnding = true; synchronized (this) { if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) { for (int i=0; i<mStartedUsers.size(); i++) { UserState uss = mStartedUsers.valueAt(i); if (uss.mState == UserState.STATE_BOOTING) { uss.mState = UserState.STATE_RUNNING; final int userId = mStartedUsers.keyAt(i); Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); // If this is an ordered broadcast, don't allow receivers to abort the broadcast. intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); broadcastIntentLocked(null, null, intent, null, new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { synchronized (ActivityManagerService.this) { requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false); } } }, 0, null, null, new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, AppOpsManager.OP_NONE, null, true/* ordered*/, false, MY_PID, Process.SYSTEM_UID, userId); } } scheduleStartProfilesLocked(); } } } private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { intent = new Intent(intent); // If set, this intent will not match any components in packages that are currently stopped. intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); //... Filter caller and partial broadcast and broadcast priority processing code return ActivityManager.BROADCAST_SUCCESS; }
The registration order of BOOT_COMPLETED is arranged according to the directory scan at the start of PMS, that is, the order of scanDirLI, as follows:
/vendor/overlay /custom/framework /system/framework /system/ priv-app /system/app ......
2.5 AMS Start app Process
Installation in the same directory comes first. The applications installed during the running process are still registered after starting the scan. So if a static receiver with the same priority wants to receive the broadcast first, it has to modify the package name to display it in front.
2.5 AMS Start app Process
The overall flow chart of AMS startup app is as follows:
Among them, AMS process is actually a System Server process, because AMS is only a service initiated by System Server, running in a thread of System Server.
When the user clicks on the application icon in Launcher program, he notifies Activity Manager Service to start the main activity of the application. If Activity Manager Service finds that the application has not yet started, he notifies Zygote process to hatch the application process, and then executes the main method of Activity Thread in the newly hatched application process. The application process then notifies the Activity Manager Service that the application process has started and the Activity Manager Service saves a proxy object of the application process so that the Activity Manager Service can control the application process through this proxy object. Then the Activity Manager Service notifies the application process to create an instance of the main activity and executes its life cycle method, such as Ond Creation. Te () and other methods.
2.5.1 APP starts the execution process on Client side
//Activity.java public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) {//Non-child Activity Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } if (requestCode >= 0) { mStartedActivity = true; } ...... } }
This involves mInstrumentation, mMainThread, mToken objects
- mInstrumentation is an object of Instrumentation type that monitors the interaction between applications and systems (mainly Activity Manager). Starting application Activity requires interaction with AMS, so Instrumentation agent is required to monitor start request processing.
- mToken is an Ibinder-type object, which is essentially a Binder Proxy through which the current Activity (Launcher here) in AMS can be accessed. ActivityRecord records information about current activities, which AMS needs to obtain
- MMainThread is an object of type ActivityThread, representing the main thread of the application (in this case Launcher's main thread). An object of type ApplicationThread is returned through the mMainThread.getApplicationThread() method, which defines the method for scheduling the current Activity. ExcStartActivity passes it into AMS, so AMS can schedule the current Activity across processes via Application Thread (Launcher, in this case, the result of scheduling is to suspend Launcher).
Note: Application Thread class diagram
AMS manages the application process through the IApplication Thread interface. The Application Thread class implements the IApplication Thread interface, realizes the operation of the management application, and the Application Thread object runs in the application process. ApplicationThreadProxy object is the proxy object of ApplicationThread object in AMS thread (AMS thread runs in system_server process). AMS calls the functions provided by ApplicationThreadProxy object, such as letting the application process start an Activity.
The scheduleLaunchActivity method in Application Thread is as follows:
//ApplicationThread.java public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, Configuration overrideConfig, CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor, int procState, Bundle state, PersistableBundle persistentState, List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents, boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) { updateProcessState(procState, false); ActivityClientRecord r = new ActivityClientRecord(); r.token = token; r.ident = ident; r.intent = intent; ...... updatePendingConfiguration(curConfig); sendMessage(H.LAUNCH_ACTIVITY, r); }
The method as a Binder server is actually done by calling the following two methods of the ActivityThread class. (ApplicationThread is the ActivityThread internal class)
private void sendMessage(int what, Object obj) { sendMessage(what, obj, 0, 0, false); } private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { if (DEBUG_MESSAGES) Slog.v( TAG, "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj); Message msg = Message.obtain(); msg.what = what; msg.obj = obj; msg.arg1 = arg1; msg.arg2 = arg2; if (async) { msg.setAsynchronous(true); } mH.sendMessage(msg); }
The handleMessage() method for processing messages is defined in the inner class H (inherited from Handler, mH is the object of H) of the ActivityThread class.
public void handleMessage(Message msg) { switch (msg.what) { case LAUNCH_ACTIVITY: { final ActivityClientRecord r = (ActivityClientRecord) msg.obj; r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null); } break;
handleLaunchActivity is a method defined in the ActivityThread class. That is to say, the actual processing is done in the ActivityThread class, which is only responsible for communication.
The Handler mechanism is used here to execute the binder request in an asynchronous manner. After understanding this process, when analyzing the interfaces in the ApplicationThread class, you no longer need to care about the messaging process, and look directly for the corresponding methods in the ActivityThread class.
Note: The method defined in ApplicationThread starts with "schedule" and the corresponding method in the ActivityThread class starts with "handle".
The flow chart above finally calls ActivityManagerProxy.startActivity, which essentially calls BinderProxy.transact to send the START_ACTIVITY_TRANSACTION command to the Binder driver, which switches the processing logic from Launcher's process to AMS's process.
2.5.2 APP starts the execution process on Server side
2.5.2.1 Pre-start
The main function of the ActivityStackSupervisor.startActivityMayWait() method is to query the Activity matching Intent in the system and call ActivityStackSupervisor. startActivityLocked to start the Activity.
- ActivityStackSupervisor. startActivityLocked
//ActivityStackSupervisor.java final int startActivityLocked( IApplicationThread caller,//AMS can interact with the originator through this parameter Intent intent,// Start intent for activity String resolvedType, // The type of intent, MIME type ActivityInfo aInfo,//Information about the activity to start IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo,//Used to receive the results of startActivityForResult, launcher launches app, which is useless in the case of null String resultWho, int requestCode,// Afferent-1 int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags,// Input 0 Bundle options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container, // When starting app, null is passed in TaskRecord inTask) // When starting app, the input is null { int err = ActivityManager.START_SUCCESS; ProcessRecord callerApp = null; if (caller != null) { callerApp = mService.getRecordForAppLocked(caller); ................ } }
By the way, here is a simple explanation of several key parameters of the startActivityLocked method according to the code.
IApplicationThread caller: An application requesting the activation of the current Activity. The IApplicationThread type is the IBinder interface that AMS IPC calls ActivityThread, as shown in the following figure:
IBinder resultTo: Active Record of the caller Activity (that is, the party that receives the returned result). After each activity is started, AMS passes the IBinder of Active Record of this activity to Activity as its identity in AMS. So resultTo is no longer an interface after two IPC passes, and it will become ActivityRecord again after returning to AMS. This parameter will be explained later.
Calling Pid and Calling Uid: If the caller is empty, it is the PID and UID of the process requesting to start Activity; the caller is not empty, but the PID and UID of the process where the caller activity is located are basically the same thing. This PID and UID are used for permission checking to check whether the current requester has permission to start the activity.
The main work of startActivityLocked is as follows:
Various checks: check the permission of the caller, check whether the caller needs to return the result, check the FLAG_ACTIVITY_FORWARD_RESULT tag, check whether the intent is correct, check whether the target Activity exists, check whether there is startActivity permission, check whether the current Activity can be switched.
After checking through, create ActiveyRecord for the target Activity
Forward the request to the startActivityUncheckedLocked method.
2.ActivityStackSupervisor.startActivityUncheckedLocked
This method is mainly responsible for task management, which can also be understood as task scheduling. In other words, it can also be understood as finding or creating a suitable task.
It mainly includes the following stages:
1) Determine whether a new Task needs to be run for the Activity to be started
This stage determines whether the activity to be started needs to run with the new Task through a series of judgments based on the flag and Launcher Mode. If you need to run a new Task, then the newly launched activity will be disconnected from its caller. This relationship mainly refers to result feedback, A -> B. If A is started through the start activity ForResult () request and request Code >= 0, then if B is in the new task, then B will not feedback result to A when finish ing, but to A during the start-up process. Feedback a RESULT_CANCELED.
//ActivityStackSupervisor.java final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, Bundle options, TaskRecord inTask) { ...... if (inTask == null) { if (sourceRecord == null) { // This activity is not being started from another... in this // case we -always- start a new task. if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) { Slog.w(TAG, "startActivity called from non-Activity context; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent); launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { // The original activity who is starting us is running as a single // instance... this new activity it is starting must go on its // own task. launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } else if (launchSingleInstance || launchSingleTask) { // The activity being started is a single instance... it always // gets launched into its own task. launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } }
As you can see from the above code, when the sourceRecord is null and the activity is not in the latest list, add FLAG_ACTIVITY_NEW_TASK to flag (if not).
When sourceRecord is not null, that is to say, it is activated from another activity, then FLAG_ACTIVITY_NEW_TASK should be added to flag if the activation mode represented by sourceRecord is singleinstance.
Finally, when the activity to be started has its own startup mode set to Single Instance or Single Task, FLAG_ACTIVITY_NEW_TASK should be added to flag.
2) Check for reusable Task s or Activities
When will you find out if there are reusable task s?
a. (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0
b. r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
c. r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
Intent.FLAG_ACTIVITY_MULTIPLE_TASK cannot be used alone. It is used in combination with Intent.FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_NEW_DOCUMENT. If Intent.FLAG_ACTIVITY_MULTIPLE_TASK is set up, a new task will always be started, regardless of whether there is a reusable task or not.
How to find reusable Task s
ActivityRecord intentActivity = !launchSingleInstance ? findTaskLocked(r) : findActivityLocked(intent, r.info);
Find out if there are reusable Activities
If so, call the resumeTopActivities Locked method Resume, the Activity
if (r.packageName != null) { ActivityStack topStack = mFocusedStack; ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) { if (top.app != null && top.app.thread != null) { if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop || launchSingleTask) { topStack.mLastPausedActivity = null; if (doResume) { resumeTopActivitiesLocked(); } ...... } } else { if (r.resultTo != null && r.resultTo.task.stack != null) { r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); } ActivityOptions.abort(options); return ActivityManager.START_CLASS_NOT_FOUND; }
3) Associate TaskRecord with ActivityRecord
if (r.resultTo == null && inTask == null && !addingToTask && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { newTask = true; //Markup creates a new Task targetStack = computeStackFocus(r, newTask); // Find a suitable ActivityStack targetStack.moveToFront("startingNewTask"); if (reuseTask == null) { r.setTask(targetStack.createTaskRecord(getNextTaskId(), newTaskInfo != null ? newTaskInfo : r.info, newTaskIntent != null ? newTaskIntent : intent, voiceSession, voiceInteractor, !launchTaskBehind /* toTop */), taskToAffiliate); //While creating Task, add task to activityStack } else { r.setTask(reuseTask, taskToAffiliate); //Reuse existing Task s }
Note: HomeStack Understanding
4) Call ActivityStack.startActivityLocked
- ActivityStack.startActivityLocked
The method is to add Activation to the top of the task. If the incoming new Task is true, indicating that a new task has been created, it also checks whether the reset task operation is performed to process the Task Reparenting; for false, it indicates that no task has been created, but that the activity is added to the task where his activity is started. Then adjust task to the top of mTaskHistory in ActivityStack. That is to move task to the top of the stack. Then call resumeTopActivities Locked to continue execution.
//ActivityStack .java final void startActivityLocked(ActivityRecord r, boolean newTask, boolean doResume, boolean keepCurTransition, Bundle options) { // If it is a newly created task, taskForIdLocked queries the history stack for the stack id where the id number is located for the target class. //If so, indicating that the target class has been created before, it is now reusable, which is not the first time to start. // newTask is passed to true if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) { insertTaskAtTop(rTask, r); // Move it to the top of the activitystack, the tail of mTaskHistory mWindowManager.moveTaskToTop(taskId); } ...... if (doResume) { mStackSupervisor.resumeTopActivitiesLocked(this, r, options); }
4.ActivityStackSupervisor.resumeTopActivitiesLocked
The main task of this method is to find out if there is an Activity that needs to be displayed on the top of the current stack, if there is an Activity that needs to be displayed, and then to find if there is an Activity that needs to be paused at the current time, and if there is one, call start Pausing Locked to pause it.
// ActivityStackSupervisor.java boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target, Bundle targetOptions) { if (isFrontStack(targetStack)) { result = targetStack.resumeTopActivityLocked(target, targetOptions); } ...... return result; } //ActivityStack.java final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { ...... boolean result = false; try { // Protect against recursion. mStackSupervisor.inResumeTopActivity = true; if (mService.mLockScreenShown == ActivityManagerService.LOCK_SCREEN_LEAVING) { mService.mLockScreenShown = ActivityManagerService.LOCK_SCREEN_HIDDEN; mService.updateSleepIfNeededLocked(); } result = resumeTopActivityInnerLocked(prev, options); } finally { mStackSupervisor.inResumeTopActivity = false; } return result; } private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) { //First check to see if the system is booted, or return directly. if (!mService.mBooting && !mService.mBooted) { // Not ready yet! return false; } ActivityRecord parent = mActivityContainer.mParentActivity; //If the activation itself of the current activity is not RESUMED, then the activity cannot be started and false is returned directly. if ((parent != null && parent.state != ActivityState.RESUMED) || !mActivityContainer.isAttachedLocked()) { // Do not resume this stack if its parent is not resumed. // TODO: If in a loop, make sure that parent stack resumeTopActivity is called 1st. return false; } ...... // We need to start pausing the current activity so the top one // can be resumed... boolean dontWaitForPause = (next.info.flags&ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0; boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause); if (mResumedActivity != null) { if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Pausing " + mResumedActivity); pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause); //Suspend the activation of Activity's source Activity, Launcher } ...... mStackSupervisor.startSpecificActivityLocked(next, true, true); } // ActivityStackSupervisor.java void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true); r.task.stack.setLaunchTime(r); // When you first start app, you're sure the app process hasn't started yet. if (app != null && app.thread != null) { ...... } catch (RemoteException e) { Slog.w(TAG, "Exception when starting activity " + r.intent.getComponent().flattenToShortString(), e); } } //Call AMS startProcessLocked to create a process mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }
2.5.2.2 Start up the application process
Entry: AMS.startProcessLocked
2.5.2.3 Load Application Activity
Entry: ActivityThread.main()
Main method: ActivityThread.main()
ActivityThread.attach()
AMS. AttachApplicationLocked()
ApplicationThread.bindApplication
2.5.2.4 Displays Activity
Note: Start the Start Setup Activity Locked Wizard
Entry: ActivityStackSupervisor. realStartActivityLocked
Main steps and methods: ActivityStackSupervisor. realStartActivityLocked
ApplicationThread.scheduleLaunchActivity
ActivityThread.handleLaunchActivity
ActivityThread.performLaunchActivity
ActivityThread.handleResumeActivity
ActivityThread.performResumeActivity
Note: Start the Start Setup Activity Locked Wizard
2.5.2.5 Activity Idle Status/Stop Source Activity
Activity onCreate then executes the onResume method and registers IdleHandler with the message queue of the main thread, where the Idler object is registered. When no other message needs to be processed in the message loop, the message processor executes Idler's queueIdle method, which is roughly as follows:
Idler.queueIdle--am.activityIdle--mStackSupervisor.activityIdleInternalLocked
The execution process of the activityIdleInternalLocked method is as follows:
1) Remove the IDLE_TIMEOUT_MSG message from the ActivityStack Supervisor message loop.
2) Stop Activity in the list to be stopped. These activities are stored in ActivityStackSupervisor. mStopping Activities, where the source activity is stored in the pending list by the ActivityStack.completePauseLocked method during the pause phase. If Activeness in the list is complete, call the ActivityStack.finishCurrentActivityLocked method to destroy the Activity, otherwise call the ActivityStack.stopActivityLocked(r) method to stop the Activity.
3) Destroy Activeness in the list to be destroyed. This process is completed by the ActivityStack.destroyActivityLocked method.
4) In the startup phase, checkFinishBooting Locked is called to handle sending a finishBooting method or an enableScreenAfterBoot method.
5) Recycle the application process. The process is completed by the trimApplications() method.
Summary of 2.5.2.6
From the source code analysis above, we can get the following Active Life Cycle Scheduling Diagram (A ctivity B is started by Activity A)
2.6 LRU & OOM mechanism
To be completed
3. Activity's four startup modes
Activity's four startup modes are closely related to task. Different startup modes have different relationships between activity and task in AMS. Its code implementation is located in ActivityStackSupervisor. startActivityUnchecked Locked
- Normal: Ordinary mode. In this mode, new activities are always created
-
SingleTop: Single Top Mode. In this mode, the activity at the top of the task is not recreated. Instead, the onNewIntent method sent to it by the receiving system is just a recovery action.
SingleTop Single Task: Single task mode. In this mode, the activity that already exists in task will not be recreated, only be restored, and all the activities on it will be removed.
-
Single Instance: Single instance mode. In this mode, activity and task are a 1:1 relationship. There can only be one activity in a task, and an activity can only exist in a task.
SingleInstance
4. AMS debugging method
command | function | Implementation Method |
---|---|---|
am start [options] | Start Activity | startActivityAsUser |
am startservice | Start Service | startService |
am stopservice | Stop Service | stopService |
am broadcast | Send Broadcasting | broadcastIntent |
am kill | Kill Designated Background Processes | killBackgroundProcesses |
am kill-all | Kill all backstage processes | killAllBackgroundProcesses |
am force-stop | The assassination process | forceStopPackage |
am hang | System jam | hang |
am restart | restart | restart |
am bug-report | Create bug report | requestBugReport |
am dumpheap | The heap information of the process pid is output to the file | dumpheap |
am send-trim-memory | Tighten the memory of the process | setProcessMemoryTrimLevel |
am monitor | Monitor | MyActivityController.run |
The implementation of AM command is based on frameworks/base/cmds/am/src/com/android/commands/am/Am.java, and almost all of them are completed by calling the corresponding method of Activity Manager Service, except am monitor.
Other am commands
am restart: restart the user-space system. am idle-maintenance: perform idle maintenance now. am screen-compat: control screen compatibility mode of <PACKAGE>. am package-importance: print current importance of <PACKAGE>. am to-uri: print the given Intent specification as a URI. am to-intent-uri: print the given Intent specification as an intent: URI. am to-app-uri: print the given Intent specification as an android-app: URI. am switch-user: switch to put USER_ID in the foreground, starting execution of that user if it is currently stopped. am start-user: start USER_ID in background if it is currently stopped, use switch-user if you want to start the user in foreground. am stop-user: stop execution of USER_ID, not allowing it to run any code until a later explicit start or switch to it. -w: wait for stop-user to complete. am stack start: start a new activity on <DISPLAY_ID> using <INTENT>. am stack movetask: move <TASK_ID> from its current stack to the top (true) or bottom (false) of <STACK_ID>. am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.
Start the activity
Use Action to Open System Settings-Input Settings
am start -a android.settings.INPUT_METHOD_SETTINGS
Start Browser with Component Name
am start -n com.android.browser/com.android.browser.BrowserActivity
Start service
Start a Service with ComponentName
am startservice com.some.package.name/.YourServiceSubClassName
Close the program that specifies the package name
Force the shutdown of the application, the ps command can not see the application's information.
am force-stop com.some.package
Killing process
Kill all processes associated with the package name of the application. This command only kills the secure process and does not affect the user experience. If the program shown in the package name is at the front end of the stack, that is, the user is using the app, kill will be invalid.
That is to say, the app shown in the package name will only take effect if it is in the background.
am kill com.some.package
After killing, select the app again from the task stack, and the app will refresh the data to start again.
Kill all background processes
am kill-all
Send Broadcasting
Am broadcast-a broadcast name
Start monitoring of test cases
adb shell am instrument -w com.android.phone.tests/com.android.phone.runners.FunctionalTestRunner
Display the activity in the current task stack
am stack list
Tighten memory
am send-trim-memory <pid> <level>
level range: HIDDEN, RUNNING_MODERATE, BACKGROUND, RUNNING_LOW, MODERATE, RUNNING_CRITICAL, COMPLETE.
Other common parameters
- a: Specify Intent action to implement Intent.setAction();
- n: Specify the component name in the form of {package name}/. {main Activity name}, and implement the principle Intent.setComponent();
- d: Specify Intent data URI
- t: Specify Intent MIME Type
- c [-c]... ] Specify Intent category and implement principle Intent.addCategory()
- p: Specify the package name and implement the principle of Intent.setPackage();
- f: Add flags to implement Intent.setFlags(int), and the next parameter must be int