Android advanced decryption reading notes -- understanding ActivityManagerService

Android 7.0 and Android 8.0 have great differences in the processing of AMS related parts

AMS family for Android 7.0

There are three main categories

  • ActivityManager

    Activity manager is a class associated with AMS. It mainly manages running activities. These management tasks are not handled by ActivityManager, but by AMs

  • ActivityManagerNative(AMN)

    AMN is an abstract class that delegates functions to its subclass AMS, which is a Binder communication class

  • ActivityManagerProxy(AMP)

    The method in the ActivityManager will get the ActivityManagerProxy through the getDefault method of ActivityManagerNative (AMN)

    AMP is the internal class of AMN. They all implement the IActivityManager interface, so they can implement the agent mode. Specifically, they are remote agents: AMP and amn run in two processes, AMP is the Client side, amn is the Server side, and the specific functions in the Server side are implemented by AMS, a subclass of AMN. Therefore, AMP is the proxy class of AMS on the Client side

Take the Activity startup process of Android 7.0 as an example. During the Activity startup process, the execStartActivity method of Instrumentation will be called

/*frameworks/base/core/java/android/app/Instrumentation.java*/
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options){
    ...
    //Call getDefault of AMN to get the proxy class amp of AMS, and then call the startActivity method of AMP
    int result = ActivityManagerNative.getDefault().startActivity(...);
    ...
}

/*ActivityManagerNative.java*/
static public IActivityManager getDefault(){
    return gDefault.get();
}

private static final Singleton<IActivityManager> getDefault = new Singleton<IActivityManager>(){
    protected IActivityManager create(){
        //Get the Service reference named "activity", that is, the reference of AMS of IBinder type
        IBinder b = ServiceManager.getService("activity");
        ...
        //The Service reference is encapsulated into a AMP type object and saved to gDefault. After that, the AMS's proxy object AMP is directly invoked by calling AMN's getDefault method.
        IActivityManager am = asInterface(b);
    }
}

static public IActivityManager asInterface(IBinder obj){
    if(obj == null){
        return null;
    }
    //The descriptor value is android.app.IActivityManager; This code is mainly used to query whether the local process has the IActivityManager interface implementation. If so, it returns
    IActivityManager in = (IActivityManager) obj.queryLocalInterface(descriptor);
    if(in != null){
        return in;
    }
    //If not, encapsulate the AMS reference of IBinder type into AMP 
    return new ActivityManagerProxy(obj);
}

class ActivityManagerProxy implements IActivityManager{
    //Assign the reference of AMS to the variable mRemote in the construction method, so that AMS can be used in AMP
    public ActivityManagerProxy(IBinder remote){
        mReomte = remote;
    }
}

//Go back to the execStartActivity method of Instrumentation to see the startActivity method of AMP. Amp is an internal class of AMN
/*ActivityManagerNative.java*/
public int startActivity(...) throws RemoteException{
    ...
    //Write the passed in parameters to the data of Parcel type
    data.writeInt(requestCode);
    data.writeInt(startFlags);
    ...
    //Send a start to the server-side AMS through the IBinder type object mremote (a reference to AMS)_ ACTIVITY_ An interprocess communication request of type transaction. Then the server AMS will read the data sent by the client from the Binder thread pool, and finally call the onTransact method of AMN
    mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
}

@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException{
    switch(code){
            case START_ACTIVITY_TRANSACTION: 
                ...
                int result = startActivity(aap, callingPackage, intetn, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
                reply.writeNoException();
                reply.writeInt(result);
                return true;
    }
}

//The startActivity method of AMS is called in the onTransact method
/*ActivityManagerService.java*/
public final int startActivity(IApplicationThread caller, ....){
    return startActivityAsUser(...);
}

//In this method, the startActivityMayWait method of ActivityStarter will be called finally
public final int startActivityAsUser(...,int userId){
    ...
    return mActivityStarter.startActivityMayWait(...);
}

AMS family for Android 8.0

Similarly, take the Activity startup process as an example. For Android 8.0, the execStartActivity method of Instrumentation will be called during the Activity startup process

/*frameworks/base/core/java/android/app/Instrumentation.java*/
public ActivityResult execStartActivity(Context who, ...){
    ...
    int result = ActivityManager.getService().startActivity(...);
    ...
}

/* ActivityManager getService method for
* ActivityManager.java
*/
public static IActivityManager getService(){
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton = new Singleton<IActivityManager>(){
    @Override
    protected IActivityManager create(){
        //Get the Service reference named "activity" (the value of Context.ACTIVITY_SERVICE is "activity"), that is, the reference of AMS of IBinder type
        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
        // Convert it to an object of type IActivityManager,
        final IActivityManager am = IActivityManager.Stub.asInterface(b);
    }
}

IActivityManager.java class is automatically generated by AIDL tool during compilation. The file path of IActivityManager.aidl is framework/base/core/java/android/app/IActivityManager.aidl. To realize inter process communication, the server side, that is, AMS, only needs to inherit the IActivityManager.Stub class and implement the corresponding methods. After AIDL is adopted, the proxy class AMP of AMS is not required

AMS startup process

AMS is started in the SystemServer process. We start from the main method of SystemServer

/*framworks/base/services/java/com/android/server/SystemServer.java*/
public static void main(String[] args){
    new SystemServer().run();
}

private void run(){
    try{
        ...
        //Create message Looper
        Looper.prepareMainLooper();
        //Load dynamic library libandroid_servers.so
        System.loadLibrary("android_servers");
        //Create a system service manager, which will create, start and manage the service life cycle of the system
        mSystemServiceManager = new SystemServiceManager(mSystemContext);
        ...
        //Start the boot service. Start AMS, PowerManagerService, PackageManagerService and other services with SystemServiceManager
        startBootstrapServices();    
        //Start the core service. Start DropBoxManagerService, BatteryService, UsageStatusService and WebViewUpdateService
        startCoreServices();
        //Start other services. Start CameraService, AlarmManagerService, VrManagerService and other services
        startOtherServices();
    }
}

//Next, we mainly look at the boot service and how AMS is started. That is, the startBootstrapServices() method
private void startBootstrapServices(){
    ...
    traceBeginAndSlog("StartActivityManager");
    //Call the startService method of SystemServiceManager
    mActivityManagerService = mSystemServiceManager.startService(ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);
    traceEnd();
    ...
}

/*SystemServiceManager.java*/
public void startService(final SystemService service){
    //Add the service object to the mServices of ArrayList type to complete the registration
    mServices.add(service);
    //Call the onStart method of the service to start the service object
    service.onStart();
}

/** What does this service object specifically refer to?
* ActivityManagerService.Lifecycle.class Is an internal class of AMS
* ActivityManagerService.java
*/
public static final class Lifecycle extends SystemService{
    private final ActivityManagerService mService;
    public Lifecycle(Context context){
        super(context);
        //Create an AMS instance in the construction method of Lifecycle
        mService = new ActivityManagerService(context);
    }
    
    @Override
    public void onStart(){
        //When you call the onStart method of a service of SystemService type, you actually call the start method of AMS there
        mService.start()
    }
    
    //Return the AMS instance, and call this method to get the AMS instance
    public ActivityManagerService getService(){
        return mService;
    }
}

AMS and application process

In Chapter 2, the system startup will go to the java framework layer of Zygote, and a Server-side Socket will be created to wait for AMS to request Zygote to create a new application process.

To start an application, first ensure that the program process required by the application already exists. When starting an application, AMS will check whether the process required by the application exists. If it does not exist, AMS will request the Zygote process to create the required application process

Here, take the service startup process as an example to analyze the relationship between AMS and application process. Service will call the bringUpServiceLocked method of ActiveServices during startup

/*frameworks/base/services/core/java/com/android/server/am/ActiveServices.java*/
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired) throws TransactionTooLargeException{
    ...
    //Get the value of processName of ServiceRecord and assign it to procName. processName is used to describe which process the Service wants to run in. By default, it is the current process. We can set the android:process attribute in the AndroidManifest file to start a new process to run the Service
    final String procName = r.processName;
    ...
    //Query whether there is an object app of ProcessRecord type corresponding to the Service
    ProcessRecord app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
    //Determine whether the application process used to run the Service exists
    if(app != null && app.thread != null){
        //Start Service
        realStartServiceLocked(r, app, execInFg);
    }
    
    //If the application process used to run the Service does not exist
    if(app == null && !permissionReviewRequired){
        //Use the startProcessLocked() method to create the corresponding application process
        if((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, hostingType, r.name, false, isolated, false)) == null)
    }
}

The relationship between AMS and application process mainly includes the following two points:

  • When starting an application, AMS will check whether the application process required by the application exists

  • If the required application does not exist, AMS will request the Zygote process to create the required application process

AMS important data structure

ActivityRecord

ActivityRecord internally records all the information of an Activity, so it is used to describe an Activity. It is created when the Activity is started, specifically in the startActivity method of ActivityStarter

Some important member variables of ActivityRecord are shown in the following table

nametypeexplain
serviceActivityManagerServiceReferences to AMS
infoActivityInfoCode in Activity and node information set by AndroidManifest, such as launchMode
launchedFromPackageStringThe package name of the startup Activity
taskAffinityStringThe stack to which the Activity wants to belong
taskTaskRecordTaskRecord where ActivityRecord is located
appProcessRecordThe application process in which the ActivityRecord resides
stateActivityStateCurrent Activity status
iconintIcon resource identifier for Activity
themeintSubject resource identifier for Activity

TaskRecord

TaskRecord is used to describe an Activity task stack, which internally stores all the information of the task stack, including the ActivityStack, that is, the ActivityStack to which the current Activity task stack belongs

nametypeexplain
taskIdintUnique identifier of the task stack
affinityStringTendency of task stack
intentIntentStart the Intent of this task stack
mActivitiesArrayList<ActivityRecord>Activity records in historical order
mStackActivityStackActivityStack to which you currently belong
mServiceActivityManagerServiceReferences to AMS

Activity stack is a management class used to manage all activities in the system. It internally maintains data such as all States of activities, activities in special states and lists related to activities. The ActivityStack is managed by the ActivityStack supervisor

taskAffinity

We can set android:taskAffinity in AndroidManifest.xml to specify the stack where the Activity wants to belong. By default, all activities of the same application have the same taskAffinity

taskAffinity works in the following two cases:

  1. TaskAffinity and FLAG_ACTIVITY_NEW_TASK or singleTask. If the taskAffinity of the newly started Activity is the same as that of the stack, it will be added to the stack; If different, a new stack is created

  2. taskAffinity works with allowtaskreparating. If allowtaskreparating is true, the Activity has the ability to transfer

Keywords: Java Android

Added by not_john on Wed, 10 Nov 2021 13:21:22 +0200