前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >连 Binder 都不知道?来看看 Android 插件化开发技术分享

连 Binder 都不知道?来看看 Android 插件化开发技术分享

作者头像
Android技术干货分享
发布2019-03-26 17:57:26
4840
发布2019-03-26 17:57:26
举报
文章被收录于专栏:Android技术分享Android技术分享

在Android开发过程中,Binder的身影无处无处不在,我们编写的程序都使用过Binder机制(例如startActivity的执行过程)但是请问你知道什么是Binder么?在开发过程中你察觉到它的存在了么?Biner翻译过来是“胶水“的意思,这个翻译分形象。Binder的主要工作就是淡化了进程边界,淡化了进程间通信的过程。要是想更好的理解Binder就必须从Linux进程谈起。

Linux进程

为了保护进程空间不被别的进程破坏或者干扰,Linux中的进程是相互独立的,也就是所谓的进程隔离。(而且一个进程的内存空间还被分为了用户空间和内核空间,二者也是相互隔离的。这里不做探讨)所以在Linux中,进程与进程之间是相互隔离的,而且进程中的用户和内核空间也是隔离的。

也就是说为了安全和独立,一个进程是不能直接操作或者访问另外一个进程的内存空间的。他们之间既然是隔离的,在需要通信、协作的时候就需要使用进程间通信技术(即IPC,也称跨进程通信),我们都知道Android框架是建立在Linux之上的,当然也会面对进程间通讯的问题。

为什么使用Binder

在Linux系统中为了达到进程间通讯的目的,我们可以选用诸如管道、Socket等技术手段,那么为什么Android选用了Binder这种新型的IPC技术,放弃了原有成熟的技术呢?

主要有如下两个方面:

1.性能角度

由于在移动设备诸如省电等性能的考虑,广泛地使用进程间通讯对于通信机制的性能有严格的要求,Binder相对于传统的Socket、管道方式更加高效。Bidner数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,内存共享方式一次内存拷贝都不需要,但是实现起来难度高,复杂性大。

2.稳定性角度

传统的进程通信方式对于通信双方的身份并没有做出严格的验证,比如Socket通信ip地址是客户端手动填入,很容易进行伪造,而Binder机制从协议本身就支持对通信双方做身份校检,因而大大提升了安全性。

Binder机制

一、Binder通信概述

binder通信是一种client-server的通信结构。

1.从表面上来看,是client通过获得一个server的代理接口,对server进行直接调用;

2.实际上,代理接口中定义的方法与server中定义的方法是一一对应的;

3.client调用某个代理接口中的方法时,代理接口的方法会将client传递的参数打包成为Parcel对象;

4.代理接口将该Parcel发送给内核中的binder driver.

5.server会读取binder driver中的请求数据,如果是发送给自己的,解包Parcel对象,处理并将结果返回;

6.整个的调用过程是一个同步过程,在server处理的时候,client会block住。

二、service manager

Service Manager是一个linux级的进程,顾名思义,就是service的管理器。这里的service是什么概念呢?这里的service的概念和init过程中init.rc中的service是不同,init.rc中的service是都是linux进程,但是这里的service它并不一定是一个进程,也就是说可能一个或多个service属于同一个linux进程。在这篇文章中不加特殊说明均指android native端的service。

任何service在被使用之前,均要向SM(Service Manager)注册,同时客户端需要访问某个service时,应该首先向SM查询是否存在该服务。如果SM存在这个service,那么会将该service的handle返回给client,handle是每个service的唯一标识符。

SM的入口函数在service_manager.c中,下面是SM的代码部分:

代码语言:javascript
复制
int main(int argc, char **argv)
{
 struct binder_state *bs;
 void *svcmgr = BINDER_SERVICE_MANAGER;
 bs = binder_open(128*1024);
 if (binder_become_context_manager(bs)) {
 LOGE(“cannot become context manager (%s)/n”, strerror(errno));
 return -1;
 }
 svcmgr_handle = svcmgr;
 binder_loop(bs, svcmgr_handler);
 return 0;
}

这个进程的主要工作如下:

1.初始化binder,打开/dev/binder设备;在内存中为binder映射128K字节空间;

2.指定SM对应的代理binder的handle为0,当client尝试与SM通信时,需要创建一个handle为0的代理binder,这里的代理binder其实就是第一节中描述的那个代理接口;

3.通知binder driver(BD)使SM成为BD的context manager;

4.维护一个死循环,在这个死循环中,不停地去读内核中binder driver,查看是否有可读的内容;即是否有对service的操作要求, 如果有,则调用svcmgr_handler回调来处理请求的操作。

5.SM维护了一个svclist列表来存储service的信息。

这里需要声明一下,当service在向SM注册时,该service就是一个client,而SM则作为了server。而某个进程需要与service通信时,此时这个进程为client,service才作为server。因此service不一定为server,有时它也是作为client存在的。

三、ProcessState

ProcessState是以单例模式设计的。每个进程在使用binder机制通信时,均需要维护一个ProcessState实例来描述当前进程在binder通信时的binder状态。

ProcessState有如下2个主要功能:

1.创建一个thread,该线程负责与内核中的binder模块进行通信,称该线程为Pool thread;

2.为指定的handle创建一个BpBinder对象,并管理该进程中所有的BpBinder对象。

(一)Pool thread

在Binder IPC中,所有进程均会启动一个thread来负责与BD来直接通信,也就是不停的读写BD,这个线程的实现主体是一个IPCThreadState对象,下面会介绍这个类型。

下面是 Pool thread的启动方式:

ProcessState::self()->startThreadPool();

(二) BpBinder获取

BpBinder主要功能是负责client向BD发送调用请求的数据。它是client端binder通信的核心对象,通过调用transact函数向BD发送调用请求的数据,它的构造函数如下:

BpBinder(int32_t handle);

通过BpBinder的构造函数发现,BpBinder会将当前通信中server的handle记录下来,当有数据发送时,会通知BD数据的发送目标。

ProcessState通过如下方式来获取BpBinder对象:

代码语言:javascript
复制
ProcessState::self()->getContextObject(handle);

在这个过程中,ProcessState会维护一个BpBinder的vector mHandleToObject,每当ProcessState创建一个BpBinder的实例时,回去查询mHandleToObject,如果对应的handle已经有binder指针,那么不再创建,否则创建binder并插入到mHandleToObject中。

ProcessState创建的BpBinder实例,一般情况下会作为参数构建一个client端的代理接口,这个代理接口的形式为BpINTERFACE,例如在与SM通信时,client会创建一个代理接口BpServiceManager。

四、IPCThreadState

IPCThreadState也是以单例模式设计的。由于每个进程只维护了一个ProcessState实例,同时ProcessState只启动一个Pool thread,也就是说每一个进程只会启动一个Pool thread,因此每个进程则只需要一个IPCThreadState即可。

Pool thread的实际内容则为:

代码语言:javascript
复制
 IPCThreadState::self()->joinThreadPool();

ProcessState中有2个Parcel成员,mIn和mOut,Pool thread会不停的查询BD中是否有数据可读,如果有将其读出并保存到mIn,同时不停的检查mOut是否有数据需要向BD发送,如果有,则将其内容写入到BD中,总而言之,从BD中读出的数据保存到mIn,待写入到BD中的数据保存在了mOut中。

ProcessState中生成的BpBinder实例通过调用IPCThreadState的transact函数来向mOut中写入数据,这样的话这个binder IPC过程的client端的调用请求的发送过程就明了了。

IPCThreadState有两个重要的函数,talkWithDriver函数负责从BD读写数据,executeCommand函数负责解析并执行mIn中的数据。

五、主要基类

(一)基类IInterface

为server端提供接口,它的子类声明了service能够实现的所有的方法;

(二)基类IBinder

BBinder与BpBinder均为IBinder的子类,因此可以看出IBinder定义了binder IPC的通信协议,BBinder与BpBinder在这个协议框架内进行的收和发操作,构建了基本的binder IPC机制。

(三)基类BpRefBase

client端在查询SM获得所需的的BpBinder后,BpRefBase负责管理当前获得的BpBinder实例。


理解Binder对于理解整个Android系统有着非常重要的作用,Android系统的四大组件,AMS,PMS等系统服务无一不与Binder挂钩;如果对Binder不甚了解,那么就很难了解这些系统机制,从而仅仅浮游与表面,不懂Binder你都不好意思说自己会Android开发;要深入Android,Binder是必须迈出的一步。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.01.14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Binder机制
  • 一、Binder通信概述
  • 二、service manager
  • 三、ProcessState
  • 四、IPCThreadState
  • 五、主要基类
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档