All of my articles are collected in this article, and will be updated in time: Knowledge is long, the road of the walker will end in no words (My Programming Road)

Zero, preface,

This article is connected to Android: This article implements cross-process invocation of a Service through AIDL (that is, App2 calls App1’s Service). This article will explore the classes automatically generated by AIDL, and take a second look at ActivityManagerService.


In the previous article, AIDL automatically generated IMusicPlayerService analysis

1. Class structure of IMusicPlayerService

Too many, a little dazzling, open the structure diagram to analyze



2. Start with IInterface

IMusicPlayerService is an interface and inherits from IInterface. What is IInterface? For these two lines of code, there is only one asBinder method, which returns an IBinder object. Note that the package it is in is Android.os

package android.os;
public interface IInterface{
    public IBinder asBinder();
}
Copy the code

3. IMusicPlayerService analysis

The IMusicPlayerService interface is defined in imusicPlayerService. aidl. The ultimate goal is to see what its implementation class is

/* * This file is auto-generated. DO NOT MODIFY. * Original file: J:\\Java\\Android\\LeverUp\\TolyService\\app\\src\\main\\aidl\\com\\toly1994\\tolyservice\\IMusicPlayerService.aidl The original file is in: J:\\Java\\Android\\LeverUp\\TolyService\\app\\src\\main\\aidl\\com\\toly1994\\tolyservice\\IMusicPlayerService.aidl */ package com.toly1994.tolyservice; Declare any non-default types here with import statements // Declare any non-default types here with import statements IMusicPlayerService extends Android.os.iInterface {//Stub class extends Android.os.iInterface... /** * Demonstrates some basic types that you can use as parameters * andreturn values inAIDL. Describes some of the basic types that can be used as arguments and return values in AIDL. */ public void stop() throws android.os.RemoteException; public void pause() throws android.os.RemoteException; public void start() throws android.os.RemoteException; public void prev() throws android.os.RemoteException; public void next() throws android.os.RemoteException; public void release() throws android.os.RemoteException; public boolean isPlaying() throws android.os.RemoteException; public void seek(int pre_100) throws android.os.RemoteException; public void create(java.util.List<java.lang.String> filePaths) throws android.os.RemoteException; }Copy the code

4. And then, of course, go deeper, toStub

It not only inherits from Binder, it implements IMusicPlayerService, which looks pretty cool, but it’s an abstract class that implements something of Binder, But there’s no IMusicPlayerService method, it’s just a hung implementation. So in terms of member variables, each method is an int constant, which in terms of switch is a method DESCRIPTOR that’s a package name. IMusicPlayerService String, used to attachInterface

public static abstract class Stub extends android.os.Binder implements com.toly1994.tolyservice.IMusicPlayerService {
     private static final java.lang.String DESCRIPTOR = "com.toly1994.tolyservice.IMusicPlayerService"; /** * Construct the stub at attach it to the interface. The stub is constructed when the interface is associated. ---- DESCRIPTOR string */ public is usedStub() {
         this.attachInterface(this, DESCRIPTOR);
     }

     /**
      * Cast an IBinder object into an com.toly1994.tolyservice.IMusicPlayerService interface,
      * generating a proxy if needed.
      */
     public static com.toly1994.tolyservice.IMusicPlayerService asInterface(android.os.IBinder obj) {
         if ((obj == null)) {
             return null;
         }
         android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
         if(((iin ! = null) && (iin instanceof com.toly1994.tolyservice.IMusicPlayerService))) {return ((com.toly1994.tolyservice.IMusicPlayerService) iin);
         }
         return new com.toly1994.tolyservice.IMusicPlayerService.Stub.Proxy(obj);
     }

     @Override
     public android.os.IBinder asBinder() {
         return this;
     }

     @Override
     public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
         java.lang.String descriptor = DESCRIPTOR;
         switch (code) {
             case INTERFACE_TRANSACTION: {
                 reply.writeString(descriptor);
                 return true;
             }
             caseTRANSACTION_stop: {// Not yet...return true;
             }
             caseTRANSACTION_pause: {// Pause...return true;
             }
             caseTRANSACTION_start: {// Not yet...return true;
             }
             caseTRANSACTION_prev: {// Not yet...return true;
             }
             caseTRANSACTION_next: {// Not yet...return true;
             }
             caseTRANSACTION_release: {// Not yet...return true;
             }
             caseTRANSACTION_isPlaying: {// For now...return true;
             }
             caseTRANSACTION_seek: {//return true;
             }
             caseTRANSACTION_create: {// not yet...return true;
             }
             default: {
                 return super.onTransact(code, data, reply, flags);
             }
         }
     }
     
     //Proxy类,暂略...
     static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
     static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
     static final int TRANSACTION_start = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
     static final int TRANSACTION_prev = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
     static final int TRANSACTION_next = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
     static final int TRANSACTION_release = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
     static final int TRANSACTION_isPlaying = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
     static final int TRANSACTION_seek = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
     static final int TRANSACTION_create = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
 }
Copy the code

5. Now for the final layer:Proxy

Now I’m going to shine the spotlight on the Stub inner Proxy class. Proxy is a code type and we all know that Proxy means Proxy. What does it Proxy? The member variable has an IBinder mRemote, and the constructor is passing an IBinder, so… It implements IMusicPlayerService, and it takes actions, and the actions are basically the same

private static class Proxy implements com.toly1994.tolyservice.IMusicPlayerService { private android.os.IBinder mRemote;  Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinderasBinder() {
        return mRemote;
    }

    public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values inAIDL. */ @Override public void stop() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); }} @ Override public void pause () throws. Android OS. RemoteException {/ / temporary slightly... } @ Override public void the start () throws. Android OS. RemoteException {/ / temporary slightly... } @ Override public void prev () throws. Android OS. RemoteException {/ / temporary slightly... } @ Override public void next () throws. Android OS. RemoteException {/ / temporary slightly... } @ Override public void release () throws. Android OS. RemoteException {/ / temporary slightly... } @ Override public Boolean isPlaying () throws. Android OS. RemoteException {/ / temporary slightly... } @ Override public void the seek (int pre_100) throws. Android OS. RemoteException {/ / temporary slightly... } @ Override public void the create (Java. Util. List < Java. Lang. String > filePaths) throws. Android OS. RemoteException {/ / temporary slightly... }}Copy the code

So far, the relationship between them is clear, let’s see which ones in detail // Temporarily… The method of


Individual methods of Binder and IBinder

Here is a list of the methods used above


1. Current methods on the IBinder
public interface IBinder {
    /**
     * Attempt to retrieve a local implementation of an interface forthis Binder object. If null is returned, you will need to instantiate a proxy class to marshall calls through the transact() method. An attempt was made to retrieve the local interface implementation of this binder object. If null is returned, it needs to be invoked by instantiating a proxy class through the transact() method. */ public @Nullable IInterface queryLocalInterface(@NonNull String descriptor); /** * Perform a generic operation with the object. * Perform a generic operation with the object. * @param code The action to perform. This should be a number between {@link#FIRST_CALL_TRANSACTION} and {@link #LAST_CALL_TRANSACTION}.Code Indicates the operation behavior code ranging from 0x00000001 to 0x00FFFFFF. 1 to 16777215 * @parAM data Marshalled Data to send to the target. Must not be Null.If you are not sending any data, you must create an empty Parcel that is given here. data Marshals data sent to the target. Cannot be empty. If you are not sending any data, you must create the empty packet given here. * @param reply Marshalled data to be received from the target. May be nullif you are not interested in the returnValue. Marshalling data received from the target. If you are not interested in the return value, it may be null. * @param flags Additional operation flags. Either 0for a normal RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.Flags Extra operation flags, 0 for common RPC and 1 for unidirectional RPC {@link# FLAG_ONEWAY}.
    
     * @return Returns the result from {@link Binder#onTransact}. A successful call generally returns true; false generally means the transaction code was not understood.
   returnReturns the result from binder.onTransact (). A successful call usually returnstrue;falseUsually indicates that the transaction code is not understood. */ public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException; / / other... Slightly}Copy the code

2. Methods currently present on Binder’s surface
---->[Binder]-------------
private IInterface mOwner;
private String mDescriptor;

---->[Binder#attachInterface]-------------
 Convenience method for associating a specific interface with the Binder. 
 After calling, queryLocalInterface() will be implemented for you to returnThe given owner IInterface the when the corresponding descriptor is requested. | - "a specific interface associated with Binder and convenient method. After the call, will realize queryLocalInterface for you (), | - so that it is returned to the owner at the request of the corresponding descriptor (IInterface objects). public void attachInterface(@Nullable IInterface owner, @Nullable Stringdescriptor) { mOwner = owner; mDescriptor = descriptor; } ---->[Binder#queryLocalInterface]-------------
 Use information supplied to attachInterface() to return the associated 
 IInterface ifit matches the requested descriptor. If the supplied descriptor is the same as the IInterface associated with the attachInterface() method, Public @nullable IInterface queryLocalInterface(@nonnull String Descriptor) {if (mDescriptor.equals(descriptor)) {
        return mOwner;
    }
    return null;
}

---->[Binder#onTransact]-------------
 * Default implementation is a stub that returns false.  You will want
 * to override this to doThe default implementation is stub returnfalse. You will want to thank it for proper unmarshalling of the transaction. * <p>If you want to call this, call transact(). protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,int flags) throws RemoteException {Copy the code

3. Let’s go back to our tentative approach
3.1: attachInterface

This method is called in the Stub constructor, and is assigned to member variables mOwner and mDescriptor

---->[IMusicPlayerService.Stub#Stub]-------------
public Stub() { this.attachInterface(this, DESCRIPTOR); } | - here call attachInterface method, parameter is yourself and descriptor -- - > [Binder] -- -- -- -- -- -- -- -- -- -- -- -- -- private IInterface mOwner; private String mDescriptor; ---->[Binder#attachInterface]-------------
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}
Copy the code

3.2: asInterface

Pass in an IBinder object obj, call obj’s queryLocalInterface method to generate an IInterface object and then make a strong push. If the strong push fails, the Proxy object will be created

---->[IMusicPlayerService.Stub#asInterface]-------------
public static com.toly1994.tolyservice.IMusicPlayerService asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if(((iin ! = null) && (iin instanceof com.toly1994.tolyservice.IMusicPlayerService))) {return ((com.toly1994.tolyservice.IMusicPlayerService) iin);
    }
    return new com.toly1994.tolyservice.IMusicPlayerService.Stub.Proxy(obj);
}
Copy the code

3.3: asBinder

AsBinder is a method of the IInterface interface that returns itself (Stub inherits from Binder). Okay

---->[IMusicPlayerService.Stub#asInterface]-------------
@Override
public android.os.IBinder asBinder() {
    return this;
}
Copy the code

3.4: onTransact

This method runs in the Binder thread pool on the server side. When the client initiates cross-process requests, remote requests are encapsulated by the underlying system and sent to this method. The logic is basically the same, you call the method by judging the code, so let’s look at two start and seek,

@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; Switch (code) {// omit...caseTRANSACTION_start: { data.enforceInterface(descriptor); // Execute the interface this.start(); // Call the start method reply.writenoException (); // Write the result in replyreturn true;
        }
        caseTRANSACTION_seek: { data.enforceInterface(descriptor); // Execute the interface int _arg0; _arg0 = data.readInt(); This.seek (_arg0); // Call the seek method reply.writenoException (); // Write the result in replyreturn true; } / / slightly...Copy the code

3.5: Implementation method in Proxy

IMusicPlayerService is a Proxy class that runs on the client side, that is, Stub#asInterface

---->[IMusicPlayerService.Stub.Proxy#start]--------@Override public void start() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); Try {// write _data to _data. WriteInterfaceToken (DESCRIPTOR); // Pass the parameter to the server via the transact method and write _reply mRemote. Transact (stub.transaction_start, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public void seek(int pre_100) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(pre_100); mRemote.transact(Stub.TRANSACTION_seek, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); }}Copy the code

4. Now look at the last picture we drew in the Service

The onServiceconnection’s onServiceConnected method calls back an IBinder object called Service And through the IMusicPlayerService. Stub. AsInterface method could become a IMusicPlayerService service object remember asInterface in do what? Now look again, is the logic of AIDL clearer at the usage level?

It should be emphasized here: In the figure: the blue area can be used in any app, equivalent to the client: just connect to the line. The other area is the server side logic, providing business logic processing for the clientCopy the code

As for Binder’s position on the ground floor, that’s later. The diamond is the last


5. To summarize: Now look back
1. In an AIDL service, where is the business logic handled? | - this still use to ask you, of course inside the MusicPlayerStub, otherwise can also? 2. What's the use of IMusicPlayerService and Stub | -- - | IMusicPlayerService is callable interface - Stub on the table there is a credit, Convert an IBinder object to an IMusicPlayerService object using asInterface. | - Proxy only appear in asInterface approach, in inn cannot be equivalent to use Proxy 4 IMusicPlayerService. When can inn not be converted into IMusicPlayerService? (see below) | -- - I did an experiment, is have a look at the client and the server respectively bind callback IBinder object types Call queryLocalInterface method get inn again, have a look at it is the type of server: MusicPlayerStub, who is it? The Stub object implements IMusicPlayerService. The client is: The BinderProxy object queryLocalInterface is null, and the Proxy is usedCopy the code


ActivityManagerService

1. How to analyze system-level cross-process communication services
What should we do when we come across this code when we're looking at the source code? (for example, ActivityManagerNative) It can be seen that neither Stub, Proxy or Binder are of great use for analyzing the logic of code. They are only the mechanism to implement the communication between classes across processes. This mechanism is not very logically related. It is necessary to understand that the main business logic is all in the implementation class of XXXXStub. Generally, XXXXStub is used as an internal class of XXXXService. That is to say, when you see the source code of the system service about AIDL, you can directly analyze XXXXService, and the logic is all thereCopy the code

2. Why was AIDL born
| - a word: lazy... The class that's automatically generated, you type it out and you run it, so if it's automatically generated, so it's generated, AIDL comes out and it simplifies communication across processes, but once you simplify things, it's hard to play with Binder can be very complex, IBinder can have a lot of control, So AIDL is just the simplest interprocess communication mechanism like a rapidly produced bench and a carefully sculpted bench, both of which can be seated, but the value is vastly differentCopy the code

3. ActivityManagerNative analysis

Remember ActivityManagerNative from the first article when an Activity is launched? This is the legendary ActivityManagerNative and you can compare it to the IMusicPlayerService at the top


4. The man behind ActivityManagerNative

In general are called ActivityManagerNative. GetDefault () to generate a IActivityManager object Then call the corresponding IActivityManager abstract methods, the specific implementation class is who? ActivityManagerNative acts like the Stub above, and you need to find a class that inherits it. This is ActivityManagerService. Note that this is not a Service object, but the core logic of the Service Its value is similar to our MusicPlayerStub above, not a Service, but more like a Service


5.ActivityManagerNative.getDefault()What does the method say?

Returns an IActivityManager object of type ActivityManagerService

---->[ActivityManagerNative#getDefault]--------------------Static public IActivityManager objectgetDefault() {
    returngDefault.get(); } / / | - here by gDefault member variables of the get () method to obtain a focus upon gDefault IActivityManager object | - now, Take a look at what he is -- -- -- - > [ActivityManagerNativegetDefault. GDefault] -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { protected IActivityManagercreate() {// Obtain the IBinder object of the activity from the ServiceManager. IBinder b = ServiceManager Obtain."activity");
        if (false) {
            Log.v("ActivityManager"."default service binder = "+ b); } // The asInterface method uses the IBinder object to get the IActivityManager object IActivityManager am = asInterface(b);if (false) {
            Log.v("ActivityManager"."default service = " + am);
        }
        returnam; }}; / / | - gDefault data type is the Singleton < IActivityManager >, a bit mean, look at the Singleton class - Singleton auxiliary class! Public abstract class Singleton<T> {private T mInstance; public abstract class Singleton<T> {private T mInstance; protected abstract T create(); public final Tget() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

---->[ActivityManagerNativegetDefault.asInterface]--------------------
static public IActivityManager asInterface(IBinder obj) {
    if (obj == null) {
        returnnull; } // If obj(i.e., Bundle) queryLocalInterface is not empty, use itin
    IActivityManager in =
        (IActivityManager)obj.queryLocalInterface(descriptor);
    if (in! = null) {return in; } // Otherwise return the ActivityManagerProxy objectreturn new ActivityManagerProxy(obj);
}

---->[ActivityManagerNativegetDefault$ActivityManagerProxy]--------------------
class ActivityManagerProxy implements IActivityManager{
    public ActivityManagerProxy(IBinder remote){
        mRemote = remote;
    }
    public IBinder asBinder() {returnmRemote; } / / slightly... public int broadcastIntent(IApplicationThreadcaller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String[] requiredPermissions, int appOp, Bundle options, boolean serialized, boolean sticky, Int userId) throws RemoteException // Omit... }Copy the code

Such use ActivityManagerNative. GetDefault () can get a IActivityManager object, the object implementation type for ActivityManagerService, Also is the legendary AMS, so looking at source ActivityManagerNative. GetDefault (), is equivalent to see the AMS