Binder简介
Binder是Android中使用的进程间通信机制(IPC)。在Android系统中,应用程序是由Activity、Service、Broadcast Receiver和Content Provider四种类型的组件构成的,它们有可能运行在同一进程中,也有可能运行在不同的进程中。此外,各种系统组件也运行在独立的进程中。这些运行在不同进程中的应用程序组件和系统组件之间的通信机制就是Binder。
Android虽然构建在Linux上面,但是在IPC机制方面,没有利用Linux提供IPC机制,而是使用了一套轻量级的IPC机制—Binder机制。Binder是基于OpenBinder来实现的。OpenBinder最先是由Be Inc.开发的,接着Palm Inc.也跟着使用。Binder是一种进程间通信机制,它是一种类似于COM和CORBA分布式组件架构,通俗一点,其实是提供远程过程调用(RPC)功能。
Binder具有以下特点
- 具有分布式的架构。
- 面向系统级的开发。面向系统层的,而不是面向应用层的。目标是进程和IPC,而不是面向跨网络通讯。
- 本身使用C++语言实现。
- 多线程编程的支持。支持多线程编程的各种线程模型。不强制使用特定的线程模型。
- 可支持多操作系统平台。从BeOS开始,到Windows和Palm OS Cobalt,再到Android。Binder都是可以在这些不同平台实现和使用的。Binder使用一些组件和对象来呈现一些基本的系统服务,比如进程和共享内存。它没有试图取代和隐藏操作系统中那些传统的概念,而是拥抱和超越它们。这使得binder可以支持大多数的传统操作系统平台。
- 良好的硬件伸缩性。对硬件要求很低,这正好符合android的实际情况,android的产品线广泛,芯片主频各个层次的都有,要在低端的机器上跑的顺畅,软件本身的性能要求还是很重要。
- 用户可定制性高。作为IPC的机制实现,串联了系统里的大部分组件,并且将各个组件之间的耦合行降到最低。各个组件的可以自由修改和替换,提高了用户的可定制性。
Binder应用模型
一个IPC通讯我们可以简单理解成Client-Server模式,Client请求Service,Server接收到Client请求后处理相应,或可能带回结果返回给Client。
Binder机制在Android系统的进程间通讯模型总结如下:
- Client通过Service Manager得到Server的Proxy。从Client角度看来Proxy和他的本地对象没有什么差别。它可以像其他本地对象一样调用其方法,访问其变量。
- Client通过调用Proxy的方法向Server发送请求信息。
- Proxy通过Binder设备节点(/dev/binder),把用户请求信息发送到Linux内核空间(实际上是内存共享),由Binder驱动获取并发送到Server。
- Server处理用户请求,并通过Linux内核的Binder驱动返回处理结果给Client的Proxy。
- Client收到Server的返回结果。
Binder机制的组成
- Binder Driver: Binder是内核中的一个字符驱动设备位于/dev/binder。这个设备是Android系统IPC的核心部分,客户端(Client)的服务代理用来通过它向服务器(Server)发送请求,服务器也是通过它把处理结果返回给客户端的服务代理对象。这部分内容,在Android中通过一个IPCThreadState对象封装了对Binder驱动的操作。
- Service Manager: 这个东西主要用来负责管理服务。Android中提供的系统服务都要通过Service Manager注册自己,将自己添加进服务管理链表中,为客户端提供服务。而客户端如果要和特定的系统服务端通讯,就需要向Service Manager来查询和获得所需要服务。可以看出Service Manager是系统服务对象的管理中心。
- Server: 需要强调的是这里服务是指的是System Server,而不是SDK server,向客户端提供服务。
- Client: 一般是指Android系统上面的应用程序。它可以请求Server中的服务。
- Proxy: 是指在客户端应用程序中获取生成的Server代理(proxy)类对象。从应用程序角度看代理对象和本地对象没有差别,都可以调用其方法,方法都是同步的,并且返回相应的结果。
一个最简单的Binder传输
下面以一个简单实例来分析Binder传输。该测试程序由client端调用add()函数,在server端完成加法操作,并返回结果。测试程序的目录结构如下,
类图如下所示。左侧为server端,右侧为client端。
Client端代码解析
从Client端的代码看起。Client如果想和Server进行通信,必须先获得Server的远程接口,这个过程通过Service Manager来实现。Service Manager用来管理Server并且向Client提供查询Server远程接口的功能。
1.---> BinderClientRun.cpp
2.
3.int main(int argc, char** argv)
4.{
5. int sum = 0;
6. sp<IBinderServiceTest> mBinderServiceTest;
7.
8. if (mBinderServiceTest.get() == 0) {
9. // 通过defaultServiceManager函数来获得Service Manager的远程接口
10. sp<IServiceManager> sm = defaultServiceManager();
11. sp<IBinder> binder;
12.
13. // 在循环中使用sm->getService不断尝试获得名称为“my.binder.test”的Service,返回binder
14. do {
15. binder = sm->getService(String16("my.binder.test"));
16. if (binder != 0)
17. break;
18. ALOGI("getService fail");
19. usleep(500000); // 0.5 s
20. } while (true);
21.
22. // 得到Service的binder后,通过interface_cast,将这个binder转化成BpBinderServiceTest
23. mBinderServiceTest = interface_cast<IBinderServiceTest> (binder);
24. ALOGE_IF(mBinderServiceTest == 0, "no IBinderServiceTest!?");
25. }
26.
27. // BpBinderServiceTest,就可以调用远程server的接口了
28. sum = mBinderServiceTest->add(3, 4);
29. ALOGI("sum = %d", sum);
30. return 0;
31.}
代码中的interface_cast是如何将binder转化为BpBinderServiceTest的呢?Android有意隐藏了这一转换,让应用很轻松的完成这一转换。看一下interface_cast的定义
1.---> IInterface.h
2.
3.template<typename INTERFACE>
4.inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
5.{
6. return INTERFACE::asInterface(obj);
7.}
interface_cast是一个模板,它返回的是 IBinderServiceTest::asInterface。但在我们的源码中并没有直接实现 asInterface,那它是在哪里实现的呢?让我们先看一下两个宏定义
1.---> IInterface.h
2.
3.#define DECLARE_META_INTERFACE(INTERFACE) \
4. static const android::String16 descriptor; \
5. static android::sp<I##INTERFACE> asInterface( \
6. const android::sp<android::IBinder>& obj); \
7. virtual const android::String16& getInterfaceDescriptor() const; \
8. I##INTERFACE(); \
9. virtual ~I##INTERFACE(); \
10.
11.
12.#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \
13. const android::String16 I##INTERFACE::descriptor(NAME); \
14. const android::String16& \
15. I##INTERFACE::getInterfaceDescriptor() const { \
16. return I##INTERFACE::descriptor; \
17. } \
18. android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
19. const android::sp<android::IBinder>& obj) \
20. { \
21. android::sp<I##INTERFACE> intr; \
22. if (obj != NULL) { \
23. intr = static_cast<I##INTERFACE*>( \
24. obj->queryLocalInterface( \
25. I##INTERFACE::descriptor).get()); \
26. if (intr == NULL) { \
27. intr = new Bp##INTERFACE(obj); \
28. } \
29. } \
30. return intr; \
31. } \
32. I##INTERFACE::I##INTERFACE() { } \
33. I##INTERFACE::~I##INTERFACE() { }
这两个宏会在程序中被使用
1.---> IBinderServiceTest.h
2.
3.class IBinderServiceTest: public IInterface {
4.public:
5. DECLARE_META_INTERFACE(BinderServiceTest);
6.
7. virtual int add(int a, int b) = 0;
8.};
9.
10.
11.---> IBinderServiceTest.cpp
12.
13.IMPLEMENT_META_INTERFACE(BinderServiceTest, "android.test.IBinderServiceTest");
将这两个宏展开会等到
1.---> IBinderServiceTest.h
2.
3.class IBinderServiceTest: public IInterface {
4.public:
5. static const android::String16 descriptor;
6. static android::sp<IBinderServiceTest > asInterface
7. (const android::sp<android::IBinder>& obj);
8. virtual const android::String16& getInterfaceDescriptor() const;
9. IBinderServiceTest ();
10. virtual ~IBinderServiceTest ();
11. virtual int add(int a, int b) = 0;
12.};
1.---> IBinderServiceTest.cpp
2.
3. const android::String16 IBinderServiceTest ::descriptor("android.test.IBinderServiceTest");
4. const android::String16& IBinderServiceTest ::getInterfaceDescriptor() const {
5. return IBinderServiceTest ::descriptor;
6. }
7. android::sp<IBinderServiceTest > IBinderServiceTest ::asInterface
8. (const android::sp<android::IBinder>& obj)
9. {
10. android::sp<IBinderServiceTest > intr;
11. if (obj != NULL) {
12. intr = static_cast<IBinderServiceTest *>
13. (obj->queryLocalInterface(IBinderServiceTest ::descriptor).get());
14. if (intr == NULL) {
15. intr = new BpBinderServiceTest (obj);
16. }
17. }
18. return intr;
19. }
20. IBinderServiceTest ::IBinderServiceTest () { }
21. IBinderServiceTest ::~IBinderServiceTest () { }
展开的宏里,我们找到了asInterface,这里new了一个 BpBinderServiceTest,然后将其返回。Client端得到Server端的代理BpBinderServiceTest后,就可以像本地调用一样来使用Server端的接口。示例程序中调用了add()函数,看一下它早Proxy中的实现。
1.---> IBinderServiceTest.cpp
2.
3.class BpBinderServiceTest: public BpInterface<IBinderServiceTest>
4.{
5.public:
6. BpBinderServiceTest(const sp<IBinder>& impl) :
7. BpInterface<IBinderServiceTest> (impl) {
8. }
9.
10. int add(int a, int b) {
11. // Parcel类用来于序列化进程间通信数据。
12. Parcel data, reply;
13. ALOGI("BpBinderServiceTest add, a = %d, b = %d", a, b);
14.
15. // 写入Binder传输数据的头,这里写入Service描述符“android.test.IBinderServiceTest”。
16. data.writeInterfaceToken(IBinderServiceTest::getInterfaceDescriptor());
17. // 之后向Binder中写入要发送给Server的数据。
18. data.writeInt32(a);
19. data.writeInt32(b);
20. // 开始进行远端的传输调用。
21. remote()->transact(TEST_ADD, data, &reply);
22. // 读取Server返回的数据。
23. int sum = reply.readInt32();
24.
25. ALOGI("BpBinderServiceTest sum = %d", sum);
26. return sum;
27. }
28.};
代码中,remote()来自于BpRefBase类,它返回一个BpBinder指针,因此这将调用BpBinder::transact。TEST_ADD是Binder执行的命令编码,Server会根据这个值来执行相应的命令。实际的Binder传输是在IPCThreadState中完成的,传输时同步的,调用返回表示Server端已经执行结束。这里不做详解。
Server端代码解析
Client端发送命令TEST_ADD,看看Server端是如何执行这个命令的。
1.---> IBinderServiceTest.cpp
2.
3.status_t BnBinderServiceTest::onTransact(uint32_t code, const Parcel& data,
4. Parcel* reply, uint32_t flags) {
5. switch (code) {
6. // 接收到Client端的命令TEST_ADD。
7. case TEST_ADD: {
8. // 检查数据头是否为Service描述符。
9. CHECK_INTERFACE(IBinderServiceTest, data, reply);
10.
11. // 读取输入的数据。
12. int a = data.readInt32();
13. int b = data.readInt32();
14. ALOGI("BnBinderServiceTest add, a = %d b = %d", a, b);
15.
16. int sum = 0;
17. // 调用Server对应的函数
18. sum = add(a, b);
19. ALOGI("BnBinderServiceTest sum = %d", sum);
20. // 写入返回数据到Binder。
21. reply->writeInt32(sum);
22. return sum;
23. }
24. default:
25. return BBinder::onTransact(code, data, reply, flags);
26. }
27.}
Server端的源头也是在IPCThreadState中。IPCThreadState借助ProcessState类来与Binder驱动程序交互,接收Client处的请求。之后调用BBinder类的transact函数,并传入相关参数。BBinder类的transact函数最终调用BnBinderServiceTest类的onTransact函数。
下面从Server端启动开始分析。
1.---> BinderServerRun.cpp
2.
3.int main(int argc, char** argv)
4. {
5. // 创建一个ProcessState实例。
6. sp<ProcessState> proc(ProcessState::self());
7. // 得到Service Manager的远程接口。
8. sp<IServiceManager> sm = defaultServiceManager();
9.
10. // 增加Service "my.binder.test"到Service Manager中。
11. BinderServiceTest::instantiate();
12. ProcessState::self()->startThreadPool();
13. IPCThreadState::self()->joinThreadPool();
14. return 0;
15.}
16.
17.
18.---> BinderTestServer.cpp
19.
20.void BinderServiceTest::instantiate() {
21. ALOGI("Enter instantiate");
22.
23. status_t st = defaultServiceManager()->addService(
24. String16("my.binder.test"), new BinderServiceTest());
25. ALOGD("addService ret=%d", st);
26.}
27.
28.BinderServiceTest::BinderServiceTest() {
29. ALOGD("Constructor");
30.}
31.
32.BinderServiceTest::~BinderServiceTest() {
33. ALOGD("Destructor");
34.}
35.
36.int BinderServiceTest::add(int a, int b) {
37. ALOGI("add a = %d, b = %d.", a, b);
38. return a+b;
39.}
Server端首先要通过ProcessState::self()调用创建一个ProcessState实例。ProcessState::self()是ProcessState类的一个静态成员变量,这个函数返回一个全局唯一的ProcessState实例gProcess。代码如下
1.---> ProcessState.cpp
2.
3.sp<ProcessState> ProcessState::self()
4.{
5. Mutex::Autolock _l(gProcessMutex);
6. if (gProcess != NULL) {
7. return gProcess;
8. }
9. gProcess = new ProcessState;
10. return gProcess;
11.}
ProcessState实例化的过程中主要完成两个工作。一是会通过open_driver函数打开Binder设备文件/dev/binder,并将打开设备文件描述符保存在成员变量mDriverFD中;二是通过mmap来把设备文件/dev/binder映射到内存中。这里不做详解。
接下来分析startThreadPool()和joinThreadPool()到底做了什么。startThreadPool() 的实现如下面的代码所示:
1.---> ProcessState.cpp
2.
3.void ProcessState::startThreadPool()
4.{
5. AutoMutex _l(mLock);
6. if (!mThreadPoolStarted) {
7. mThreadPoolStarted = true;
8. spawnPooledThread(true);
9. }
10.}
11.......
12.void ProcessState::spawnPooledThread(bool isMain)
13.{
14. if (mThreadPoolStarted) {
15. String8 name = makeBinderThreadName();
16. ALOGV("Spawning new pooled thread, name=%s\n", name.string());
17. sp<Thread> t = new PoolThread(isMain);
18. t->run(name.string());
19. }
20.}
PoolThread 是在 IPCThreadState 中定义的一个 Thread 子类,它的实现如下所示:
1.---> ProcessState.cpp
2.
3.class PoolThread : public Thread
4.{
5.public:
6. PoolThread(bool isMain)
7. : mIsMain(isMain)
8. {
9. }
10.
11.protected:
12. virtual bool threadLoop()
13. {
14. IPCThreadState::self()->joinThreadPool(mIsMain);
15. return false;
16. }
17.
18. const bool mIsMain;
19.};
PoolThread继承Thread类,其run函数调用Thread::run()创建一个线程,最终调用子类的threadLoop函数。threadLoop()也是调用joinThreadPool()完成工作。joinThreadPool()的代码如下。
1.---> IPCThreadState.cpp
2.
3.status_t IPCThreadState::getAndExecuteCommand()
4.{
5. status_t result;
6. int32_t cmd;
7.
8. result = talkWithDriver();
9. if (result >= NO_ERROR) {
10. size_t IN = mIn.dataAvail();
11. if (IN < sizeof(int32_t)) return result;
12. cmd = mIn.readInt32();
13. IF_LOG_COMMANDS() {
14. alog << "Processing top-level Command: "
15. << getReturnString(cmd) << endl;
16. }
17.
18. result = executeCommand(cmd);
19.
20. // After executing the command, ensure that the thread is returned to the
21. // foreground cgroup before rejoining the pool. The driver takes care of
22. // restoring the priority, but doesn't do anything with cgroups so we
23. // need to take care of that here in userspace. Note that we do make
24. // sure to go in the foreground after executing a transaction, but
25. // there are other callbacks into user code that could have changed
26. // our group so we want to make absolutely sure it is put back.
27. set_sched_policy(mMyThreadId, SP_FOREGROUND);
28. }
29.
30. return result;
31.}
32.......
33.void IPCThreadState::joinThreadPool(bool isMain)
34.{
35. LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
36.
37. mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
38.
39. // This thread may have been spawned by a thread that was in the background
40. // scheduling group, so first we will make sure it is in the foreground
41. // one to avoid performing an initial transaction in the background.
42. set_sched_policy(mMyThreadId, SP_FOREGROUND);
43.
44. status_t result;
45. do {
46. processPendingDerefs();
47. // now get the next command to be processed, waiting if necessary
48. result = getAndExecuteCommand();
49.
50. if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
51. ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
52. mProcess->mDriverFD, result);
53. abort();
54. }
55.
56. // Let this thread exit the thread pool if it is no longer
57. // needed and it is not the main process thread.
58. if(result == TIMED_OUT && !isMain) {
59. break;
60. }
61. } while (result != -ECONNREFUSED && result != -EBADF);
62.
63. LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
64. (void*)pthread_self(), getpid(), (void*)result);
65.
66. mOut.writeInt32(BC_EXIT_LOOPER);
67. talkWithDriver(false);
68.}
这个函数最终是在一个无穷循环中,通过调用talkWithDriver函数来和Binder驱动程序进行交互,实际上就是调用talkWithDriver来等待Client的请求,然后再调用executeCommand来处理请求,而在executeCommand函数中,最终会调用BBinder::transact来真正处理Client的请求。而BBinder::transact最终会调用onTransact函数来处理,也就实际调用了示例中的BnBinderServiceTest::onTransact。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。