Binder principle analysis for Android Application Engineers
Programmer meow 2021-08-09 18:52:45

Original address :zhuanlan.zhihu.com/p/35519585

Original author : Zhang Lei

One . Preface

Binder The complexity is far from clear in an article , This article wants to stand in a higher dimension to overlook Binder The design of the , Finally help everyone form a complete concept . For students of application layer development , It's almost enough to understand this article .

Two . Binder summary

Give me a brief introduction to Binder.Binder It's an inter process communication mechanism , Open source based OpenBinder Realization ;OpenBinder At first, by Be Inc. Development , After by Plam Inc. To take over . Literally Binder There's glue 、 Adhesive means , As the name suggests, it is sticky and different processes , Make it possible to communicate . about Binder A more comprehensive definition , After we introduce Binder The communication principle will be explained in detail later .

2.1 Why must we understand Binder ?

As Android Engineer's you , Is there often such a question :

  • Why? Activity Objects to be passed between need to be serialized ?
  • Activity What is the start-up process ?
  • What is the underlying communication mechanism of the four components ?
  • AIDL What is the internal implementation principle ?
  • Where should plug-in programming technology start ? wait ...

These problems are related to Binder There is a great deal of connection , Understand the above questions Bidner Communication mechanism is necessary .

We know Android The application is created by Activity、Service、Broadcast Receiver and Content Provide Consisting of one or more of the four components . Sometimes these components run in the same process , Sometimes it runs in different processes . The communication between these processes depends on Binder IPC Mechanism . More Than This ,Android Various services provided by the system to the application layer, such as :ActivityManagerService、PackageManagerService And so on Binder IPC Mechanism to implement .Binder Mechanism in Android The position in the is very important , It is no exaggeration to say that I understand Binder It's towards Android The first step in advanced engineering .

2.2 Why Binder ?

Android The system is based on Linux Kernel ,Linux Pipes have been provided 、 Message queue 、 Shared memory and Socket etc. IPC Mechanism . What then? Android Also provide Binder To achieve IPC Well ? Mainly based on performance stability and Security Several reasons .

performance

First, let's talk about the performance advantages .Socket As a universal interface , Its transmission efficiency is low , Spending big , It is mainly used for inter process communication across the network and low-speed communication between processes on the machine . Message queues and pipes use storage - Forwarding method , That is, the data is first copied from the sender's cache to the cache opened by the kernel , Then copy from the kernel cache to the receiver cache , There are at least two copy processes . Shared memory doesn't need to be copied , But the controls are complicated , Difficult to use .Binder Only one copy of the data is required , Second only to Shared memory in performance . notes : Various IPC Mode data copy times , This table comes from Android Binder Design and implementation - Design

IPC The way Number of data copies
Shared memory 0
Binder 1
Socket/ The Conduit / Message queue 2

stability

And stability ,Binder be based on C/S framework , client (Client) If you need anything, you can leave it to the server (Server) To complete , Clear architecture 、 Responsibilities are clear and independent , Better natural stability . Shared memory doesn't need to be copied , But control is responsible , Difficult to use . In terms of stability ,Binder The mechanism is superior to memory sharing .

Security

The other is security .Android As an open platform , There are various massive applications on the market for users to choose and install , So security is important for Android The platform is extremely important . As users, of course, don't want us to download APP Secretly read my address book , Upload my privacy data , Backstage sneak traffic 、 Power consumption of mobile phone . Conventional IPC There are no safety measures , Rely entirely on the upper layer protocol to ensure . First, the traditional IPC The receiver cannot obtain the reliable process user of the other party ID/ process ID(UID/PID), So we can't identify each other .Android For each installed APP Assign your own UID, So the process UID It is an important marker to identify a process . Conventional IPC It can only be filled in by the user in the data package UID/PID, But it's not reliable , Easy to be used by malicious programs . Reliable identification only by IPC The mechanism adds... To the kernel . Secondly, the traditional IPC Access points are open , As long as you know the programs of these access points can establish connection with the opposite end , In no way can a malicious program be prevented from getting a connection by guessing the address of the receiver . meanwhile Binder Both support real name Binder, And support anonymity Binder, High safety .

For the above reasons ,Android A new set of IPC Mechanism to meet the stability of the system 、 Requirements for transmission performance and security , This is it. Binder.

Finally, use a table to summarize Binder The advantages of :

advantage describe
performance Only one copy of the data is required , Second only to Shared memory in performance
stability be based on C/S framework , Clear responsibilities 、 Clear architecture , Therefore, the stability is good
Security For each APP Distribute UID, Process UID It is an important marker to identify a process

3、 ... and . Linux Under the traditional principle of interprocess communication

understand Linux IPC Related concepts and principles help us understand Binder Communication principle . therefore , Introducing Binder Before the principle of cross process communication , Let's talk about Linux How to realize the traditional inter process communication under the system .

3.1 Introduction to basic concepts

Here we start with Linux Some basic concepts involved in interprocess communication are introduced , Then step by step , Explain the principle of traditional interprocess communication .

Liunx The basic concepts involved in cross process communication :

  • Process isolation
  • Process space partition : User space (User Space)/ Kernel space (Kernel Space)
  • system call : User mode / Kernel mode

Process isolation

Simply put, in the operating system , Memory between processes is not shared . Two processes are like two parallel worlds ,A The process cannot directly access B Process data , This is the popular explanation of process isolation .A The process and B Special communication mechanism must be adopted for data interaction between processes : Interprocess communication (IPC).

Process space partition : User space (User Space)/ Kernel space (Kernel Space)

Now the operating system adopts virtual memory , about 32 Bit system , Its addressing space ( Virtual storage space ) Namely 2 Of 32 Power , That is to say 4GB. The core of the operating system is the kernel , Independent of ordinary applications , Access to protected memory space , You can also access the permissions of the underlying hardware devices . In order to protect the user process can not directly operate the kernel , Keep the kernel safe , The operating system logically divides the virtual space into user space (User Space) And kernel space (Kernel Space). in the light of Linux In terms of operating system , Will be the highest 1GB Bytes for kernel use , It's called kernel space ; Lower 3GB Bytes for each process , It's called user space .

Simply put , Kernel space (Kernel) Is the space where the system kernel runs , User space (User Space) Is the space where user programs run . To ensure safety , They are isolated .

system call : User mode and kernel mode

Although the user space and kernel space are logically divided , But inevitably, user space requires access to kernel resources , Like file manipulation 、 Access to the network, etc . In order to break through the isolation limit , We need help from system call To achieve . System calls are the only way user space can access kernel space , It ensures that all resource access is under the control of the kernel , It avoids the user program's unauthorized access to system resources , Improve the security and stability of the system .

Linux Use a two-level protection mechanism :0 Level is used by the system kernel ,3 Level is used by user programs .

When a task ( process ) When a system call is executed and gets stuck in kernel code , Call the process in Kernel running state ( Kernel mode ) . At this time, the processor is at the highest privilege level (0 level ) Execute... In kernel code . When the process is in kernel state , The executed kernel code will use the kernel stack of the current process . Each process has its own kernel stack .

When the process is executing the user's own code , We call it in User running status ( User mode ) . At this time, the processor is at the lowest privilege level (3 level ) Run... In user code .

The system call is mainly realized through the following two functions :

copy_from_user() // Copy data from user space to kernel space
copy_to_user() // Copy data from kernel space to user space
 Copy code 

3.2 Linux Under the tradition of IPC Communication principle

Understand the above concepts , Let's take a look at the traditional IPC In the way , How processes communicate .

It is common practice for the message sender to store the data to be sent in the memory cache , Enter kernel state through system call . Then kernel program allocates memory in kernel space , Open up a kernel cache , call copy_from_user() Function to copy data from the memory cache in user space to the kernel cache in kernel space . alike , When receiving data, the receiver process creates a memory buffer in its own user space , Then the kernel program calls copy_to_user() Function to copy data from the kernel cache to the memory cache of the receiving process . In this way, the data sender process and the data receiver process complete a data transmission , We call it an inter process communication .

This traditional IPC There are two problems with communication :

  1. Poor performance , A data transfer needs to go through : Memory cache --> Kernel cache --> Memory cache , need 2 Secondary data copy ;

  2. The buffer for receiving data is provided by the data receiving process , But the receiving process doesn't know how much space is needed to store the data to be transferred , So we can only open up as much memory space as possible or call first API Receive the header to get the size of the message body , These two methods are either a waste of space or a waste of time .

Four . Binder Principle of cross process communication

I understand Linux IPC Related concepts and communication principles , Now let's formally introduce Binder IPC Principle .

4.1 Dynamic kernel loadable module && Memory mapping

As mentioned earlier , Cross process communication requires kernel space support . Conventional IPC Mechanisms such as pipes 、Socket Are all part of the kernel , Therefore, inter process communication through kernel support is naturally no problem . however Binder Not at all Linux Part of the system kernel , Then what shall I do? ? This benefits from Linux Of Dynamic kernel loadable module (Loadable Kernel Module,LKM) The mechanism of ; Modules are programs with independent functions , It can be compiled separately , But it can't run independently . It is linked to the kernel at runtime and runs as part of the kernel . such ,Android The system can run in the kernel space by dynamically adding a kernel module , User processes communicate with each other through this kernel module as a bridge .

stay Android In the system , This runs in kernel space , Responsible for each user process through Binder The kernel module for communication is called  Binder drive (Binder Dirver).

So in Android How user processes in the system pass through this kernel module (Binder drive ) To achieve communication ? Is it the same as the tradition mentioned above IPC The mechanism is the same , First copy the data from the sender process to the kernel cache , Then copy the data from the kernel cache to the receiver process , Is it achieved by two copies ? Obviously not , Otherwise, there will be no opening Binder In terms of performance .

This has to be the channel Linux Another concept under : Memory mapping .

Binder IPC The memory mapping involved in the mechanism is through mmap() To achieve ,mmap() Is a memory mapping method in the operating system . Memory mapping is simply to map a block of memory area of user space to kernel space . After the mapping relationship is established , The user's modification of this memory area can directly reflect the kernel space ; On the other hand, the kernel space modification of this area can also directly reflect the user space .

Memory mapping can reduce the number of data copies , Achieve efficient interaction between user space and kernel space . The changes of the two spaces can be directly reflected in the mapped memory area , So as to be perceived by each other's space in time . That's why , Memory mapping can provide support for inter process communication .

4.2 Binder IPC Realization principle

Binder IPC It's based on memory mapping (mmap) To achieve , however mmap() Usually used on file systems with physical media .

For example, the user area in the process cannot directly deal with physical devices , If you want to read the data on the disk to the user area of the process , It takes two copies ( disk --> Kernel space --> User space ); Usually in this scenario mmap() It works , By mapping between physical media and user space , Reduce the number of copies of data , Replace... With memory reading and writing I/O Reading and writing , Improve the efficiency of file reading .

and Binder There is no physical medium , therefore Binder Driver USES mmap() It's not about mapping between physical media and user space , It's used to create a cache space for data reception in kernel space .

Once complete Binder IPC The communication process is usually like this :

  1. First Binder The driver creates a data receiving buffer in kernel space ;
  2. And then open a kernel cache in kernel space , establish Kernel cache and Data receiving buffer in kernel Mapping between , as well as Data receiving buffer in kernel and Receive process user space address The mapping relation of ;
  3. Sender process through system call copy_from_user() Put the data copy Into the kernel Kernel cache , Due to the memory mapping between the kernel cache and the user space of the receiving process , Therefore, it is equivalent to sending data to the user space of the receiving process , This completes a communication between processes .

5、 ... and . Binder Communication model

Introduction after Binder IPC Underlying communication principle of , Next, let's look at how the implementation level is designed .

A complete inter process communication must contain at least two processes , Usually, we call the two sides of communication the client process (Client) And server processes (Server), Due to the existence of process isolation mechanism , Both sides of communication must rely on Binder To achieve .

5.1 Client/Server/ServiceManager/ drive

We talked about that earlier ,Binder Is based on C/S Architecturally . It consists of a series of components , Include Client、Server、ServiceManager、Binder drive . among Client、Server、Service Manager Run in user space ,Binder The driver runs in kernel space . among Service Manager and Binder The drive is provided by the system , and Client、Server Implemented by an application .Client、Server and ServiceManager All through system calls open、mmap and ioctl To access device files /dev/binder, So as to realize and Binder Drive interaction to indirectly realize cross process communication .

Client、Server、ServiceManager、Binder The role of driving these components in the communication process is just like the server in the Internet (Server)、 client (Client)、DNS Domain name server (ServiceManager) And routers (Binder drive ) Previous relationship .

Usually the steps we take to visit a web page are as follows : First enter an address in the browser , Such as  www.google.com  Then press enter . But there is no way to directly find the server we want to access through the domain name address , Therefore, you need to visit DNS Domain name server , The domain name server saved  www.google.com  Corresponding ip Address 10.249.23.13, And then through this ip The address can be put to  www.google.com  Corresponding server .

5.3 Binder Agent mode in communication

We have explained Client、Server With the help of Binder Drive the implementation mechanism of cross process communication , But there's another question that will confuse us .A The process wants B An object in the process (object) How to achieve it ? After all, they belong to different processes ,A process I can't use it directly B In process object.

We have introduced the process of cross process communication before Binder Driven participation , So in the data flow Binder When driving, the driver will make a layer of data conversion . When A The process wants to get B In process object when , Driving doesn't really put object Return to A, But back to a heel object It looks as like as two peas objectProxy, This objectProxy With and object The same way , But these methods do not B In progress object The ability to target those methods , These methods only need to give the request parameters to the driver . about A Process and direct call object The method in is the same .

When Binder The driver receives A After the process message , Find out this is a objectProxy Just check the form you maintain , A search revealed that it was B process object Proxy object of . So I'll call B Process call object Methods , And ask the B The process sends the returned result to itself . When the driver gets B The return result of the process will be forwarded to A process , One communication is done .

5.4 Binder Complete definition

Now we can deal with Binder Make a more comprehensive definition :

  • From the perspective of interprocess communication ,Binder It's a mechanism of inter process communication ;
  • from Server From the perspective of process ,Binder refer to Server Medium Binder Entity object ;
  • from Client From the perspective of process ,Binder It means right Binder Proxy object , yes Binder A remote agent for entity objects
  • From the perspective of transmission process ,Binder Is an object that can be transferred across processes ;Binder The driver will do a little bit of special work with this object that crosses the process boundary , Automatic conversion between proxy and local objects .

6、 ... and . Manual coding enables cross process calls

Usually when we do development , The most used to realize interprocess communication is AIDL. When we define AIDL file , At compile time, the compiler will help us generate code implementation IPC signal communication . With the help of AIDL The compiled code can help us further understand Binder IPC The principle of communication .

But in terms of readability and comprehensibility , Compiler generated code is not developer friendly . For example, a BookManager.aidl The corresponding file will generate a BookManager.java file , This java The file contains a BookManager Interface 、 One Stub Static abstract class and a Proxy Static class .Proxy yes Stub The static inner class of ,Stub again BookManager The static inner class of , This creates the problem of readability and comprehensibility .

Android The reason why this design actually makes sense , Because when there are multiple AIDL Put... When you file BookManager、Stub、Proxy Putting it in the same file can effectively avoid Stub and Proxy The problem of duplicate names .

Therefore, it is easy for everyone to understand , Let's write code manually to implement cross process calls .

6.1 various Java Class responsibility description

Before formal coding to implement cross process calls , First introduce some classes used in the implementation process . Understand the responsibilities of these classes , It helps us better understand and realize cross process communication .

  • IBinder : IBinder It's an interface , Represents a cross process communication capability . As long as this excuse is realized , This object can be transferred across processes .
  • IInterface : IInterface It stands for Server What capabilities do process objects have ( What methods can be provided , In fact, it corresponds to AIDL The interface defined in the file )
  • Binder : Java Layer of Binder class , It actually represents Binder Local object .BinderProxy Class is Binder An inner class of a class , It represents the name of the remote process Binder Object's local agent ; Both classes inherit from IBinder, So they all have the ability to transmit across processes ; actually , When crossing the process ,Binder The driver will automatically complete the conversion of these two objects .
  • Stub : AIDL When , The compiler tool will generate a file named Stub The static inner class of ; This class inherits Binder, That means it's a Binder Local object , It has achieved IInterface Interface , It shows that it has Server Promise to Client The ability of ;Stub Is an abstract class , Concrete IInterface The related implementation of requires developers to implement .

6.2 Explain the implementation process

A cross process communication must involve two processes , In this case RemoteService As a server process , Provide services ;ClientActivity As a client process , Use RemoteService Services provided . Here's the picture :

What capabilities does the server process have ? What kind of services can be provided for the client ? Remember what we introduced earlier IInterface Do you , It represents the specific capabilities of the server process . So we need to define a BookManager Interface ,BookManager Inherited from IIterface, Show what capabilities the server has .

/**
* This class is used to define the server RemoteService What kind of ability do you have
*/
public interface BookManager extends IInterface {
void addBook(Book book) throws RemoteException;
}
 Copy code 

It is not enough to define the capabilities of the server , Since it is a cross process call , Then we have to implement a cross process call object Stub.Stub Inherit Binder, That means it's a Binder Local object ; Realization IInterface Interface , Indicates that there is Server Promise to Client The ability of ;Stub Is an abstract class , Concrete IInterface The relevant implementation of needs to be implemented by the caller itself .

public abstract class Stub extends Binder implements BookManager {
public static BookManager asInterface(IBinder binder) {
if (binder == null)
return null;
IInterface iin = binder.queryLocalInterface(DESCRIPTOR);
if (iin != null && iin instanceof BookManager)
return (BookManager) iin;
return new Proxy(binder);
}
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION:
reply.writeString(DESCRIPTOR);
return true;
case TRANSAVTION_addBook:
data.enforceInterface(DESCRIPTOR);
Book arg0 = null;
if (data.readInt() != 0) {
arg0 = Book.CREATOR.createFromParcel(data);
}
this.addBook(arg0);
reply.writeNoException();
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
 Copy code 

Stub Class, we focus on  asInterface  and  onTransact.

Let's talk about it first.  asInterface, When Client Create a connection with the server side , call bindService You need to create a ServiceConnection Object as input parameter . stay ServiceConnection The callback method onServiceConnected in It will go through this asInterface(IBinder binder) Get BookManager object , This IBinder type binder It's the driver that passed it on to us , As you can see in the code , Method will call binder.queryLocalInterface() Go find Binder Local object , If you find it, it means Client and Server In the same process , So this binder Itself is Binder Local object , You can use it directly . Otherwise, it means binder It's a remote object , That is to say BinderProxy. So we need to create a proxy object Proxy, Remote access is achieved through this proxy object .

Next, we will implement the proxy class Proxy 了 , Since it is a proxy class, you naturally need to implement BookManager Interface .

public class Proxy implements BookManager {
...
public Proxy(IBinder remote) {
this.remote = remote;
}
@Override
public void addBook(Book book) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel replay = Parcel.obtain();
try {
data.writeInterfaceToken(DESCRIPTOR);
if (book != null) {
data.writeInt(1);
book.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
remote.transact(Stub.TRANSAVTION_addBook, data, replay, 0);
replay.readException();
} finally {
replay.recycle();
data.recycle();
}
}
}
 Copy code 

Let's see. addBook() The implementation of the ; stay Stub Class ,addBook(Book book) It's an abstract method ,Client The client needs to inherit and implement it .

  • If Client and Server In the same process , Then you just call this method .
  • If it's a remote call ,Client Want to call Server The method needs to pass Binder Agent to complete , That's the top Proxy.

stay Proxy Medium addBook() Method first through Parcel Serialize data , And then call remote.transact(). As mentioned earlier Proxy Is in Stub Of asInterface Created in , Can go to create Proxy This step shows Proxy The arguments to the constructor are BinderProxy, That is here remote It's a BinderProxy object . Finally, through a series of function calls ,Client Processes fall into kernel state through system calls ,Client In process execution addBook() Thread is suspended waiting to return ; The driver wakes up after a series of operations Server process , call Server Process local object onTransact(). Finally came to Stub Medium onTransact() in ,onTransact() Call related functions according to the function number ( stay Stub Class is BookManager A number is defined in each function in the interface , But in the above source code, we simplified ; When calling across processes , Instead of passing a function, you pass a number to indicate which function to call ); In our case , Called Binder Local object addBook() And return the result to the driver , Drive wake up Client The thread just suspended in the process and returns the result .

In this way, a cross process call is completed .

Finally, I suggest that you do not use AIDL In the case of handwriting Client and Server Process communication , To deepen the Binder Understanding of the communication process .

Limited by personal ability level , There are bound to be mistakes in the article . If you find the shortcomings of the article , Welcome to communicate with me .

official account : Programmer meow ( Focus on Android All kinds of study notes 、 Interview questions and IT Sharing of such information .)

Please bring the original link to reprint ,thank
Similar articles

2021-08-09

2021-08-09