Android Interprocess Communication(二)
博客专区 > ifindbug 的博客 > 博客详情
Android Interprocess Communication(二)
ifindbug 发表于3年前
Android Interprocess Communication(二)
  • 发表于 3年前
  • 阅读 44
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 新注册用户 域名抢购1元起>>>   

摘要: 学习Android Binder的入门文章,浅显易懂,您值得阅读。 -----by Thorsten Schreiber

4. Binder

This chapter explains what the Binder is and what its capabilities are. The explanation covers an abstract level, without going into implementation details. These are handled in the next chapter.

4.1. Origin

The Binder was originally developed under the name OpenBinder by Be Inc and later Palm Inc under the leadership of Dianne Hackborn. Its documentation claims OpenBinder as ”... a system-level component architecture, designed to provide a richer high-level abstraction on top of traditional modern operating system services.”

Or more concretely, the Binder has the facility to provide bindings to functions and data from one execution environment to another. The OpenBinder implementation runs under Linux and extends the existing IPC mechanisms. The documentation of OpenBinder states that ”... the code has run on a diverse variety of platforms, including BeOS, Windows, and PalmOS Cobalt.” [20]

Binder in Android is a customized implementation of OpenBinder. In Android’s M3 release the original kernel driver part from OpenBinder was used, but the user space part had to be rewritten due to the license of OpenBinder beeing not compatible to Android’s license. In Android’s M5 release the driver was rewritten, too. The core concepts remained the same, but many details have changed.

The original OpenBinder code is no longer being developed. But to some extent, the reimplementation to android can be seen as a branch, which is maintained by Android developers. So the OpenBinder survived in Android Binder. [19]

4.2. Binder Terminology

The Binder framework uses its own terminology to name facilities and components. This section summarizes the most important terms, the details are discussed in the later sections. [20]

Binder This term is used ambiguous. The Binder refers to the overall Binder architecture, whereas a Binder refers to a particular implementation of a Binder interface.

Binder Object is an instance of a class that implements the Binder interface. A Binder object can implement multiple Binders.

Binder Protocol The Binder middleware uses a very low level protocol to communicate with the driver.

IBinder Interface A Binder interface is a well-defined set of methods, properties and events that a Binder can implement. It is usually described by AIDL1 language.

Binder Token A numeric value that uniquely identifies a Binder.

4.3. Facilities

The Binder framework provides more than a simple interprocess messaging system. The facilities are listed in Figure 4.1

The Binder Facilities

The most important improvement from Android application programmer’s view is that methods on remote objects can be called as if they where local object methods. This is achieved with a synchronous method call. Accordingly, the calling client process is blocked for the duration of the answer of the server process. To its advantage, the client has no need to provide a threat method for a asynchronous return message from the client.

This is related to the facility of the Binder framework to send one and two way messages and to start and stop threads.

It is a feature of AIDL, thus settled in a higher level, that an application does not need to know if a service is running in a server process or in the local process. Android’s application concept makes it possible to run a service either in a own process or in the activity process. This makes it easy for a application developer to export services to other Android applications without reviewing the code.

The Android system service uses a special notification feature of the Binder, that is called link to death mechanism. This facility allows processes to get informed when a Binder of a certain process is terminated. In particular, this is the way the Android window manager establishes a link to death relation to the callback Binder interface of each window, to get informed if the window is closed.

Each Binder is uniquely identifiable, that means it can act as shared token. Under the assumption the Binder is not published via the service manager, the Binder identification is only known by the involved communicating parties, including remote process, local process and the system. Consequently a Binder may be used as a security access token. The token can also be shared across multiple processes.

Another security feature is that a callee process can identify his caller process by UID and PID. Combined with the Android security model, a process can be identified. Another feature, but in this work not analyzed, is the shared memory mechanism, where via binder framework a heap can be shared.

Summarized, the Binder and its framework support many features to ensure a well object oriented interprocess communication. [19] [14]

4.4. Concepts

This section describes the concepts behind the facilities. Due to the lack of a public available documentation, they are largely derived by reviewing the source code.

4.4.1. Communication Model

The Binder framework communication is a client server model. A client will initiate a communication and wait for response from a server. The Binder framework uses a client-side proxy for communication. On the server side, a thread pool exists for working on requests. In Figure 4.2 the process A is the client and holds the proxy object which implements the communication with the Binder kernel driver. Process B is the server process, with multiple Binder threads. The Binder framework will spawn new threads to handle all incoming requests, until a defined maximum count of threads is reached. The proxy objects are talking to the Binder driver, that will deliver the message to the destinated object. 3

Abstract Binder Communication

4.4.2. Transactions

If one process sends data to another process, it is called transaction. Along with each transmission payload data is submitted. The data is called transaction data.

The structure of the data is shown in Figure 4.3. It contains a target, that is a destination binder node. The cookie field is used for internal information. The sender ID field contains security relevant information. The data field contains a serialized data array. An array entry is composed of a command and its arguments, that is parsed through the Binder. An application on top of the Binder framework can now define own commands and depending on that arguments. As it can be seen in Android source codes derived from AIDL [11], developers implementing remote services use the target command field as a function pointer and serialize its arguments to the argument field corresponding to the function signature. Beyond this fact, the concept facilitate to implement a user defined IPC protocol. Binder communication is relying on a request and reply mechanism. This fact limits the implementation, meaning that each request must have a reply and the requesting process must wait for it. It is blocked in waiting time and cannot proceed. To implement an asynchronous IPC protocol, which is possible in general, a developer must pay attention to this fact. If a developer needs a non-blocking IPC, he has to implement a managing mechanism that assigns the answer to its request. Binder does not provide this asynchronous feature.

Transmission Data

Therefore a transaction implies two messages, a transaction request and its reply. The one way communication of the Binder facilities section is limited to internal features as the death notification.

4.4.3. Parcels and Marshaling

In an object oriented view, the transaction data is called parcel. Namely, this is the transmitted data structure. Any object, that can be transmitted remotely, must implement the Parcelable interface. An object, that implements this interface must provide methods, that serialize the data structure of an object on sender side and restore it on receiver side. All information must be reduced to simple data types like Int, Float, Boolean and String types. This partial information are written serial to an parcel by the sender and are read and rebuild by the receiver.

The procedure of building a parcel is called marshaling or flattening an object. In reverse, the procedure of rebuilding a object from a parcel is called unmarshaling or unflattening an object.

The memory sharing facilities of Binder can not be used by Java API wrapper applications, only native C++ libraries can have access to shared object representations in memory.

4.4.4. Death Notification

The Binder framework supports notifications on the death of Binder objects. This is realized by an observer pattern. A local Binder object, that is interested to know about the termination of a remote Binder object adds itself to an observer list. If the event occurs that a process keeping the remote Binder object is terminated, the local object is informed and can react. Figure 4.4 was discharged from source code and is a flow chart and visualizes the pattern. [19]

Binder Death Notification

4.5. Context Manager

The context manager is a special Binder node of the Binder framework. It is the Binder with the number 0. It serves as name system and makes it possible to assign a name to a Binder interface. This is important, because possible clients do not know the remote Binder addresses a priori. If the client would know the remote Binder address a priori, the security token feature of Binder would not work. But if no remote partner address is known, no initial communication could happen, because each Binder interface knows only his own address. The context manager solves this problem, having the only Binder interface with a fixed and a priori known Binder address. The context manager implementation is not part of the Binder framework. In Android the implementation of the context manager is called service manager. Each Binder that needs to publish its name due to being a service, submits a name and its Binder token to the service manager. Relying on that feature, the client must only know the name of a service and asks the service manager for the Binder address of the requested service.

4.6. Intents

An intent is a message, that the developer uses on Java API layer and that is sent with Binder IPC. ”It is an abstract representation of an operation to be performed.” [15] ”Abstract” means that the performer of the desired operation does not have to be defined in the intent. The intent holds as main information an action and a data field. Figure 4.5 gives an example of an intent. This intent is delivered by the intent reference monitor to the Binder that is assigned to the action ACTION DIAL, e.g. the telephony application. This service will dial the number, that is stored in the contact application under the given name.

Intent

There are two forms of intents. An explicit intent addresses to a specific component. On the other side, an implicit intent gives the decision to the Android system, which component is addressed. If multiple components for one purposes are installed, the system will choose the best component to run the intent.

4.7. System Integration

The Binder is extensively used in the android platform. Whenever two processes must communicate, Binder is involved. For example the window-manger exchange data with his clients over Binder framework. It also uses the Binder death notification feature for getting informed when a client application terminates.

So the Binder connects the distributed architecture of the Android operating system and is because of this a really important module. [19]

4.8. Security Model

The Binder security model is very basic but effective. It ensures a secure channel for communication of two process, and guarantees identification of communication partners by delivering information like PID number and UID number.

Another feature coming with intents is the intent filter. This is a declaration for an service or app, which intents are forwarded by the system to this service or app. But it does not guarantee security for all intents, because the intent filter can be bypassed by explicit intents. [24] In last consequence, the security relies on checking of PID and UID like presented above.

5. Implementation of the Binder Framework

This chapter provides an overview about the implementation of the Binder framework. For each layer, the source code files [10] 9 are listed and its purposes are discussed. Also, the AIDL is presented, which is an implementation feature because it generates Java code and thus can be viewed as a part of the Binder framework.

IPC System

Figure 5.1 presents the different layers of the Binder framework. It is composed of three layers. The first and highest layer is the API for Android applications. The second layer is a middleware that keeps the userspace implementation of the Binder framework. The third and lowest layer is the kernel driver.

5.1. AIDL

The Android interface definition language (AIDL) [11] is part of the Eclipse SDK, provided by Google. Its main purpose is to ease the implementation of Android remote services. The AIDL follows a Java like syntax.

In the AIDL file the developer defines an interface with the method signatures of the remote service. The AIDL parser generates a Java class from the interface, that can be used for two different purposes. First it generates a proxy class to give the client access to the service, second it generates a stub class that can be used by the service implementation to extend it to an anonymous class with the implementation of the remote methods.

The AIDL language supports only basic data types. It generates code that takes care of writing the values into the parcels, sending them via Binder IPC, receiving them, reading the values and calling the methods of service and writing and sending the result back.

The AIDL file must be shared between remote service app developer and client app developer. Because the AIDL generator generates the source code for client and remote service in one file, each application uses and instantiate only a subset of generated classes.

5.2. Java API Wrapper

This section discusses the Java framework, operating on top of the middleware and the kernel driver. These source classes and interfaces belong to the Java API layer:

Interfaces:

  • android.app.IActivityManager
  • android.os.Parcable
  • andorid.os.IBinder
  • android.content.ServiceConnection

Classes:

  • android.app.ActivityManagerNative
  • android.app.ContextImpl
  • android.content.Intent
  • android.content.ComponentName
  • android.os.Parcel
  • android.os.Bundle
  • android.os.Binder
  • android.os.BinderProxy
  • com.android.internal.os.BinderInternal

The Java layer of the Binder framework has two functions. One function is wrapping the subjacent middleware layer, to let the Android applications participate on Binder communication. As a second function, it introduces facilities to the Binder framework, namely the use of intents.

Figure 5.2 presents the main Java classes and its dependencies.

Java System

5.2.1. JNI Wrapper

The Java API Layer relies on the Binder middleware. To use the C++ written middleware from Java, the JNI must be used. In the source code file frameworks/ base/core/jni/android util Binder.cpp, the mapping between Java and C++ function is realized.

5.3. C++ Middleware

The middleware implements the user space facilities of Binder framework and is written in C++. The framework provides the process and thread control methods and structures that are necessary to spawn and manage new threads for working on requests. The marshalling and unmarshalling facilities are implemented here, so that the object information can be transformed to a submittable parcel of data. The middleware provides the interaction with the Binder kernel driver and implements the shared memory.

Services or apps written in native C++ can use the Binder framework directly, but must relinquish features implemented in Java API layer.

The source code is contained in these files:

  • frameworks/base/include/utils/IInterface.h
  • frameworks/base/include/utils/Binder.h
  • frameworks/base/include/utils/BpBinder.h
  • frameworks/base/include/utils/IBinder.h
  • frameworks/base/include/utils/Parcel.h
  • frameworks/base/include/utils/IPCThreadState.h
  • frameworks/base/include/utils/ProcessState.h
  • frameworks/base/libs/utils/Binder.cpp
  • frameworks/base/libs/utils/BpBinder.cpp
  • frameworks/base/libs/utils/IInterface.cpp
  • frameworks/base/libs/utils/ProcessSTate.cpp
  • frameworks/base/libs/utils/IPCThreadState.cpp

5.4. C Kernel Driver

The Binder kernel driver is the heart of the Binder framework. At this point, the reliable and secure delivery of messages must be guaranteed. The kernel driver is a small kernel module and is written in C. The driver module is build from the source files:

  • /drivers/staging/android/binder.c
  • /drivers/staging/android/binder.h

The Binder kernel driver supports the file operations open, mmap, release, poll and the system call ioctl. This operations represent the interface by that the higher layers access the Binder driver. The Binder operation open establishes a connection to the Binder driver and assign it with a Linux file pointer, whereas the release operation closes the connection. The mmap operation is needed to map Binder memory. The main operation is the system call ioctl. The higher layers submit and receive all information and messages by that operation. The ioctl operation takes as arguments a Binder driver command code and a data buffer. These commands are:

BINDER_WRITE_READ is the most important command, it submits a series of transmission data. The series consists of multiple data as described in Figure 4.3.

BINDER_SET_MAX_THREADS sets the number of maximal threads per process to work on requests.

BINDER_SET_CONTEXT_MGR sets the context manager. It can be set only one time successfully and follows the first come first serve pattern.

BINDER_THREAD_EXIT This command is sent by middleware, if a binder thread exits.

BINDER_VERSION returns the Binder version number.

The facilities implemented in the Binder driver are discussed in the next sections. The commands used in these section are target commands. Even if the name is target command, some of these commands are applied to the local binder. In the OpenBinder documentation they are referred to as Binder driver protocol. The available codes are discussed as follows and start with a BC_ prefix for Binder command. The Binder diver talks back with codes starting with a BR_  prefix for Binder return.

5.4.1. Binder Thread Support

Since the kernel driver does not implement the thread start mechanism, it must be kept up to date about how many threads are started. These commands are sent so that Binder driver can have an accurately count of the number of looping threads available. The target commands are BC_REGISTER_LOOPER, BC_ENTER_LOOPER and BC_EXIT_LOOPER. These commands are for bookkeeping and are destined for the local Binder.

Binder Driver Interaction

5.4.2. Binder Transactions

The commands BC_TRANSACTION and BC_REPLY cause a transit of data to another Binder interface. The BC_REPLY command is used by the middleware to answer a received BC_TRANSACTION. Figure 5.3 presents the interaction with the Binder driver when a Binder transmits a transaction and waits until receiving a reply to this transaction. The Binder driver takes care of delivering the reply to the waiting thread, that it can see the reply as direct response.

The Binder driver copies the transmission data from the user memory address space of the sending process to its kernel space and then copies the transmission data to the destination process. This is achieved by the copy from user and copy to user command of the linux kernel. The data transaction is presented in Figure 5.4.

Data Transaciton

5.4.3. Further Mechanism

The Binder kernel commands BC_INCREFS, BC_RELEASE and BC_DECREFS implement the reference counting facilities of the Binder framework. The link to death or death notification feature is also implemented in the kernel driver. The kernel driver manages and keeps all information, that are necessary to recognize and deliver the termination of a Binder node. The commands are BC_REQUEST_DEATH_NOTIFICIATION, BC_CLEAR_DEATH_NOTIFICATION, BC_DEAD_BINDER_DONE and their response codes.

(continue...)

共有 人打赏支持
粉丝 0
博文 9
码字总数 0
×
ifindbug
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: