Binder for system source code learning

insert image description here

The Binder class is used as the Bn terminal (native), and the BinderProxy is used as the representative of the Bp of the client. BinderInternal is a class used only by the Binder framework. It has a GcWather class inside, which is a
Java layer that handles garbage collection related to Binder. It also provides a user Data parcel class for bearer communication

In the Android system, in the initial period of java, the system will register some JNI functions in advance, and complete the initialization of the three most important classes in the java Binder architecture through the register_android_os_Binder function. Binder, BinderInternal, and BinderProxy classes, initialization is actually to obtain some JNI layers in
advance usage information for

Analyze the working principle of the java layer Binder through ActivityManagerService
Analysis steps:
first analyze how AMS registers itself to ServiceManager
and then analyze how AMS responds to the client's Binder call request

The starting point is AMS.setSystemProcess()

public static final String ACTIVITY_SERVICE = "activity";
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);

Add the AMS service to ServiceManager. There is only one Native ServiceManager (SM) process in the entire Android system, which coordinates and manages all services on the Android system. The first condition for becoming a service is to register in SM first.

(1) Register service with SM

public static void addService(String name, IBinder service) {
    
    
    try {
    
    
        getIServiceManager().addService(name, service, false);
    } catch (RemoteException e) {
    
    
        Log.e(TAG, "error in addService", e);
    }
}

First figure out what getIServiceManager returns?

private static IServiceManager getIServiceManager() {
    
    
    if (sServiceManager != null) {
    
    
        return sServiceManager;
    }

    //调用asInterface ,传递的参数类型IBinder
    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
    return sServiceManager;
}

The parameters are: BinderInternal.getContextObject() return value

public static final native IBinder getContextObject();

The getContextObject method is a native function, which obtains the BpProxy pointing to the ServiceManager in the Native process, but this cannot be used directly by the java layer. A BinderProxy object is generated and returned through the javaObjectForIBinder() function. (Through JNI BinderProxy and native BpProxy object hook)

static public IServiceManager asInterface(IBinder obj)
{
    
     
    IServiceManager in =
        (IServiceManager)obj.queryLocalInterface(descriptor);
    return new ServiceManagerProxy(obj);
}

Eventually the ServiceManagerProxy.addService method will be called

public ServiceManagerProxy(IBinder remote) {
    
    
    mRemote = remote;  //为刚才传入的BinderProxy 参数
}

public void addService(String name, IBinder service, boolean allowIsolated)
        throws RemoteException {
    
    
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IServiceManager.descriptor);
    data.writeString(name);
//下面的writeStrongBinder为特殊函数
    data.writeStrongBinder(service);
    data.writeInt(allowIsolated ? 1 : 0);
//此处调用的是BinderProxy的transact函数,为native函数
    mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
    reply.recycle();
    data.recycle();
}

Respond in the onStransact function, the representative of the native layer is Binder, and ActivityManagerNative inherits Binder
Binder.java

private boolean execTransact(int code, long dataObj, long replyObj,
        int flags) {
    
    
    Parcel data = Parcel.obtain(dataObj);
    Parcel reply = Parcel.obtain(replyObj);
    boolean res;
    try {
    
    
	//派生类可以重新实现这个函数,以完成业务
        res = onTransact(code, data, reply, flags);

ActivityManagerNative inherits Binder and rewrites the onTransact method

public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
    
    
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException {
    
    
    switch (code) {
    
    
case START_SERVICE_TRANSACTION: {
    
    
    data.enforceInterface(IActivityManager.descriptor);
    IBinder b = data.readStrongBinder();
    IApplicationThread app = ApplicationThreadNative.asInterface(b);
    Intent service = Intent.CREATOR.createFromParcel(data);
    String resolvedType = data.readString();
    String callingPackage = data.readString();
    int userId = data.readInt();
	//再由ActivityManagerService实现具体的事务
    ComponentName cn = startService(app, service, resolvedType, callingPackage, userId);
    reply.writeNoException();
    ComponentName.writeToParcel(cn, reply);
    return true;
}

(2) Understand AIDL
After the last analysis, I have roughly understood the architecture of the Java layer Binder. The Bp side can send requests to the Bn side through the transact() method of BinderProxy, and the Bn side can receive by rewriting onTransact () by inheriting the Binder class. And handle requests from the Bp side . It is quite complicated and cumbersome to implement, so Android provides AIDL language and AIDL interpreter to automatically generate a service Bn terminal

Define the AIDL file, IMyServer.aidl, and provide an interface foo() that can be called across Binder. Use the aidl tool to parse it into a java source code that realizes the communication between Bn and Bp through Binder

interface IMyServer {
    
    
    void foo(String str);
}

Build/Make Project in Android studio to generate java source code, in the directory app/build/generated/aidl_source_output_dir/debug/out directory

ublic interface IMyserver extends android.os.IInterface
{
    
      //首先IMyserver被解析成一个java接口IMyserver,这个接口定义了AIDL文件中所定义的就口foo
  public static class Default implements com.example.touthdemo.AIDL.IMyserver
  {
    
    
    @Override public void foo(java.lang.String str) throws android.os.RemoteException
    {
    
    
    }
    @Override
    public android.os.IBinder asBinder() {
    
    
      return null;
    }
  }
  //AIDL工具生成一个继承自IMyserver接口的抽象类IMyserver.Stub
  //这个抽象类实现了Bn端通过onTransacet()方法用于接收来自Bp端的请求代码,foo为抽象方法
  //所以aidl工具不知道foo()方法是做什么的,它只能通过onTransact中得知Bp端希望foo方法进行调用,所以Stub是抽象的
  public static abstract class Stub extends android.os.Binder implements com.example.touthdemo.AIDL.IMyserver
  {
    
    
    private static final java.lang.String DESCRIPTOR = "com.example.touthdemo.AIDL.IMyserver";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
    
    
      this.attachInterface(this, DESCRIPTOR);
    }
  //根据code数值选择调用IMyserver接口中的不同方法,本例中TRANSACTION_foo 以为这调用foo
    @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;
        }
        case TRANSACTION_foo:
        {
    
    
          data.enforceInterface(descriptor);
          java.lang.String _arg0;
	//从data中需要读取arg0
          _arg0 = data.readString();
	//Stub类的子类需要实现foo()方法
          this.foo(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        {
    
    
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
  //AIDL工具生成一个继承IMyServer接口的类proxy,它是Bp端的实现,与Bn端的stub类不同,它实现的了foo()函数,因为foo函数Bp端的实现是确定的,即将参数存储到parcel中,然后执行transact()方法将请求发送到Bn端,然后从reply中读取返回值并返回给调用者。  
private static class Proxy implements com.example.touthdemo.AIDL.IMyserver
    {
    
    
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
    
    
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
    
    
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
    
    
        return DESCRIPTOR;
      }
      @Override public void foo(java.lang.String str) 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.writeString(str);
          boolean _status = mRemote.transact(Stub.TRANSACTION_foo, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
    
    
            getDefaultImpl().foo(str);
            return;
          }
          _reply.readException();
        }
        finally {
    
    
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.example.touthdemo.AIDL.IMyserver sDefaultImpl;
    }
    static final int TRANSACTION_foo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    public static boolean setDefaultImpl(com.example.touthdemo.AIDL.IMyserver impl) {
    
    
      // Only one user of this interface can use this function
      // at a time. This is a heuristic to detect if two different
      // users in the same process use this function.
      if (Stub.Proxy.sDefaultImpl != null) {
    
    
        throw new IllegalStateException("setDefaultImpl() called twice");
      }
      if (impl != null) {
    
    
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.example.touthdemo.AIDL.IMyserver getDefaultImpl() {
    
    
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public void foo(java.lang.String str) throws android.os.RemoteException;
}

In order to realize the capabilities of the Bn side, developers need to inherit the IMyServer.Stub class and implement the abstract method foo

@Override
public IBinder onBind(Intent intent) {
    
    
    return new MyBinder();
}
private class MyBinder extends IMyserver.Stub {
    
    
    @Override
    public void foo(String str) throws RemoteException {
    
    
        Log.d(TAG, "foo: ");
    }

Note:
In order to have the capability of the Bn side, the typical method is to add the instance of the MyServer class to the system service through ServiceManager, addService(), or use it as the return value in the onBInd() method of the quasi-Service so that it can be used by other processes access.

So how will the Bp side use IMyServer.Proxy?
Once you get the BinderProxy of IMyServer (via ServiceManager.getService(), onServiceConnected() or other methods), you can get it as follows
//binderProxy is obtained through ServiceManager.getService or
IMyServer remote = IMyServer in onServiceConnected(). Stub.asInterface(binderProxy);
remote.foo("");

final class MyServiceConnection implements ServiceConnection {
    
    
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
    
    
        myServer = (IMyserver) IMyserver.Stub.asInterface(iBinder);
        try {
    
    
            myServer.foo("hahhahaha");
        } catch (RemoteException e) {
    
    
            e.printStackTrace();
        }
    }
    @Override
    public void onServiceDisconnected(ComponentName componentName) {
    
    
    }
}

Then the implementation of IMserver.Stub.asInterface()
is to create an IMServer.Stub.Proxy, in which obj will be saved as the mRemote member of the proxy class

public static com.example.touthdemo.AIDL.IMyserver asInterface(android.os.IBinder obj)
{
    
    
  if ((obj==null)) {
    
    
    return null;
  }
  android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  if (((iin!=null)&&(iin instanceof com.example.touthdemo.AIDL.IMyserver))) {
    
    
    return ((com.example.touthdemo.AIDL.IMyserver)iin);
  }

  return new com.example.touthdemo.AIDL.IMyserver.Stub.Proxy(obj);
}

Guess you like

Origin blog.csdn.net/qq_42447739/article/details/125668085