Android Binder Design and Implementation 4

Source: Internet
Author: User

5 Binder statement

During the entire Binder communication process, we can find that the Binder exists in the following parts of the system:

· Application processes: Server Processes and Client Processes

· Binder DRIVER: Server and Client have different expressions

· Data Transmission: Since the Binder can be transferred across processes, it must be expressed in the transmitted data.

In different parts of the system, the functions implemented by the Binder are different in different forms. Next we will discuss the roles and data structures used by the Binder in each part one by one.

5.1 statement of the Binder in the Application

Although the Binder uses the object-oriented idea, it does not limit the application to use the object-oriented language. Both C and C ++ can easily use the Binder for communication. For example, although Android mainly uses java or C ++, an important process like SMgr is implemented in C language. However, the object-oriented method is more convenient to express, so this article assumes that the application is implemented in object-oriented language.

The Binder is essentially an underlying communication method and has nothing to do with a specific service. To provide specific services, the Server must provide a set of interface functions for the Client to remotely access various services. In this case, the Proxy design mode is usually used: the interface function is defined in an abstract class, and both the Server and Client use this abstract class as the base class to implement all interface functions, what is different is that the Server side is the real function implementation, and the Client side is the packaging of Remote Call requests for these functions. How to combine the Binder and Proxy design patterns is the fundamental problem for the application to implement object-oriented Binder communication.

5.1.1 Binder expression on the Server-Binder entity

As the basis of the Proxy design pattern, an abstract interface class is defined to encapsulate all the functions of the Server, including a series of pure virtual functions to be implemented by the Server and Proxy respectively. Because these functions need to be called across processes, they must be numbered one by one, so that the Server can decide which function to call based on the number received. Next, we need to introduce the Binder. The Server defines another Binder abstract class to process the Binder request data packets from the Client. The most important member is the virtual function onTransact (). This function analyzes the received data packet and calls the corresponding interface function to process the request.

Next, we use the Inheritance Method to Construct the entity of the Binder on the Server using the interface class and the Binder abstract class as the base class, and implement all the virtual functions in the base class, including public interface functions and data packet processing functions: onTransact (). The input of this function is a data packet from the Client's binder_transaction_data structure. As mentioned above, there is a member code in this structure that contains the interface function number of this request. OnTransact () parses the code value in case-by-case mode, extracts the function parameters from the data packet, and calls the corresponding public interface functions in the interface class. After the function is executed, construct a binder_transaction_data package and enter the returned data packet.

When Will onTransact () of each Binder object be called? This requires driver participation. As mentioned above, the Binder object must be sent to other processes in the form of flat_binder_object transmitted by Binde to establish the Binder communication, and the Binder Object Pointer is stored in the handle domain of the structure. The driving root data Binder position array obtains the Transmission Structure of the Binder from the transmitted data, creates a Binder node in the kernel for it, and records the Binder object pointer in the node. If another process sends data to the Binder, the driver fills in the Binder object pointer in the target. ptr of binder_transaction_data according to the information recorded in the node and returns the data to the receiving thread. The receiving thread retrieves the pointer from the data packet. reinterpret_cast is a binary abstract class and the onTransact () function is called. Because this is a virtual function, different Binder entities have their own implementations, so that they can call onTransact () provided by different Binder entities ().

5.1.2 Binder Statement on the Client-Binder reference

As part of the Proxy design pattern, the Client-side Binder must inherit the public interface classes provided by the Server and implement public functions. But this is not a real implementation, but a packaging of remote function calls: Package function parameters, send an application to the Server through the Binder, and wait for the return value. Therefore, the Client-side Binder also needs to know the information about the Binder object, that is, the reference to the Binder object. This reference is either a reference to the real-name Binder or a reference to the anonymous Binder that is directly sent by another process.

Because it inherits the same public interface class, the Client Binder provides the same function prototype as the Server Binder, making the user feel that the Server is running locally or remotely. In Client Binder, the implementation of common interface functions is: Create a binder_transaction_data packet, enter the corresponding encoding into the code field, and fill in the parameters required to call this function with data. buffer points to the cache and specifies the destination of the data packet, that is, the reference to the Binder entity that has been obtained, and fill in the target of the data packet. handle. Note the difference between this and Server: in fact, the target domain is a consortium, including ptr and handle. The former is used as the Server of the responder and points to the memory space corresponding to the Binder object; the latter is used as the Client of the requester to store the reference of the Binder object and inform the driver of the object to which the data packet will be routed. After the data packet is ready, it is sent through the driver interface. Call the function remotely and obtain the return value after the BC_TRANSACTION/BC_REPLY round.

5.2 Statement of Binder in Data Transmission

The Binder can be inserted into the valid data of the data packet. The process boundary is transferred from one process to another. The Binder in the transmission is represented by the structure flat_binder_object, as shown in the following table:

Table 6 Binder Transmission Structure: flat_binder_object

Member Description
Unsigned long type Indicates the type of the Binder, including the following:
BINDER_TYPE_BINDER: It indicates that the Binder object is passed and the references to this object are strongly typed;
BINDER_TYPE_WEAK_BINDER: It indicates that the Binder object is passed, and references to this object are weak types;
BINDER_TYPE_HANDLE: indicates that a reference with a strong Binder type is passed.
BINDER_TYPE_WEAK_HANDLE: indicates that references of weak Binder types are passed.
BINDER_TYPE_FD: the file-format Binder is passed. For details, see the following section.
Unsigned long flags This field is only valid when the Binder object is passed for the first time, because at this moment, the driver needs to create the corresponding entity node in the kernel, and some parameters need to be retrieved from this field:
0-7 bits: Use FLAT_BINDER_FLAG_PRIORITY_MASK in the code to obtain the lowest priority of the thread that processes the request data packets of this entity. When an application provides multiple objects, you can use this parameter to adjust the processing capabilities assigned to each object.
8th bits: the code is obtained using FLAT_BINDER_FLAG_ACCEPTS_FDS. If this parameter is set to 1, the entity can receive Binder files sent by other processes. Because the received file-form Binder will automatically open the file in this process, some servers can use this flag to disable this function to prevent too many files from being opened.
Union {
Void * binder;
Signed long handle;
};
When the Binder object is passed, the binder domain is used to point to the address of the Binder object in the application.
The handle field is used to store the reference number of the Binder in the process when the Binder is referenced.
Void * cookie; This field is only valid for the Binder object and stores additional information related to this Binder.
 

Both the Binder object and the reference to the object are subordinate to a process. Therefore, the structure cannot be transparently transmitted between processes and must be driven. For example, when the Server passes the Binder object to the Client, the type in flat_binder_object in the sent data is BINDER_TYPE_BINDER, and the binder points to the Server process user space address. If passthrough is useless to the receiver, the driver must modify the Binder in the data stream to BINDER_TYPE_HANDLE; create a reference in the kernel for this Binder in the receiving process and enter the reference number in handle. The Binder of the reference type in the data stream must also be converted. After processing, the Binder reference obtained by the receiving process from the data stream is valid. You can fill in the target. handle field of the data packet binder_transaction_data to send a request to the Binder entity.

This is also for security considerations: the application cannot randomly guess a reference number and fill in the target. handle can request services from the Server. Because the driver does not create this reference for you in the kernel, the driver will be rejected. Only the Binder granted to you by The 'authorization' can be used after the authentication is confirmed legal, because the driver has already created a reference for you in the kernel, the quote number given to you is legal.

The following table summarizes the operations performed by the driver when the flat_binder_object structure passes through the driver:

Table 7 driver operations on flat_binder_object

BinderType (TypeDomain) Actions on the sender Operations on the receiver
BINDER_TYPE_BINDER
BINDER_TYPE_WEAK_BINDER
Only the process where the object is located can send this type of Binder. If this is the first time the driver is sent, it will create an entity node in the kernel and save the binder, cookie, and flag Fields. If this is the first time you receive the Binder, create an object reference in the kernel. Replace the handle field with the new reference number. Replace the type field with BINDER_TYPE _ (WEAK _) HANDLE.
BINDER_TYPE_HANDLE
BINDER_TYPE_WEAK_HANDLE
All processes referenced by the Binder can send this type of Binder. The driver searches for references established in the kernel based on the reference number provided by the handle domain. If the reference number is valid, the request is rejected. If the received Binder object is in the receiving process: Replace the ptr domain with the binder value in the existing node, the cookie with the cookie value in the existing node, and the type with BINDER_TYPE _ (WEAK _) BINDER.
If the received Binder object is not in the receiving process: if it is received for the first time, a reference of the object is created in the kernel; replace the handle field with the new reference number.
BINDER_TYPE_FD Verify whether the opened file number provided in the handle domain is valid. If the value is invalid, the sending request is rejected. Create a new open file number on the receiver and bind it with the provided open file description structure.

5.2.1 file format Binder

In addition to the Binder used for communication, there is also a special Binder: file Binder. The basic idea of this kind of Binder is to regard the file as the Binder entity, and the file number opened by the process as the reference of the Binder. A process can pass the file number of the opened file to another process, and the other process opens the same file, just as the reference of the Binder is transmitted between processes.

When a process opens a file, it obtains the number of open files bound to the file. From the perspective of the Binder, the description structure of the Open file Created by linux in the kernel, struct file is the entity of the Binder, and the open file number is the reference of the process to the entity. Since it is a Binder, it can be transferred between processes. Therefore, you can also use the flat_binder_object structure to send the file Binder to other processes through data packets. The value of the type field in the structure is BINDER_TYPE_FD, indicates that the Binder is a file Binder. The handle field in the structure stores the open file number of the file in the sender's process. We know that opening a file number is a value limited to a specific process. It makes no sense to open a file number across processes. This is the same as the Binder Object User pointer or Binder reference number. If you want to cross-process conversion, the driver must also perform the conversion. The driver creates a new open file number in the process space that receives the Binder and hooks it with the existing open file description structure struct file. Therefore, this Binder entity has another reference. The new open file number overwrites the original file number in flat_binder_object and submits it to the receiving process. The receiving process can be used to perform file operations such as read () and write.

Why is it so troublesome to upload a file? You can directly upload the file name to the receiver using the Binder. Is it okay if the receiver uses open () to open the file? In fact, there is a difference. First, there are different levels of Open file Sharing: files opened by using the file Binder share the struct file, struct dentry, and struct inode structure in linux VFS, which means that a process uses read () /write ()/seek () changes the file pointer of another process. If the two processes use the file name to open the same file, they have their own struct file structure, in this way, the file pointers are maintained independently without mutual interference. Second, some special device files must be shared at the struct file level. For example, ashmem, another android driver, is also a misc device like the Binder to implement shared memory between processes. Only when the ashmem file opened by a process is sent to another process through the file Binder can the memory be shared, which greatly improves the security of Memory sharing. The reason is that the Binder enhances the security of IPC.

From LuoXianXiong, your partner

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.