Principle of Linux Binder Mechanism

Table of contents

foreword

Table of contents

1. What exactly is Binder?

2. Knowledge reserve

2.1 Process space division

2.2 Process Isolation & Inter-Process Communication (IPC)

2.5 Memory Mapping

3. Binder cross-process communication mechanism model

3.1 Model schematic diagram

3.3 Description of the principles and steps of the model

3.4 Additional Notes

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

Step 1: Sign up for the service

Step 2: Get the service

Step 3: Use the service

5. Advantages


foreword

  • If you have been exposed to inter-process communication (IPC), then you must be familiar with Binder
  • Although there are many articles introducing Binder on the Internet, there are some problems: simply discussing the Binder mechanism or blindly explaining the Binder source code, the logic is not clear, and the final result is that readers still cannot form a complete Binder concept
  • This article uses a clear graphic explanation method to analyze Binder from a large angle -> a small angle, namely:
    1. First analyze the model of the entire Binder cross-process communication mechanism from the perspective of mechanism and model
    2. Then analyze it from the perspective of source code implementation The specific implementation of Binder in Android

Table of contents

1. What exactly is Binder?

  • Chinese is adhesive, which means bonding two different processes
  • There are many definitions of Binder on the Internet, but they are not clear: Binder is a cross-process communication method, it implements the IBinder interface, and is a bridge to connect ServiceManager blabla, it is estimated that everyone is dizzy and cannot understand it well
  • I think: For the definition of Binder, its definition is different in different scenarios

In the explanation of this article, Binder is analyzed according to the large angle -> small angle, namely:

  • First analyze the model of the entire Binder cross-process communication mechanism from the perspective of mechanism and model
Among them, the Binder driver in the model composition will be analyzed in detail
  • From the perspective of source code implementation, analyze the specific implementation of Binder in Android,
    so as to introduce Binder in an all-round way, I hope you will like it.

2. Knowledge reserve

Before explaining Binder, let's understand some basic knowledge of Linux

2.1 Process space division

  • A process space is divided into user space & kernel space (Kernel), that is, to isolate the user & kernel in the process
  • The difference between the two:
    1. Data in user space cannot be shared between processes, so user space = non-shareable space
    2. Data in kernel space can be shared between processes, so kernel space = shareable space
All processes share 1 kernel space
  • In-process user space & kernel space need to interact through system calls, mainly through functions:
copy_from_user(): Copy data from user space to kernel space copy_to_user(): Copy data from kernel space to user space

2.2 Process Isolation & Inter-Process Communication (IPC)

  • Process isolation In order to ensure security & independence, one process cannot directly operate or access another process, that is, Android processes are independent and isolated from each other
  • Inter-process communication (IPC) means data interaction and communication between processes
  • Fundamentals of inter-process communication

a. The role of Binder is: to connect two processes, realize the mmap() system call, and is mainly responsible for creating a buffer space for data reception & managing data reception cache b. Note: traditional cross-process communication needs to copy data twice, But the Binder mechanism only needs to be used once, mainly because memory mapping is used, which will be described 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 diagram

Binder cross-process communication mechanism model is based on Client-Server mode

3.2 Model Composition Role Description

Here we will focus on explaining the function & principle of the Binder driver:

  • Introduction

  • The core principle of cross-process communication
About its core principle: memory mapping, please see the article for details: Operating system: memory mapping

3.3 Description of the principles and steps of the model

3.4 Additional Notes

Note 1: The interaction between the Client process, Server process & Service Manager process must be driven by Binder (using open and ioctl file operation functions), rather than direct interaction

reason:

1. The Client process, Server process & Service Manager process belong to the user space of the process space, and inter-process interaction is not allowed. 2. The Binder driver belongs to the kernel space of the process space, and can perform inter-process & intra-process interaction. Therefore, the schematic diagram can be expressed as follows :

Dotted lines indicate non-direct interaction

Note 2: The Binder driver & Service Manager process belongs to the Android infrastructure (that is, the system has been implemented); while the Client process and Server process belong to the Android application layer (the developer needs to implement it himself)

Therefore, when performing cross-process communication, developers only need to customize the Client & Server process and explicitly use the above three steps, and finally complete inter-process communication with the help of Android's basic architecture functions

Description 3: Thread management for Binder requests

  • The Server process will create many threads to process Binder requests
  • The thread management of the Binder model adopts the thread pool driven by Binder, and is managed by the Binder driver itself
Rather than managed by the Server process
  • The default maximum number of Binder threads for a process is 16. Exceeding requests will be blocked waiting for idle Binder threads.
Therefore, when dealing with concurrency issues during inter-process communication, such as when using ContentProvider, its CRUD (create, retrieve, update, and delete) method can only have 16 threads working at the same time
  • So far, I believe that everyone has a very clear qualitative understanding of the Binder cross-process communication mechanism model
  • Below, I will use an example to analyze the specific code implementation of the Binder cross-process communication mechanism model in Android
That is to analyze how the above steps are implemented in Android with code

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

  • The implementation of the Binder mechanism in Android mainly relies on the Binder class, which implements the IBinder interface
will be detailed below
  • Example description: The Client process needs to call the addition function of the Server process (to add the integers a and b)
That is: 1. The Client process needs to pass two integers to the Server process 2. The Server process needs to return the added result to the Client process
  • Specific steps
    Below, I will analyze the steps of the Binder cross-process communication mechanism model

Step 1: Sign up for the service

  • Process description
    The Server process registers services with the Service Manager process through the Binder driver
  • The code realizes that
    the Server process creates a Binder object
1. The Binder entity is the existence form of the Server process in the Binder driver. 2. This object saves the information of the Server and ServiceManager (stored in the kernel space). 3. The Binder driver finds the Server object in the user space through the Binder entity in the 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 registering the service, the Binder driver holds the Binder entity created by the Server process

Step 2: Get the service

  • Before the Client process uses a certain service (here is the addition function), it must obtain the corresponding Service information from the ServiceManager process through the Binder driver
  • The specific code implementation process is as follows:

At this point, the Client process has established a connection with the Server process

Step 3: Use the service

According to the obtained Service information (Binder proxy object), the Client process establishes a communication link with the Server process where the Service is located through the Binder driver, and starts to use the service

  • process description

The client process sends the parameters (integers a and b) to the server process. The server process calls the target method (that is, the addition function) according to the requirements of the client process. The server process returns the result of the target method (that is, the result after addition) to the client process.

  • code implementation process

Step 1: Client process sends parameters (integer a and b) to Server process

// 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 Server process calls the target method (that is, the addition function) according to the client's incoming 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 Server process returns the result of the target method (that is, the result after addition) to the Client process

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

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

5. Advantages

Compared with other process communication methods (pipeline, message queue, shared memory, semaphore, Socket) on Linux (Android is based on Linux), the advantages of the Binder mechanism are:

  1. Summarize
  • This article mainly explains in detail the Binder mechanism of the cross-process communication model, which is summarized as follows:

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

  • Principle steps & source code analysis of the entire Binder model

Guess you like

Origin blog.csdn.net/m0_64560763/article/details/131132658