Android IPC 之Binder基础

作者: 小鱼人爱编程 | 来源:发表于2021-11-17 13:19 被阅读0次

    前言

    IPC 系列文章:
    建议按顺序阅读。

    Android IPC 之Service 还可以这么理解
    Android IPC 之Binder基础
    Android IPC 之Binder应用
    Android IPC 之AIDL应用(上)
    Android IPC 之AIDL应用(下)
    Android IPC 之Messenger 原理及应用
    Android IPC 之服务端回调
    Android IPC 之获取服务(IBinder)

    在平时的开发中,大部分时候都在编写单个App,每个App就是个进程。App之间的通信即是进程间通信(IPC),Android采用Binder进行IPC。
    通过本篇文章,你将了解到:

    1、Linux IPC 基础
    2、Linux IPC 常用方式
    3、Android Binder 简单认识
    4、Android Binder 使用场合

    1、Linux IPC 基础

    我们知道进程间并不能直接通信,什么是通信呢?
    在自然语言里,通信其实就是交互信息的过程,而在计算机里是交换数据,数据又是存储在内存里,因此关键的问题是:如果两个进程分别能访问到对方数据所在的内存,那么说明进程间能够通信。

    虚拟内存地址空间

    在32位系统里,物理内存寻址大小为:4G。


    image.png

    用32位表示一个地址块(上图的一个格子),最多能显示2^32个格子,也就是4 * 2^30 = 4G。

    在编写程序的过程中,并不能直接访问物理内存地址。系统设计了虚拟地址(逻辑地址)来给每个进程分配地址空间。


    image.png

    同样的,虚拟地址寻址空间也是4G。只是被分为了两部分:内核地址空间和用户地址空间。其中内核地址空间占用1G,用户地址空间占用3G。
    普通的应用程序只能访问3G的用户空间,内核、驱动等运行在内核地址空间,每个进程内核地址空间是共享的。应用程序想要操作网络、磁盘等硬件资源需要通过内核来访问。

    理论上来说运行在内核空间的代码可以访问整个虚拟地址空间,当然一般不会直接访问,因为用户地址空间的内存有可能是缺页的。通常来说是通过:copy_from_user 和 copy_to_user 函数用来交换内核地址空间与用户地址空间的数据。

    虚拟地址如何映射到物理内存呢?


    image.png

    每个进程分配的虚拟地址空间都是独立的,通过页表映射到物理内存,进而读写数据。进程的虚拟地址空间既然是独立的,那么各个进程之间自然无法直接访问。

    2、Linux IPC 常用方式

    虽然进程间是不能直接访问对方,但是某个进程有需要其它进程的协助,比如提供一些数据,那么该怎么实现进程间通信呢?有哪些常用的方式呢?
    从上面可以知道,要想实现IPC,大致有两种思路:

    1、共享物理内存
    2、通过内核中转

    循着这思路,来看看常用的Linux IPC方式。

    共享物理内存

    共享内存
    属于共享物理内存方式:多个进程共享同一段物理内存,当某个进程改变内存内容时,其它进程都能够知道。此种方式无需拷贝内容,但是需要信号量进行进程间同步。

    image.png
    如图,进程A向进程B发送一段内容:"say hello",可以看出由于共享了内存,因此双方都可以直接从里面拿数据。

    通过内核中转

    管道
    消息队列
    套接字(socket)

    同样是进程A向进程B发送一段内容:


    image.png

    先将A发送的内容拷贝到内核,这过程可以理解为存储,再从内核拷贝到B的用户空间,这过程可以理解为转发,因此一次"存储-转发"过程需要两次内容拷贝。

    3、Android Binder 简单认识

    虽然Linux提供了上述(还有其它的如信号量等)的IPC方式,但是由于每种方式都有其缺点,因此Android另起炉灶弄了另一种方式:Binder。
    在此之前,先来了解一下内存映射(mmap)。

    内存映射

    image.png

    上面提到过,"存储-转发"过程需要在用户空间和内核空间之间拷贝数据,还有一种不需要拷贝的方式:内存映射。
    如上图,进程空间与内核空间共享磁盘上的一个映射文件,当进程空间往映射文件写入数据后(此处不是真正的I/O,而是内存读写),相当与写入了内核空间,反之亦然。

    Binder 通信方式

    image.png

    进程A给进程B发送一段信息,流程如下:

    1、进程A通过系统调用拷贝内容到内核空间。
    2、由于内核空间与进程B做了内存映射,因此进程B能够知道内核空间的信息。

    从上可知,通过Binder,进程A给进程B发送信息只进行了一次数据拷贝。
    对比其它IPC方式可知:


    image.png

    另外,传统的IPC方式只能由使用者填入UID/PID,容易被外界仿造、篡改。而Binder内置为发送者添加UID/PID,更安全。

    4、Android Binder 使用场合

    似乎平时很少使用Binder呢?其实不然,我们不知不觉中已经用了它。
    上图展示了Binder使用C/S模式,也就是S(Server)端提供服务入口,C(Client)调用服务提供的接口,进而两者可以进行通信。
    先来看看一段手机马达震动的代码:

            Vibrator vibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
            vibrator.vibrate(1000);
    

    调用了Context里的方法:getSystemService,指定获取名为:VIBRATOR_SERVICE 的服务,拿到服务后调用 vibrate(xx)即可实现手机震动。
    每个App都能通过访问这段代码来实现手机震动,可想而知拿到的"震动服务"一定是某个地方统一提供的。
    我们知道,Android系统启动后会开启名为:system_server的进程,顾名思义:系统服务,提供给所有App使用的公共服务进程。
    "震动服务"就是跑在该进程里的。
    当调用getSystemService(xx)获取"震动服务时",相当于调用者(App进程)与system_server(服务提供进程)进行了一次IPC过程(实际比较复杂,简单说是:通过ServiceManager获取Binder,该Binder连接system_server,ServiceManager跑在另外的进程里)。
    App进程--->Client
    system_server--->Server
    类似的调用了getSystemService(xx)都是进程间通信。

    你也许会说,我不调用上面的方法就不进行进程间通信了?


    image.png

    举个例子:客户端进程里有行为:Activity A跳转到ActivityB,这个过程是:

    客户端进程先请求ActivityManagerService(AMS)[AMS运行在system_server进程],此时已经通过Binder进行了一次IPC操作。
    AMS准备好之后告诉客户端进程创建Activity B对象,又是一次IPC操作。
    注:中途还有其它IPC过程

    同理四大组件Service、ContentProvider、BroadcastReceiver都离不开Binder。
    Binder一直存在,默默地充当着进程间通信的桥梁,只是系统封装好了上层很少去主动调用它。
    既然Binder如此强悍又无处不在,在下篇文章中将分析如何使用它。
    本文基于Android 10.0。

    您若喜欢,请点赞、关注,您的鼓励是我前进的动力

    持续更新中,和我一起步步为营学习Android

    1、Android各种Context的前世今生
    2、Android DecorView 必知必会
    3、Window/WindowManager 不可不知之事
    4、View Measure/Layout/Draw 真明白了
    5、Android事件分发全套服务
    6、Android invalidate/postInvalidate/requestLayout 彻底厘清
    7、Android Window 如何确定大小/onMeasure()多次执行原因
    8、Android事件驱动Handler-Message-Looper解析
    9、Android 键盘一招搞定
    10、Android 各种坐标彻底明了
    11、Android Activity/Window/View 的background
    12、Android Activity创建到View的显示过
    13、Android IPC 系列
    14、Android 存储系列
    15、Java 并发系列不再疑惑
    16、Java 线程池系列

    相关文章

      网友评论

        本文标题:Android IPC 之Binder基础

        本文链接:https://www.haomeiwen.com/subject/csultrtx.html