Binder机制在Android中的原理和使用
Binder机制概述
Binder是Android的一种跨进程通信机制,它允许不同进程间进行通信,甚至可以跨设备进行通信。Binder通常用于实现Android Framework与App之间的通信,也用于App之间的通信。
Binder机制是Android框架的基石,深入理解Binder机制有助于我们更好地理解Android系统的工作原理。本文将从Binder的原理出发,全面介绍Binder在Android中的使用和工作流程。
Binder原理概述
Binder机制运用的是一个C/S(Client/Server)架构,客户端进程发送请求,服务端进程接收请求并返回结果。Binder机制的实现是基于Linux的Binder驱动,Binder驱动可以理解为一个消息传递的通道,各个进程通过读取和写入这个通道来实现跨进程通信。
当Client进程调用Server中的binder方法时,Binder驱动会将这个方法调用转换成一条Binder消息,这条消息会发送到Server进程。Server进程收到消息后,Server中的Binder线程池会按照一定的调度策略选取一个空闲线程来处理这条消息,最终执行Server端的binder方法。执行完后,会将结果打包成Binder消息发送回Client进程,Client进程收到消息后会从驱动中读取结果,最终解包使用。这就是Binder机制的整个调用流程。
Binder的使用
定义接口
Binder机制通常用于实现进程间的接口调用,我们需要先定义Binder接口。一个典型的Binder接口如下:
public interface IBookManager {public void addBook(Book book);public void deleteBook(int bookId);public Book getBook(int bookId);public List<Book> getBooks();
}
这是一个书管理的Binder接口,包含增加书籍、删除书籍、获取书籍等方法。
实现Binder接口
然后我们需要实现上面的Binder接口,并继承自Binder类,这样这个类的实例就代表了一个Binder实体,可以跨进程传输。
public class BookManager extends Binder implements IBookManager {public void addBook(Book book) { ... }public void deleteBook(int bookId) { ... }public Book getBook(int bookId) { ... }public List<Book> getBooks() { ... }
}
在Server端注册Binder实体
在提供服务的进程内,我们需要将Binder实体注册到ServiceManager中。这样当其他进程想访问这个Binder实体时,就可以从ServiceManager中获取它。
public class BookManagerService extends Service {private final BookManager bookManager = new BookManager();public void onCreate() {super.onCreate();publishBinderService(CMD_BOOK_MANAGER, bookManager);}
}
在onCreate()
方法中我们通过publishBinderService()
方法将bookManagerBinder实体发布到ServiceManager中,这样其他进程就可以通过CMD_BOOK_MANAGER这个key来获取这个Binder实体了。
在Client端获取Binder代理并调用
在客户端进程中,我们可以通过ServiceManager访问Server发布的Binder实体。
public void queryBookManager() {// 获取ServiceManager的代理IBinder service = ServiceManager.getService(CMD_BOOK_MANAGER);// 通过服务端返回的IBinder对象生成Binder代理IBookManager bookManager = IBookManager.Stub.asInterface(service);// 通过代理调用服务端的方法List<Book> books = bookManager.getBooks();...
}
我们首先通过ServiceManager
获取要访问的Binder实体,这个会返回一个IBinder
对象。然后通过IBookManager.Stub.asInterface(service)
将IBinder
对象转成客户端所需的IBookManager
接口类型,这个对象就是Binder代理。我们可以通过这个代理对象调用服务端IBookManager
接口中的方法。
至此,我们完成了一个跨进程的Binder通信的全过程。客户端通过Binder代理访问服务器提供的服务,服务器通过Binder实体来处理客户端的请求。这整套机制都建立在Binder驱动之上,Binder驱动负责将双方的请求和回复进行传递。
Binder通信的底层原理
我们上面简单介绍了Binder通信的使用过程,下面来深入分析Binder通信的底层实现原理。
Binder通信的底层实现依靠的是Linux的Binder驱动框架。当客户端的Binder线程向服务端的Binder对象发送请求时,请求会被打包成一条Binder消息,这条消息会通过write()系统调用写入到Binder驱动中。Binder驱动会将消息发送到服务端进程的Binder线程池中。
服务端的某个Binder线程会从驱动中读取这条消息,解析后调用服务端的Binder对象来处理请求。处理完成后,服务端也会将结果打包成一条Binder消息写入到驱动中。这条消息最终会传递到客户端,客户端的Binder线程会从驱动中读取消息,得到服务端的回复。
从上面的过程可以看出,Binder驱动扮演了消息传递的媒介角色,实际上完成客户端与服务端的通信。客户端和服务端的Binder线程通过读写驱动中的消息来实现进程间的调用。这种机制的优点是简单高效,并且Binder驱动已经处理好了跨进程调用所需要解决的低层问题,如线程同步、内存拷贝等,我们只需要关注更高层的Binder接口设计和业务逻辑处理。
-
客户端的Binder线程调用transact()方法,将请求的参数打包成Binder消息(binder_write_read结构体)
-
客户端的Binder线程通过write()系统调用,将请求消息写入Binder驱动
-
Binder驱动接收到消息,查找服务端的进程并将消息转发给服务端的Binder线程池
-
服务端的某个Binder线程通过read()系统调用读取Binder驱动中的请求消息
-
服务端的Binder线程解析消息,执行请求需要调用的服务端Binder对象的方法
-
服务端的Binder线程将结果打包成回复消息(binder_write_read结构体)
-
服务端的Binder线程通过write()系统调用,将回复消息写入Binder驱动
-
Binder驱动接收到消息,查找客户端的进程并将消息转发给客户端的Binder线程池
-
客户端的Binder线程通过read()系统调用读取Binder驱动中的回复消息
-
客户端的Binder线程将收到的回复消息返回给Step1的transact()方法调用
-
transact()方法在获得回复消息后返回,客户端得到服务端的调用结果
可以看到,Binder通信的整个过程,客户端和服务端的交互其实都是通过Binder驱动中的消息传递来完成的。Binder驱动作为媒介,屏蔽了跨进程通信中的底层细节,大大简化了开发者的工作。
Binder线程池
在Binder通信的过程中,我们提到过Binder线程池。每个进程中的Binder通信都是通过线程池中的Binder线程来完成的。那么这个Binder线程池是如何工作的呢?
每个进程启动时,会启动一定数量的Binder线程,这些线程就构成了Binder线程池。当客户端的Binder接口发出跨进程请求时,请求会被放入工作队列中,线程池的某个空闲线程会从队列中取出请求,调用transact()方法与Binder驱动进行数据交换,并最终执行服务端的Binder对象方法。
同理,当服务端的Binder对象完成请求处理后,也需要向客户端发送回复,这个过程也需要线程池中的某个空闲线程来完成与驱动的通信。
由此可见,Binder线程池中的线程不断从工作队列中取出请求并与驱动通信,实现了客户端请求的发送和服务端回复的发送。如果工作队列中有大量请求积压,线程池可以通过创建更多线程来应对,这就实现了Binder通信的并发能力。
每个Binder线程与Binder驱动建立了一个会话,用于发送和接收消息。在进程启动时会创建多个会话,这些会话会被线程池中的线程复用。当某条请求需要与驱动交互时,线程会选择一个空闲会话来使用,使用完后回收到会话池中,以供其他线程使用。
-
客户端的Binder接口调用会被加入工作队列
-
线程池中的某个空闲线程会从工作队列中取出请求
-
取出的线程会从会话池中获取一个空闲会话与Binder驱动交互
-
交互完成后,线程会回收会话到会话池,等待下一请求使用
-
如果工作队列中的请求较多,可以通过创建更多线程来增加处理能力
这就是Binder线程池的基本工作机制,它实现了Binder通信的并发以及客户端与驱动、服务端与驱动的交互工作。Binder线程池的可扩展性也可以根据请求量进行动态调整,这使得Binder机制可以应对不同级别的并发请求。
至此,我们对Binder机制的原理有了比较全面和深入的了解。Binder机制作为Android Framework和App之间的基石,理解Binder的工作原理可以帮助我们更好地理解Android系统的工作机制,也可以更高效地进行Binder协议的设计与开发。