Binder原理

Binder是Android底层实现进程通讯的一种方式,由于它的调用过程比较复杂。本篇暂不涉及源码,只是做一个原理上的讲解,而具体的源码调用,会在后面用一个系列的篇章来分析。

Binder这种进程通讯是Android系统特有的,也就是说,进程间的通讯其实还有许多实现方式,通常称为传统的进程通讯方式。

传统IPC方式:

  • 管道(Pipe) :操作简单,但只能在父子进程间通讯,并且只能单向通讯。
  • FiFO:解决了Pipe需要父子进程的问题,但长期存在于系统之中,使用不当容易出错。
  • 信号量(Signal):不适用数据量大的传输。
  • 消息队列(Message):信息的复制需要消耗CPU的时间.不适用信息量大或操作频繁的情形。
  • Socket:传输效率低,开销大,主要用在网络通讯。
  • 共享内存(Share Memory):共享内存无须拷贝,可操作大数据量,但实现复杂。

传统IPC原理:

对于 32 位系统,它的寻址空间(虚拟存储空间)就是 2 的 32 次方,即 4GB。分内核空间和用户空间:

  • 内核空间:最高的 1GB 字节供内核使用,权限为0级;
  • 用户空间:低的 3GB 字节供各进程使用,权限为3级。

用户空间是每个进程私有的,其他进程不能够访问。而用户空间访问内核资源的资源,无法直接访问,需要借助系统调用来实现。系统调用指的是,根据系统对外暴露的api接口,来访问系统资源,换句话说,系统封装了一层实现,如果用户空间要访问内核资源,需要交给这一层实现,来帮我们访问。

系统调用主要通过如下两个函数来实现:

//将数据从用户空间拷贝到内核空间
copy_from_user() 

//将数据从内核空间拷贝到用户空间
copy_to_user() 

消息发送方,将要发送的数据存放在用户空间的内存缓存区中,接着通过系统调用进入内核态,内核程序在内核空间分配内存,开辟一块内核缓存区。然后调用 copy_from_user() 函数,将数据从用户空间的内存缓存区,拷贝到内核空间的内核缓存区中。同样的,接收方进程在接收数据时,在用户空间开辟一块内存缓存区,接着内核程序调用 copy_to_user() 函数,将数据从内核缓存区拷贝到接收进程的用户空间内存缓存区。

可以看到,整个发送和接收的通讯过程,内核需要做2次数据的拷贝。这里的2次,指的是从用户空间切换到内核空间,和从内核空间用户空间,每做一次切换,系统都需要比较大的开销,因此,应尽量减少切换的次数,这是第一个问题。

第二个问题是,接收数据的缓存区由数据接收进程提供,但是接收进程并不知道需要多大的空间,来存放将要传递过来的数据,因此只能开辟尽可能大的内存空间或者先调用 API 接收消息头,来获取消息体的大小,这两种做法不是浪费空间就是浪费时间。

Binder原理

传统的方式在用户和内核态间切换,至少要拷贝2次数据,共享内存虽无需拷贝,但实现复杂。而Binder只要拷贝1次,性能仅次于共享内存。

传统的方式接收方无法获得对方可靠的进程用户ID/进程ID(UID/PID),从而无法鉴别对方身份。而android系统为每个安装好的 APP 分配了自己的 UID,故而进程的 UID 是鉴别进程身份的可靠标志。而且 Binder 既支持实名 Binder,又支持匿名 Binder,安全性高。

传统的 IPC 方式如Pipe、Socket 都是内核的一部分,通过内核支持来实现进程间通信,自然没问题。但是 Binder 并不是 Linux 系统内核的一部分,因此,需要借助 Linux 的动态内核可加载模块(Loadable Kernel Module,LKM)的机制,动态添加一个内核模块运行在内核空间中,这个内核模块就是Binder 驱动(Binder Dirver)

内存映射

Binder Dirver是通过内存映射,来进行进程通讯的。系统对外提供了一个函数mmap(),来做内存映射。它的原理是,将用户空间的一块内存区域映射到内核空间。用户对这块内存区域的修改,就可以直接反应到内核空间;同样的,内核空间对这块内存的修改,也能直接反应到用户空间。

但mmap通常用在有物理介质的文件系统上。因为,进程中的用户空间是不能直接访问物理设备的,所以,通常情况下,我们对磁盘上一个文件进行I/O读写,是系统先把磁盘的数据拷贝到内核空间,再从内核空间把数据拷贝到用户区域。这种情况下,就可以通过mmap来做映射,用内存读写取代I/O读写,剩去了数据拷贝,提高效率。

int main(void){
   //打开磁盘上的文件
   int fd =  open("test",O_RDWR|O_TRUNC|O_CREAT,0664);
   //拓展10字节
   ftruncate(fd,10);
   //获取文件长度
   int len = lseek(fd,0,SEEK_END);
   //映射地址
   char *memp;
   //内存映射
   memp = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
    //映射失败
    if(memp==MAP_FAILED){
         perror("mmap error");
         exit(1);
     }

    //关闭文件
    close(fd);
    //将数据写入内存
    strcpy(memp,"hello world\n");
    
    //关闭内存映射
    int ret = munmap(memp,len);  
    if(ret==-1){
       perror("mmap error");
       exit(1);
    }

   return 0;
 }

打开test文件:

hello world

如上代码,我们将一个文件映射到内存中,然后往内存中写入一串数据,数据将会同步写入文件中。

上面的示例虽然使用了物理介质(磁盘文件)来做映射,但用mmap做内存映射,物理介质并不是必须的。也就是说,我们可以在内核中创建一块内存空间,并将这块内存映射到接收进程的用户空间(等同于磁盘文件),当我们往这块内存中写数据时,也就同步传递到接收进程的用户空间中。大致的创建流程分三步:

image.png
  • Binder 驱动先在内核空间创建一个数据接收缓存区
  • 接着在内核空间开辟一块内核缓存区,将接收缓存区接收进程用户空间地址进行映射;
  • 发送方进程通过系统调用 copy_from_user() 将数据拷贝到内核中的内核缓存区,内核缓存区会将数据写到接收缓存区中,由于接收缓存区映射到了接收进程用户空间地址,因此接收进程就同步收到了数据,整个过程只经历用户到内核的1次拷贝。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容