What is IPC?

IPC stands for Interprocess communication

Linux existing IPC mode

Pipes: A page size memory is allocated at creation time, and the cache size is limited

Message queuing: Information is copied twice, extra CPU consumption; Not suitable for frequent or informative communication

Shared memory: No replication is required. The shared buffer is directly attached to the virtual address space of processes, which is fast. However, the synchronization between processes cannot be realized by the operating system and must be solved by each process using the synchronization tool

Socket: As a more general interface, the transmission efficiency is low, mainly used for communication between different machines or across networks

Semaphore: Often used as a locking mechanism to prevent other processes from accessing a shared resource while one process is accessing it, and therefore, primarily as a means of synchronization between processes and between different threads within the same process

Signal: not suitable for information exchange, more suitable for process interrupt control, such as illegal memory access, killing a process and so on

Traditional IPC communication principles in Linux

First of all, we want to know, in Linux is isolation between processes, and each process is the process of space will be divided into “user control” and “kernel mode”, corresponds to the “user mode” and “kernel mode”, and “system calls” is the user space access kernel space, the only way the system call mainly by the following two functions:

  • Copy_from_user () // copies data from user space to kernel space
  • Copy_to_user () // copies data from kernel space to user space

Next, we can study the principle of traditional IPC communication, as shown below:

The data that the message is about to send is stored in the memory cache and entered into the kernel state through a system call. Then the kernel program allocates memory in the kernel space, creates a memory cache, and calls copy_from_user() to copy the data from the memory cache in user space to the kernel cache in kernel space. Similarly, when receiving data, the recipient process creates a memory cache in its own user space, and the kernel program calls copy_to_user() to copy the data from the kernel cache to the recipient process’s memory cache. At this point, the two processes have completed a data transfer, we call the completion of an interprocess communication

Android in the IPC

Usually, an App has only one process, but Android can achieve multiple processes, for example, some communication apps will have a separate process resident in the background. With rapid development, this practice is becoming more and more common

How to multiprocess in Android

Typically, there is only one way to do this, which is to specify the new Android: Process property in AndroidMenifest

Details are as follows:

<activity android:name=".Activity1"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Activity2" android:process=":remote"/> <activity android:name=".Activity3" android:process="com.example.myapplication.remote"/> ------------------------------ The above code creates three processes: 1. Com. Example. Myapplication 2. Com. Example. Myapplication. Remote 3. Com. Example. Myapplication. Remote after the difference between the two processes: Use ":" to create a private process, and other applications can not co-exist with it in the same process. - Use ":" to create a private process, and other applications can co-exist with it in the same process. The Android system assigns a unique UID to each application. Only applications with the same UID and signature can share dataCopy the code

Another unconventional approach is to fork new processes in the native layer via JNI

Android multiple processes cause problems

Before introducing AndroidIPC, let’s talk a little bit about why we need these methods. Is the original Android communication mechanism or LinuxIPC not suitable for Android multiprocess?

The Android system assigns a separate VIRTUAL machine to each process. Different virtual machines have different address Spaces for memory allocation, which causes many problems:

  • Static member and singleton patterns fail
  • The thread synchronization mechanism fails
  • SP concurrent operations deteriorate data reliability
  • Application created multiple times (equivalent to restarting App)

To solve the above problems, the following AndroidIPC approach is introduced

  • File sharing
  • ContentProvider
  • Bundle
  • Messager
  • AIDL
  • Binder

File sharing

The obvious way to exchange data is for two processes to read/write the same file

Disadvantages: Concurrent operations may cause file data to be valid

Scenario: This mode is suitable for communication between processes that do not have high requirements on data synchronization, and the concurrent read and write problem must be properly solved


ContentProvider

Data is mainly organized in the form of tables, containing multiple tables, with one row corresponding to a record and one column corresponding to a field in a record, similar to a database. File data such as pictures and videos are supported in addition to tables

After the organization encapsulates the data, it provides a unified access interface, so that other processes can ignore the underlying data storage mode and only use the unified interface to manipulate the data

Communication is usually implemented with its helper classes, which can be either interprocess or intra-process communication

Principle: Binder mechanism

Advantages: Secure encapsulation of data; Provides a unified data access interface for other processes to call

Scenario: One-to-many processes share data

Usage: Android School Recruitment interview Guide -ContentProvider full analysis


Bundle

Bundle data is stored as key-value pairs between activities and threads. Since the Bundle implements the Parcelable interface, it can also be used between processes by configuring the target package name

For reference:

Bundle bundle = new Bundle(); Bundle. puString("test", "from A"); Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_LAUNCHER); ComponentName cn = new ComponentName("com.test", "com.test.MainActivity"); intent.setComponent(cn); intent.puExtras(bundle); startActivity(intent);Copy the code

When passing objects using bundles, serialization is required, which implements the Serializable/Parcelable interface

About serialization: Notes on Oldjii -Android serialization

Principle: The Bundle is just a carrier of information, and internally maintains a Map
,>

Scenario: Interprocess communication between four components


Messager

Messager can be translated as “messenger”, through which Message objects can be passed between different processes. In the Message, such as data, can realize inter-process communication, which is a lightweight IPC scheme

Messager uses the AIDL approach, but unlike AIDL, Messager uses a Handler for processing. This is why it does not support concurrency. Handler is a mechanism for communication between threads, which itself does not support interprocess communication (IPC)

To learn more about the Handler mechanism, see Oldjii’s Note-Handler mechanism Parsing

Rationale: The underlying implementation is AIDL

Pros: Security, no concurrency support (both pros and cons); Package AIDL, easy to use, no need for AIDL files; Support real-time communication

Disadvantages: Serial processing of messages sent by the client, the server does not exist concurrency; Data is passed through Message so only the data types supported by the Bundle can be passed

Scenario: low concurrency one-to-many even communication

Use: Messenger lightweight IPC solution


AIDL

AIDL stands for Android Interface Description Language, which defines mutually agreed programming interfaces for cross-process communication

Relationship with Messager: Messager is wrapped based on AIDL, but the server only supports serial processing of messages. If there are a large number of concurrent requests, Messager is not suitable. Furthermore, the main purpose of using Messager is to deliver messages, but IPC goes beyond that and may call server-side methods across processes, in which case Messager can’t be satisfied, while using AIDL directly is fine

Scenario: One-to-many process communication

Use: The server writes the specific implementation of the interface in the Stub and passes it to the client with the iBinder object. When the client bindService, it restores the iBinder to the interface in the form of asInterface. Then call the method

For details: Notes of Oldjii -AIDL


Binder

Binder mechanisms are unique to Android as a means of cross-process communication that is not available in Linux

Binder is used in Android to implement IPC. Binder is used in the Framework between XXXManager and XXXManagetService. XXXManager is the Client and XXXManagetService is the Server. Such as ActivityManager, ActivityManagerService, WindowManager, WindowManagerService, PackageManager, PackageManagerService, Even the Native Framework layer MediaPlay and MediaPlayService are the same

For details, please refer to: The process of an Android phone from startup to APP startup

At the application level, Binder can also be used to implement IPC with Messager and AIDL. Binder can also be used directly with Messager and AIDL

  • AIDL: When you need clients from different applications to access your service via IPC and need to support multi-threading
  • Direct use of Binders: Situations where IPC is not required for several applications at the same time
  • Messager: You need to implement IPC, but you don’t need to handle multithreading

Direct use: Minimalist use with Android Binder

Basic principle of Binder

Before reading this section, it is recommended that you review the “Principles of Traditional IPC” with Binder to better understand the communication principles

Binders differ from traditional IPC mainly in their use of “dynamic kernel loadable modules” and “memory mapping”

Dynamic kernel loadable modules

Linux’s dynamic kernel loadable module (LKM) is a piece of self-contained program that can be compiled separately and cannot run separately at that time. The module is linked to the kernel at runtime and runs as part of the kernel. In this way, the Android system can dynamically add a kernel module to run in the kernel space, and user processes can communicate with each other through this kernel module

The kernel module responsible for user process communication with Binder is Binder Dirver.

The memory mapping

In simple terms, memory mapping is to map a memory region of user space to kernel space. After the mapping relationship is established, the modification of this memory region by users can directly reflect the kernel space, and vice versa. This reduces the number of data copies using memory mapping

Memory mapping in BinderIPC is done with mmap(), which is a way of mapping memory in operating systems. Mmap () is usually used in file systems with physical media, but Binder does not have physical media. It is also impossible to establish a mapping between physical media and user space using mmap(). Mmap () in Binder is used to create a cache space for data acceptance in kernel space

Complete the process

With the above concepts in mind, you can understand the full BinderIPC communication principle

A complete BinderIPC communication process:

  1. The Binder driver first creates a data acceptance cache in kernel space
  2. Then a kernel cache is created in the kernel space, and the mapping relationship between the kernel cache and the data receiving cache, as well as the mapping relationship between the data receiving cache and the user space of the receiving process is established
  3. The sender uses the system call copy_from_user() to copy the data to the kernel cache in the kernel. Since the kernel cache is memory-mapped to the user space of the receiving process, the data is sent to the user space of the receiving process, thus completing an inter-process communication

As shown below:

Communication process with Binder

Client/Server/ServiceManager/Binder Driver

Binder is based on the C/S architecture. It consists of a series of components, including Client, Server, ServiceManager, and Binder drivers. Client, Server, and ServiceManager run in the user space, and Binder drivers run in the kernel space. The ServiceManager and Binder drivers are provided by the system, and the Client and Server are implemented by application programs. Client, Server, and ServiceManager invoke open(), mmap(), and ioctl() to access device file /dev/binder to interact with binder drivers to implement indirect cross-process communication

This is where you need to understand the ServiceManager component

Client, Server, ServiceManager, Binder Drivers play the same roles in communication as servers, clients, ServiceManager, and routers on the Internet. The following memory is taken from Android Binder design and implementation

A ServiceManager is similar to a real name Binder. A ServiceManager translates a Binder name into a reference to a Binder name in a Client. Enables clients to obtain references to Binder entities through Binder names. Binders are real names, just like websites except that they have an IP address and a web address. Server creates a Binder, gives it a character form, a readable and memorable name, and sends the Binder entity with the name to the ServiceManager as a packet through the Binder driver. Tell the ServiceManager to register a Binder named “John” that resides in a Server. The driver creates entity nodes in the kernel and references to the entity by the ServiceManager for the Binder that crosses process boundaries, packaging the name and the new reference to the ServiceManager. The ServiceManger receives the data and retrieves the name and reference from it to fill the lookup table

Introduction to the binder_xxx() function

Init () : creates /dev/binder device nodes. Open () : obtains file descriptors for binder drivers. Mmap () : allocates a block of memory in the kernel for storing data

The ioctl command:

BINDER_WRITE_READ --> Sending and receiving Binder IPC data BINDER_SET_MAX_THREADS --> Setting the maximum number of Binder threads BINDER_SET_CONTEXT_MGR --> Setting Service BINDER_THREAD_EXIT --> Release Binder threads BINDER_VERSION --> Obtain Binder version information BINDER_SET_IDLE_TIMEOUT --> Not used BINDER_SET_IDLE_PRIORITY --> Not usedCopy the code

Binder Series 1 – Preliminary Introduction to Binder Driver

Complete communication process with Binder

A complete Binder communication process is as follows:

  1. First, a process registers itself as a ServiceManager with Binder using the ioctl() command (BINDER_SET_CONTEXT_MGR)
  2. Server registers Binder entities (Binder entities in Server) with ServiceManager through Binder drivers, indicating that services can be provided externally. The Driver creates entity nodes for this Binder in the kernel and references to the entities by ServiceManager. Package the name and the new reference to the ServiceManager, which then fills it into the lookup table
  3. With the help of Binder drivers, clients obtain references to Binder entities from ServiceManager by name, and then communicate with the Server through this reference


Why did Android use Binder as an IPC mechanism?

You can answer this question from two aspects: performance and security

Performance:

On mobile devices, the wide use of cross-process communication has strict requirements on the performance of communication mechanism. Binder is more efficient than traditional Socket. Binder data is copied only once, while pipes, message queues, sockets, etc. 2 Although shared content is not copied in memory, the implementation is too complex and not suitable for this scenario

Safety:

The traditional process communication method does not strictly verify the identity of the communication parties. For example, the IP address of Socket communication is manually filled by the client, which is easy to be forged. Binder mechanisms, however, provide enhanced security by enabling identity verification of communication parties from the protocol itself

Refer to the article

Thank you dalao:

  • https://www.jianshu.com/p/52ec31fcf0a6
  • https://www.jianshu.com/p/2d6ddd6a3399
  • https://www.zhihu.com/question/39440766
  • http://www.myexception.cn/ai/1844929.html
  • http://gityuan.com/2015/11/01/binder-driver/
  • https://blog.csdn.net/AndroidStudyDay/article/details/93749470
  • https://lrh1993.gitbooks.io/android_interview_guide/content/android/basis/ContentProvider.html