微信号:open_dev

介绍:欢迎关注open软件开发小组;我们专注于android平台上学习类app开发,每周分享Android开发技巧、经验,让我们一起交流学习,共同进步.

Android Binder 分析系列——原理(上)

2017-04-19 08:16 胡明明
  作者 介绍 

胡明明


专注于AndroidFramework、VR开发。

         分析之前说一下原理。为要 android 要搞这么复杂的一个东西。那是因为 android 是个多进程的系统,进程间的数据交换、相互调用(某几个程序配合完成某些业务)就涉及跨进程通信。2个进程不能直接访问数据的原因:

  1. 1、每个进程的地址空间的独立的,所以进程A中某个数据的地址在进程B中不确定是什么东西。

  2. 2、安全性,如果能随便访问其它进程空间的数据,那么是非常危险的事情(想想看你再用支付宝输支付密码的时候,其它随便一个程序就能轻轻松松读取你输入的密码是多么恐怖)。

所以 android 就整一套进程通信框架——binder。

一、原理

        首先 binder 在最底层有 kernel 的驱动支持。/dev/binder 是 binder 的设备文件。然后 android 通过这个驱动在 native 层整了一套 C/S 架构的框架出来,最后在 java 对应也封装了一层(可以理解为 native 的马甲)。这些东西后面再慢慢分析。

二、应用

        基于 binder android 弄了很多 manager services,不过我觉得倒是因为需要存在这些 maanger services 才需要 binder 进程间通信。这里说说为什么需要这些 manager services(我后面把这些称为:那一票 services)。因为设备的上的有些硬件(例如相机、传感器)一般一次只能一个访问,有些需要把一些数据混合在一起输出(SurfaceFlinger、AudioFlinger),这就需要一些管理,但是应用是不同的程序,它们并不知道其它人的情况,所以就需要一个 manager,而且这个 manager 是要能接受不同进程的。这就引出了 android binder 的最经典的场景—— android 那一票 services。

        同时由于有这一票 services 的 存在,那么又要有人来管它们,所以就有一个东西叫: ServiceManager 。这个东西本身也是基于 binder 通信的。

三、框架设计——native

        binder 主要的实现在 native 层。先来张图,整体对框架有个概括(图中我省略了 binder 进程 death 之后的通知机制,这个可以后面单独分析,这里只是画出了刚开始比较关键的通信的那部分):

        这里先啰嗦下 binder native 层的代码位置(这个是个模块,相关的都里面,没几个文件,自己找吧):

1

2

3

4

5

# 头文件:

frameworks/native/include/binder

# 实现:

frameworks/native/libs/binder


        图中分为2个部分:一个是实现部分(BBinder、BpBinder 那部分),一个是接口部分(IInterface 那部分)。先来看下实体部分:

        前面说了 binder 是 C/S 架构的,那当然得有 server 和 client。BBinder 代表 server,BpBinder 代表 client,然后在这个基础上抽象出 IBinder 这个基类。IBinder 中比较重要的抽象方法有4个:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

/**

* Check if this IBinder implements the interface named by

* @a descriptor.  If it does, the base pointer to it is returned,

* which you can safely static_cast<> to the concrete C++ interface.

*/

virtual sp<IInterface>  queryLocalInterface(const String16& descriptor);

virtual status_t        transact(   uint32_t code,

const Parcel& data,

Parcel* reply,

uint32_t flags = 0) = 0;

virtual BBinder*        localBinder();

virtual BpBinder*       remoteBinder();

然后在基类有默认实现的是3个:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

sp<IInterface>  IBinder::queryLocalInterface(const String16& descriptor)

{

return NULL;

}

BBinder* IBinder::localBinder()

{

return NULL;

}

BpBinder* IBinder::remoteBinder()

{

return NULL;

}


        基类的实现还真全是马甲,但是这样也有个好出,就是子类可以只覆盖自己感兴趣的方法就可以了(否则子类就必须全部实现,不然编译会报错的)。

        先来看看 localBinder 和 remoteBinder 这2个,这2个看定义就十分明显了,一个是返回 BBinder 的指针(服务器的),一个是返回 BpBinder 的指针(客户端的),而且在 BBinder 和 BpBinder 分别只实现了一个:

1

2

3

4

5

6

7

8

9

10

11

# 简单干脆,都直接返回自己

BBinder* BBinder::localBinder()

{

return this;

}

BpBinder* BpBinder::remoteBinder()

{

return this;

}

        然后是 queryLocalInterface 这个,这个返回的是 IInterface 的指针(sp android 搞的啥智能指针,可以参看我前面一篇相关的备忘,挺烦的)。BBinder 和 BpBinder 都没有实现,这个放到后面暴露的接口去实现了(后面再说)。

        最后来看下: transact,这个看名字,和参数就知道这个就是通信用的方法。这个在基类中也没实现,但是在 BBinder 和 BpBinder 有实现,并且不一样(当然得不一样,服务器能和客户端一样么)。BBinder 的:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

status_t BBinder::transact(

uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

data.setDataPosition(0);

status_t err = NO_ERROR;

switch (code) {

case PING_TRANSACTION:

reply->writeInt32(pingBinder());

break;

default:

err = onTransact(code, data, reply, flags);

break;

}

if (reply != NULL) {

reply->setDataPosition(0);

}

return err;

}


        那个 PING_TRANSACTION 估计是测试用的,先不理它,它主要就是调用了 onTransact 这个回调。这个回调是在 BBinder 中定义的,是个虚函数,主要留给它的子类来实现。可以想象得到服务器端在等待客户端的请求,当有请求来的时候,就会出发 onTransact 然后由具体的服务(子类)来实现这个回调,处理不同的逻辑。

        而在 BpBinder 中是这样的:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

status_t BpBinder::transact(

uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

// Once a binder has died, it will never come back to life.

if (mAlive) {

status_t status = IPCThreadState::self()->transact(

mHandle, code, data, reply, flags);

if (status == DEAD_OBJECT) mAlive = 0;

return status;

}

return DEAD_OBJECT;

}


        又是马甲,这个IPCThreadState 是线程剧本变量,就是一个线程存一个,不同线程不一样,binder 的 C/S 架构采用了多线程来处理请求,这个也是后面再分析,先来看看实现再说:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

status_t IPCThreadState::transact(int32_t handle,

uint32_t code, const Parcel& data,

Parcel* reply, uint32_t flags)

{

status_t err = data.errorCheck();

flags |= TF_ACCEPT_FDS;

IF_LOG_TRANSACTIONS() {

TextOutput::Bundle _b(alog);

alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "

<< handle << " / code " << TypeCode(code) << ": "

<< indent << data << dedent << endl;

}

if (err == NO_ERROR) {

LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),

(flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");

err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);

}

if (err != NO_ERROR) {

if (reply) reply->setError(err);

return (mLastError = err);

}

if ((flags & TF_ONE_WAY) == 0) {

#if 0

if (code == 4) { // relayout

ALOGI(">>>>>> CALLING transaction 4");

} else {

ALOGI(">>>>>> CALLING transaction %d", code);

}

#endif

if (reply) {

err = waitForResponse(reply);

} else {

Parcel fakeReply;

err = waitForResponse(&fakeReply);

}

#if 0

if (code == 4) { // relayout

ALOGI("<<<<<< RETURNING transaction 4");

} else {

ALOGI("<<<<<< RETURNING transaction %d", code);

}

#endif

IF_LOG_TRANSACTIONS() {

TextOutput::Bundle _b(alog);

alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "

<< handle << ": ";

if (reply) alog << indent << *reply << dedent << endl;

else alog << "(none requested)" << endl;

}

} else {

err = waitForResponse(NULL, NULL);

}

return err;

}


        这个函数中关键点是 writeTransactionData 和 waitForResponse,这2个函数分别是对 binder 驱动写请求(数据已经通过 Parcel 打包好,这个也是后面再分析),然后等待 binder 驱动的返回的数据结果(服务器那端写的)。驱动相关的也是后面再说,先在继续往下走。这里可以看得出客户端是将请求写入驱动,发送给服务器,然后等待服务器返回的结果。

        然后就是接口了,接口基类是 IInterface,这个基类很简单,就定义2个有用的函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

class IInterface : public virtual RefBase

{

public:

IInterface();

sp<IBinder>         asBinder();

sp<const IBinder>   asBinder() const;

protected:

virtual                     ~IInterface();

virtual IBinder*            onAsBinder() = 0;

};

sp<IBinder> IInterface::asBinder()

{

return this ? onAsBinder() : NULL;

}

sp<const IBinder> IInterface::asBinder() const

{

return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL;

}

        其实它留给子类的就 onAsBinder 这个回调,用来获取 IBinder 的指针。IInterface 的子类是 BnInterface  和 BpInterface  分别对应 BBinder(服务器) 和 BpBinder(客户端)的接口。在这之前得先看看 INTERFACE 这个东西,android 在这里弄了一个模版类,BnXx 和 BpXx 都是。

在 IInterface.h 中有这2个宏:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

// ----------------------------------------------------------------------

#define DECLARE_META_INTERFACE(INTERFACE)                               \

static const android::String16 descriptor;                          \

static android::sp<I##INTERFACE> asInterface(                       \

const android::sp<android::IBinder>& obj);                  \

virtual const android::String16& getInterfaceDescriptor() const;    \

I##INTERFACE();                                                     \

virtual ~I##INTERFACE();                                            \

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \

const android::String16 I##INTERFACE::descriptor(NAME);             \

const android::String16&                                            \

I##INTERFACE::getInterfaceDescriptor() const {              \

return I##INTERFACE::descriptor;                                \

}                                                                   \

android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \

const android::sp<android::IBinder>& obj)                   \

{                                                                   \

android::sp<I##INTERFACE> intr;                                 \

if (obj != NULL) {                                              \

intr = static_cast<I##INTERFACE*>(                          \

obj->queryLocalInterface(                               \

I##INTERFACE::descriptor).get());               \

if (intr == NULL) {                                         \

intr = new Bp##INTERFACE(obj);                          \

}                                                           \

}                                                               \

return intr;                                                    \

}                                                                   \

I##INTERFACE::I##INTERFACE() { }                                    \

I##INTERFACE::~I##INTERFACE() { }                                   \

#define CHECK_INTERFACE(interface, data, reply)                         \

if (!data.checkInterface(this)) { return PERMISSION_DENIED; }       \

// ----------------------------------------------------------------------

        如果在 .h 中的 class 定义中调用 DECLARE_META_INTERFACE("Xx") 在 .cpp 中的实现中调用 IMPLEMENT_META_INTERFACE("Xx", "Xx") 那么就相当于声明和实现了:

  1. 1、默认构造函数

  2. 2、析构函数

  3. 3、定义了并以 Xx 初始化 String16 descriptor 这个变量

  4. 4、asInterface: 返回 IXx 的指针

  5. 5、getInterfaceDescriptor: 返回 descriptor 字符串

        实际上,后面的具体的 native 的 service 的接口就是这么写的(后面会有具体的实例分析)。

接下来就看真正的接口基类: BnInterface :

1

2

3

4

5

6

7

8

9

10

11

template<typename INTERFACE>

class BnInterface : public INTERFACE, public BBinder

{

public:

virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);

virtual const String16&     getInterfaceDescriptor() const;

protected:

virtual IBinder*            onAsBinder();

};

        哎呦咧,C++ 的多重继承,分别继续了 BBinder(binder 的服务器) 和 INTERFACE 这个其实就是上面的 IInterface,在具体的 services 中会通过 IInterface 中的那2个宏弄一个 IXx 出来,然后 BnInterface 这里的 INTERFACE 就是 IXx(这个后面到了实例分析,就会很清楚了)。这里实现上面 BBinder 那没实现的几个接口:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

template<typename INTERFACE>

inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(

const String16& _descriptor)

{

// 对比下是不是自己的标示,是的话直接返回自己

if (_descriptor == INTERFACE::descriptor) return this;

return NULL;

}

template<typename INTERFACE>

inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const

{

// 这 ... 有必要重写一下么??

return INTERFACE::getInterfaceDescriptor();

}

template<typename INTERFACE>

IBinder* BnInterface<INTERFACE>::onAsBinder()

{

// 这里抛弃 BBinder 的 localBinder 了,直接返回自己了

return this;

}

        queryLocalInterface 这个是只有 BBinder 才有的(对比 IBinder 的接口),然后根据在这个函数的实现:对比 descriptor 是不是自己定义的(通过DECLARE_META_INTERFACE 这个宏定义的),然后是否返回自己,可以猜得到:1、这个函数是用来判断请求是不是处于本进程内,如果是的话,应该就不需要跨进程调用,直接可以调用本进程的方法。这样对于上层应用来说,暴露的是 IBinder 接口,上层应用不需要关心调用是本地的还是远程的。2:descriptor 这个是用来区别 binder 的服务器的,binder 通过这个来判断请求是不是发给自己的,如果 descriptor 不匹配,则拒绝处理。(这些猜测后面再慢慢说)

然后是 BpInterface 了:

1

2

3

4

5

6

7

8

9

10

template<typename INTERFACE>

class BpInterface : public INTERFACE, public BpRefBase

{

public:

BpInterface(const sp<IBinder>& remote);

protected:

virtual IBinder*            onAsBinder();

};

        比 Bn 相比,没了判断是不是本地的接口了,客户端当然不需要有啦。然后应该是继续 BpBinder 的,变成了 BpRefBase ,看到这个名字我又想到了 android 那蛋疼的智能指针和引用计数,我真的很烦这个东西,就不能好好的自己管好内存么??

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

class BpRefBase : public virtual RefBase

{

protected:

BpRefBase(const sp<IBinder>& o);

virtual                 ~BpRefBase();

virtual void            onFirstRef();

virtual void            onLastStrongRef(const void* id);

virtual bool            onIncStrongAttempted(uint32_t flags, const void* id);

// 最重要的一个函数,返回 mRemote IBinder 指针

inline  IBinder*        remote()                { return mRemote; }

inline  IBinder*        remote() const          { return mRemote; }

private:

BpRefBase(const BpRefBase& o);

BpRefBase&              operator=(const BpRefBase& o);

IBinder* const          mRemote;

RefBase::weakref_type*  mRefs;

volatile int32_t        mState;

};


       上面这个东西,其它的不看,就看一个函数 remote() 返回 mRemote 这个 IBinder 指针。然后来看下 BpInterface 的构造函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

template<typename INTERFACE>

inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)

: BpRefBase(remote)

{

}

template<typename INTERFACE>

inline IBinder* BpInterface<INTERFACE>::onAsBinder()

{

// 调用 BpRefBase 的 remote() 返回 BpBinder 的远程 binder 指针

return remote();

}


        BpInterface 的 sp  参数的构造函数,把 sp  传给 BpRefBase 了,这个 IBinder 其实就是 BpBinder (通过后面的分析可以看得出的)。结合上面 Bn 的 onAsBinder 是返回 this 自己(BBinder),Bp 的是返回 BpBinder 。

        再下面,就是具体业务相关的了,IXx 继承自 IInterface,主要是使用 IInterface 提供的那个 DECLARE_META_INTERFACE(Xx) 这个宏声明一些接口(上面有分析的),Xx 就是接口的名字了,例如 ServerManager、SurfaceComposer 之类的(这个后面会有具体的实例分析的)。然后这个 IXx 还得定义这个 service 对外(客户端)提供的接口,例如 CaptureScreen 之类的,这个就和具体的 service 相关了。

        BnXx 继承 BnInterface(同时继承 IXx),使用 IInterface 提供的 IMPLEMENT_META_INTERFACE(Xx, Xx) 来实现上面说的那些接口。注意这里的 Xx 要和 DECLARE_META_INTERFACE 那里的一样,例如都叫 SurfaceComposer, 然后后面那个是标示(descriptor),例如 “android.ui.ISurfaceComposer”(用包名来标示一般不会重复)。

        然后剩下的主要是实现 onTransact 就是响应客户端的请求。其实通过后面的分析 BnXx 中也并不是真正实现请求的地方,这个只是一个中转站而已,真正的实现在 service 模块里面,一个一个业务函数实现的,这里的 onTransact 只是区分客户端发过来的请求命令,然后去调用 service 里面的函数,实现这些的文件都叫 I
Xx.h, IXx.cpp 看上去也不像实现的样子。然后真正的 service 就要继承 BnXx 去实现 onTransact。但是你也发现了,onTransact 已经在 BnXx 里实现了,所以你在 services 看到的 onTransact 都是马甲(有些做了一些拦截,例如权限检测,没权限的请求直接拦截下来),基本上都是调用: super.onTransact 的 -_-|| 。

        BpXx 继承 BpInterface。 BpInterface 并没强制要求 BpXx 实现啥东西,但是作用客户端(Java 层那一堆 XxManager 给其它 apk 调用的),暴露给第三方引用使用的,必须要实现服务器提供的方法对应的接口:例如说 service 那边有一个方法是: captureScreen 用来实现截屏用的,那么客户端也必须有响应的方法: captureScreen,然后客户端调用 remote()(IBinder) 的 transact 发送请求到服务器。当然其实函数名字也可以不一一对应,你只要在服务器 onTransact 里调用正确就行了。但是后面你会发现如果这些东西一一对应的话,代码是很机械的,后面 android 就搞了个代码自动生成的工具出来(aidl)。

        这里 native 层的框架就说完了。接下来看下 java 层的。见《Android Binder 分析系列——原理(下)》

小贴士
     

        本文由原作者胡明明独家授权Open软件开发小组发布,著作权归原作者所有。如需转载请联系原作者申请授权。

       申请加群交流学习请加主编微信:Jf-1994(井方哥),并备注:姓名-地区-公司-职业-加群。




Open软件开发小组



专注Android开发,欢迎关注open_dev



点击“阅读原文”
 
Open软件开发小组 更多文章 [第30期]Android技术资源每周精选 [第29期]Android技术资源每周精选 [第28期]Android技术资源每周精选 [第27期]Android技术资源每周精选 [第26期]Android技术资源每周精选
猜您喜欢 【753】未来十年:世界的风口依然在中国(深度好文) 今晚公开课《HBase简介与实践分享》,搜狗刘俊宏,9月10日,19:30-21:30 如何在Cell中有不定数量个带图Button的情况下,保持性能和代码可读性? python VS matlab 每个程序员应该知道的计算机网络知识