[Android] Binder mechanism principle

table of Contents

table of Contents


definition

 


2. Knowledge reserve

Before explaining Binder, we first understand some Linuxbasic knowledge

2.1 Process space division

  • A process space is divided into user space & kernel space ( Kernel), which separates the user & kernel in the process
  • The difference between the two:
    1. Between processes, user space data cannot be shared, so user space = non-shareable space
    2. Between processes, data in the kernel space can be shared, so kernel space = sharable space

All processes share 1 kernel space

  • & In-process user space kernel space required to interact via system calls , mainly through the function:
  1. copy_from_user(): Copy data from user space to kernel space
  2. copy_to_user(): Copy the data in the kernel space to the user space

Schematic diagram

2.2 Process isolation & cross-process communication (IPC)

  • Process isolation
    In order to ensure safety & independence, a process cannot directly operate or access another process, that is Android, the processes are independent and isolated from each other

  • Cross-process communication ( IPC)
    means that data interaction and communication are required between processes

  • Basic principles of inter-process communication

Schematic diagram

a. BinderThe function is to connect the two processes and realize the mmap() system call, which is mainly responsible for creating the data receiving buffer space & managing the data receiving buffer
b. Note: The traditional cross-process communication needs to copy the data twice, but BinderThe mechanism only needs 1 time, mainly using memory mapping, which will be explained in detail below

2.5 Memory mapping

For details, please see the article: Operating System: Graphical Detailed Memory Mapping


3. Binder cross-process communication mechanism model

3.1 Model schematic

BinderInter-process communication mechanism model based on Client - Servermode
Schematic diagram

3.2 Model composition role description

Schematic diagram

Here focus on explaining Binderthe driving role & principle:

  • Introduction

Schematic diagram

  • The core principle of inter-process communication

Regarding its core principle: memory mapping, please see the article for details: operating system: detailed graphics and text memory mapping

Schematic diagram

3.3 Model principle step description

Schematic diagram

3.4 Additional instructions

Note 1: Clientprocess, Serverprocess & Service Managerthe interaction between the processes must pass Binderthe driving (use openand ioctlfile manipulation functions), rather than direct interaction

the reason:

  1. ClientProcesses, Serverprocesses & Service Managerprocesses belong to the user space of the process space, and inter-process interaction is not allowed
  2. BinderThe driver belongs to the kernel space of the process space, which can carry out inter-process & intra-process interaction

Therefore, the schematic diagram can be expressed as the following:

Dotted lines indicate not direct interaction

Schematic diagram

Note 2: Binderdrive & Service Managerprocess belongs to Androidthe infrastructure (ie, the system has achieved good); and Clientprocess and the Serverprocesses belonging to Androidthe application layer (requires developers to achieve their own)

Therefore, when the inter-process communication is performed, the developer only needs custom Client& Serverprocess and explicit use of the above-described three steps, by means of the final Androidbasic structure can be completed interprocess communication functions

Schematic diagram

Description 3: Binder request thread management

  • ServerThe process creates many threads to handle Binderrequests
  • BinderThe thread management of the model adopts Binderthe thread pool of the Binderdriver and is managed by the driver itself

Not managed by the Serverprocess

  • The Binderdefault maximum number of threads in a process is 16, and requests that exceed them will be blocked waiting for idle Binder threads.

Therefore, when dealing with concurrency issues during inter-process communication, such as ContentProviderwhen used, its CRUD(create, retrieve, update, and delete) methods can only have 16 threads working at the same time


  • At this point, I believe that everyone Binderhas a very clear qualitative understanding of the cross-process communication mechanism model.
  • Below, I will go through an example, analysis of Binderinter-process communication mechanism model Androidspecific code implementation

That is, analyze how the above steps Androidare specifically implemented in code


4. The specific implementation principle of the Binder mechanism in Android

  • BinderMechanism in the Androidimplementation of mainly depends on Binderthe class that implements IBinderthe interface

The following will explain in detail

  • Examples: ClientProcess call the Serveradd function process (a and b integer addition)

which is:

  1. ClientProcess needs to pass two integers to Serverprocess
  2. ServerThe process needs to return the result of the addition to the Clientprocess
  • Specific steps
    Below, I will Binderanalyze the steps according to the cross-process communication mechanism model

Step 1: Register for the service

  • Process Description
    Serverprocess by Binderdriving to the Service Managerprocess of registration services
  • Code implementation
    Serverprocess creates a Bindertarget
  1. BinderEntity is Servera process in Binderthe presence of the drive in the form of
  2. The object stores Serverand ServiceManagerinformation (stored in the kernel space)
  3. BinderThe driver Binderfinds Serverobjects in user space through entities in kernel space
  • Code analysis
    
    Binder binder = new Stub();
    // 步骤1:创建Binder对象 ->>分析1

    // 步骤2:创建 IInterface 接口类 的匿名类
    // 创建前,需要预先定义 继承了IInterface 接口的接口 -->分析3
    IInterface plus = new IPlus(){

          // 确定Client进程需要调用的方法
          public int add(int a,int b) {
               return a+b;
         }

          // 实现IInterface接口中唯一的方法
          public IBinder asBinder(){ 
                return null ;
           }
};
          // 步骤3
          binder.attachInterface(plus,"add two int");
         // 1. 将(add two int,plus)作为(key,value)对存入到Binder对象中的一个Map<String,IInterface>对象中
         // 2. 之后,Binder对象 可根据add two int通过queryLocalIInterface()获得对应IInterface对象(即plus)的引用,可依靠该引用完成对请求方法的调用
        // 分析完毕,跳出


<-- 分析1:Stub类 -->
    public class Stub extends Binder {
    // 继承自Binder类 ->>分析2

          // 复写onTransact()
          @Override
          boolean onTransact(int code, Parcel data, Parcel reply, int flags){
          // 具体逻辑等到步骤3再具体讲解,此处先跳过
          switch (code) { 
                case Stub.add: { 

                       data.enforceInterface("add two int"); 

                       int  arg0  = data.readInt();
                       int  arg1  = data.readInt();

                       int  result = this.queryLocalIInterface("add two int") .add( arg0,  arg1); 

                        reply.writeInt(result); 

                        return true; 
                  }
           } 
      return super.onTransact(code, data, reply, flags); 

}
// 回到上面的步骤1,继续看步骤2

<-- 分析2:Binder 类 -->
 public class Binder implement IBinder{
    // Binder机制在Android中的实现主要依靠的是Binder类,其实现了IBinder接口
    // IBinder接口:定义了远程操作对象的基本接口,代表了一种跨进程传输的能力
    // 系统会为每个实现了IBinder接口的对象提供跨进程传输能力
    // 即Binder类对象具备了跨进程传输的能力

        void attachInterface(IInterface plus, String descriptor);
        // 作用:
          // 1. 将(descriptor,plus)作为(key,value)对存入到Binder对象中的一个Map<String,IInterface>对象中
          // 2. 之后,Binder对象 可根据descriptor通过queryLocalIInterface()获得对应IInterface对象(即plus)的引用,可依靠该引用完成对请求方法的调用

        IInterface queryLocalInterface(Stringdescriptor) ;
        // 作用:根据 参数 descriptor 查找相应的IInterface对象(即plus引用)

        boolean onTransact(int code, Parcel data, Parcel reply, int flags);
        // 定义:继承自IBinder接口的
        // 作用:执行Client进程所请求的目标方法(子类需要复写)
        // 参数说明:
        // code:Client进程请求方法标识符。即Server进程根据该标识确定所请求的目标方法
        // data:目标方法的参数。(Client进程传进来的,此处就是整数a和b)
        // reply:目标方法执行后的结果(返回给Client进程)
         // 注:运行在Server进程的Binder线程池中;当Client进程发起远程请求时,远程请求会要求系统底层执行回调该方法

        final class BinderProxy implements IBinder {
         // 即Server进程创建的Binder对象的代理对象类
         // 该类属于Binder的内部类
        }
        // 回到分析1原处
}

<-- 分析3:IInterface接口实现类 -->

 public interface IPlus extends IInterface {
          // 继承自IInterface接口->>分析4
          // 定义需要实现的接口方法,即Client进程需要调用的方法
         public int add(int a,int b);
// 返回步骤2
}

<-- 分析4:IInterface接口类 -->
// 进程间通信定义的通用接口
// 通过定义接口,然后再服务端实现接口、客户端调用接口,就可实现跨进程通信。
public interface IInterface
{
    // 只有一个方法:返回当前接口关联的 Binder 对象。
    public IBinder asBinder();
}
  // 回到分析3原处

After registration services, Binderdrivers hold Serverthe process of creating Binderan entity

Step 2: Obtain service

  • ClientUse a process servicebefore (here is the sum function ), to go through Binderthe drive ServiceManagerto obtain the corresponding process Serviceinformation
  • The specific code implementation process is as follows:

Schematic diagram

At this point, Clientthe process and the Serverprocess has established a connection

Step 3: Use the service

ClientThe process according to the obtained Serviceinformation ( Binderproxy object), by Binderdriving the establishment and Servicewhere the Serverlink-process communication, and start using the service

  • Process description

    1. ClientThe process sends the parameters (integer a and b) to the Serverprocess
    2. ServerThe process Clientcalls the target method (that is, the addition function) according to the process requirements
    3. ServerThe process returns the result of the target method (that is, the result after the addition) to the Clientprocess
  • Code implementation process

Step 1: The Clientprocess sends the parameters (integer a and b) to the Serverprocess

// 1. Client进程 将需要传送的数据写入到Parcel对象中
// data = 数据 = 目标方法的参数(Client进程传进来的,此处就是整数a和b) + IInterface接口对象的标识符descriptor
  android.os.Parcel data = android.os.Parcel.obtain();
  data.writeInt(a); 
  data.writeInt(b); 

  data.writeInterfaceToken("add two int");;
  // 方法对象标识符让Server进程在Binder对象中根据"add two int"通过queryLocalIInterface()查找相应的IInterface对象(即Server创建的plus),Client进程需要调用的相加方法就在该对象中

  android.os.Parcel reply = android.os.Parcel.obtain();
  // reply:目标方法执行后的结果(此处是相加后的结果)

// 2. 通过 调用代理对象的transact() 将 上述数据发送到Binder驱动
  binderproxy.transact(Stub.add, data, reply, 0)
  // 参数说明:
    // 1. Stub.add:目标方法的标识符(Client进程 和 Server进程 自身约定,可为任意)
    // 2. data :上述的Parcel对象
    // 3. reply:返回结果
    // 0:可不管

// 注:在发送数据后,Client进程的该线程会暂时被挂起
// 所以,若Server进程执行的耗时操作,请不要使用主线程,以防止ANR


// 3. Binder驱动根据 代理对象 找到对应的真身Binder对象所在的Server 进程(系统自动执行)
// 4. Binder驱动把 数据 发送到Server 进程中,并通知Server 进程执行解包(系统自动执行)

Step 2: The Serverprocess Clientcalls the target method (that is, the addition function) according to the progress requirements

// 1. 收到Binder驱动通知后,Server 进程通过回调Binder对象onTransact()进行数据解包 & 调用目标方法
  public class Stub extends Binder {

          // 复写onTransact()
          @Override
          boolean onTransact(int code, Parcel data, Parcel reply, int flags){
          // code即在transact()中约定的目标方法的标识符

          switch (code) { 
                case Stub.add: { 
                  // a. 解包Parcel中的数据
                       data.enforceInterface("add two int"); 
                        // a1. 解析目标方法对象的标识符

                       int  arg0  = data.readInt();
                       int  arg1  = data.readInt();
                       // a2. 获得目标方法的参数
                      
                       // b. 根据"add two int"通过queryLocalIInterface()获取相应的IInterface对象(即Server创建的plus)的引用,通过该对象引用调用方法
                       int  result = this.queryLocalIInterface("add two int") .add( arg0,  arg1); 
                      
                        // c. 将计算结果写入到reply
                        reply.writeInt(result); 
                        
                        return true; 
                  }
           } 
      return super.onTransact(code, data, reply, flags); 
      // 2. 将结算结果返回 到Binder驱动


Step 3: The Serverprocess returns the result of the target method (ie the result of the addition) to the Clientprocess

  // 1. Binder驱动根据 代理对象 沿原路 将结果返回 并通知Client进程获取返回结果
  // 2. 通过代理对象 接收结果(之前被挂起的线程被唤醒)

    binderproxy.transact(Stub.ADD, data, reply, 0);
    reply.readException();;
    result = reply.readInt();
          }
}
  • Summary
    Below, I use a schematic diagram & flow chart to summarize the content of step 3

Schematic diagram

flow chart


5. Advantages

Compared Linux( Androidbased on Linux) other process communication methods (pipes, message queues, shared memory,
semaphores, Socket), Binderthe advantages of the mechanism are:
Schematic diagram


6. Summary

  • This article explains in detail cross-process communication model Bindermechanism, summarized as follows:

definition

In particular, for the Binder driver composed from the model structure:

Schematic diagram

 

Guess you like

Origin blog.csdn.net/xfb1989/article/details/91354288