In the last article, we saw the benefits of using Binder for interprocess communication in Android by comparing the way Linux processes communicate. This article will take a look at Binder’s architectural design for Android.
What is a Binder?
For security, stability, memory management and other reasons, Android applications and system services run in an independent process, but the system services and application processes, application process A and application process B need to communicate and share data. As a result,The Android system needs to provide a set of efficient and secure cross-process communication solutions. Binder came into being.
- Security: Each application runs in a separate process, and the system assigns a unique ID, UID, to each process
- Stable: Because each app runs in a separate process, a bug or crash in one app has no impact on the others.
- Memory management: When a process is destroyed, resources occupied by the process are removed from memory and the allocated memory is reclaimed.
Note: Actually, different components in a single app (activities, services, for example) can run in different processes.
Different Android apps run in different processes. The figure above shows interprocess communication (IPC) between applications, interprocess communication (IPC) between application layer and FrameWork layer, interprocess communication (IPC) between FrameWork and Native layer, interprocess communication (IPC) between application layer and Native layer. Binder communication is used in most of the scenarios in this diagram. Binder is important in Android.
summary
Binder is an efficient and secure cross-process communication framework provided in Android.
Binder structure design
As shown in the picture above, it is divided into five layers:
- Application layer: the client and server logic that the developer deals with
- AIDL: this is the AIDL. Exe file automatically help us to define our own AIDL files into Java files. There are two inner classes Proxy and Stub. They represent the sender and the receiver respectively.
- FrameWork layer: Proxy class generated by AIDL layer will call methods in IBinder in FrameWork layer. IBinder implementation class in this layer is BinderProxy, so it will call methods in BinderProxy. On the receiving side of the data, Binder classes will handle it,
- Native layer: The sender is BpBinder and the receiver is BBinder.
- Kernel layer: Binder drivers. This article will not explain
The point of this article is to clarify the overall process. Don’t go into too much detail.
Binder communication
- The client wants to establish link communication with the server
2. Because two processes cannot communicate with each other directly (reading and writing data), different applications can communicate with each other by passing data through the kernel, Binder drivers can be used.
Binder driven by open/dev/Binder provides, release, poll, mmap, flush and ioctl operation API. Interprocess communication can be achieved through these apis. In fact, most of the communication in the process takes place through iOTCL (binderFd, BINDER_WRITE_READ, & BWD). BWD is defined as follows:
struct binder_write_read { signed long write_size; /* bytes to write */ signed long write_consumed; /* bytes consumed by driver */ unsigned long write_buffer; signed long read_size; /* bytes to read */ signed long read_consumed; /* bytes consumed by driver */ unsigned long read_buffer; };Copy the code
The write_buffer contains a set of instructions for the driver
- Book-keeping commands, e.g. inc/decrement binder object references, request/clear death notification, Etc (add or subtract references to binder objects, request or clear death notifications, etc.) does not know if the translation is correct.
- Instructions to respond to, such as BC_TRANSACTION instructions.
Accordingly, read_buffer contains a set of instructions to user space
- Request the command to process the response (that is, BC_REPLY) or perform nested (recursive) operations
Senders and receivers don’t want to know about protocols driven by Binder, so Android uses proxies and stubs for senders and receivers, respectively
The advantage of this is that both client and service do not interact directly with Binder; Smart Android designers, however, consider that Binder may not be necessary for clients to know about, so Android provides a Manager to manage clients. In this way, the Client only needs to deal with the Manager, and there is nothing else to worry about. Android designers really worry about us developers.
Note: This is especially true for system services, which typically expose only a subset of their apis to their Managers, such as activities managed through ActivityManager, Windows handled through WindowManager, and so on.Binder obtains XXManagerService to control Actvitity and Window. But how does a client get a handle to the service it communicates with? That is, how the client gets the ManagerService. Next we will talk about Binder communicationService registration, service discovery, service invocation. The Servicemanager is used to manage all managerServices.
Servicemanager: Binder drivers accept only one Servicemanager for security reasons, so the Servicemanger process needs to be started when Android is started.
Adb shell ps can be used to verify this:
The first process to start on Android is init (PID=1). The Servicemanager is started by the init process (PPID=1, the parent process PID=1, the init process). The zygote64 process id is PID=1021. The parent process id of the system_server process is zygote64. From this we can get the following figure
The second chapter of the book “Advanced Decryption of Android” explains this part of the content, we can also verify the book through ADB shell PS, I will write a blog about this part later.
The ADB shell Service List shows 259 system services registered with servicemanager on my phone.
The service registry
Step 1: The Service calls the addService method in the serviceManager, and then the addService (name) method in the ServiceManagerNative class.
The second step: ServiceManagerNative sends an SVG_MGR_ADD_SERVICE instruction through Binder, and then adds the corresponding service to svc_list by calling do_add_service () via svcmgr_handler().
Important: All services must be registered in svc_list before they can be invoked by clients. Svc_list stores these services as linkedList.
Service access
The first step: When a client requests a service, such as calling context.getSystemService() in an activity, the serviceManager uses getService (name), The getService(name) method in the ServiceManagerNative class in the Native layer is then called.
The second step: ServiceManagerNative sends a SVG_MGR_GET_SERVICE command through its Binder, We then call do_find_service () via svcmgr_handler() to find the service in svc_list.
Step 3: After finding the corresponding service, the Binder will send the service to ServiceManagerNative, and then to serviceManager, and finally the client can use it.
Note: The service is stored in Svclist, which is a linked list, so the service invoked by the client must be registered with Svclist first.
The service call
Pass mContext. GetSystemService () get to the service, then can invoke the service method.
NotificationManager manager = mContext.getSystemService(NotificationManager.class);
ensureNotificationChannelExists(manager, DYNAMIC_MODE_NOTIF_CHANNEL_ID,
R.string.dynamic_mode_notification_channel_name);
manager.notifyAsUser(TAG, DYNAMIC_MODE_NOTIFICATION_ID,
buildNotification(DYNAMIC_MODE_NOTIF_CHANNEL_ID,
R.string.dynamic_mode_notification_title,
R.string.dynamic_mode_notification_summary,
Intent.ACTION_POWER_USAGE_SUMMARY),
UserHandle.ALL);
Copy the code
Let’s look at the figure below, which is closer to our client-side coding process. As for this content, we will explain it in detail in the subsequent articles. First we know the whole process.
summary
Binder implements cross-process communication, as you may have seen in the previous article. The main feature is mMAP memory mapping, which allows data to be copied from sender to receiver in a single copy (the sender copies data into the kernel process via copy_from_user()). The challenge is to implement the framework for Binder communication, how to manage the communication with the Binder, and how to implement cross-process communication between clients and servers. Three-step strategy: service registration, service discovery, and service invocation.
In my next article, I’ll take a look at the Android Framework source code, How do dozens of services such as ActivityManagerService and WindonManagerService enabled in the SystemServer process connect with the serviceManager process?
If there are any mistakes in this article, please leave comments and discuss them. Thanks again to the authors of the following articles. If you find this article helpful, please give it a thumbs up and a follow. reference
Binder in Android
Events.static.linuxfound.org/images/stor…
Andevcon-Binder (newandroidbook.com)