搞懂Android内Binder的前因后果

瞻仰了前辈们的研究成果, 并掺入了自己的理解, 如有不对, 敬请批评.


为什么Android要使用Binder

Binder 作为一种 IPC 机制, 在 Linux 内有很多的前辈, 为什么 google 会创建这么一种新的方式呢?

Linux 现有 IPC 方式有这几类:

  1. 管道:在创建时分配一个page大小的内存,缓存区大小比较有限;
  2. 消息队列:信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信;
  3. 共享内存:无须复制,共享缓冲区直接付附加到进程虚拟地址空间,速度快;但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决;
  4. 套接字:作为更通用的接口,传输效率低,主要用于不通机器或跨网络的通信;
  5. 信号量:常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
  6. 信号: 不适用于信息交换,更适用于进程中断控制,比如非法内存访问,杀死某个进程等;

与以上方式相比较, Binder 有以下特点:

  1. 性能较好: 数据拷贝 Binder 只需要一次, 管道/消息队列/socket 都需要两次, Binder 仅次于共享内存(一次都不需要);
  2. 稳定性较好: 基于C/S架构的Binder在逻辑上更加解耦, 架构清晰, 而共享内存容易出现各种并发同步死锁问题;
  3. 安全性好: Android每个App都有自己的UID, 传统的 IPC 机制的接收方无法拿到发送方可靠的UID, 而 Binder 的 Server 端可以通过 Android 给每个 App 暴露出的 Client 端获取到, 从而对不同UID的App进行权限判断等安全性控制;
  4. 语言层面: Linux基于C, Android基于java, Binder机制更符合面向对象的环境;
  5. 协议: Linux 受开源代码许可协议GPL的保护, 如果上层应用调用到 Linux Kernel, 就必须也遵循GPL协议; Android利用Binder隔离了Linux Kernel层, 把GPL控制在内核空间, 而用户空间采用了允许不反馈源码的Apache-2.0协议, 并在中间采用BSD授权, 有利于Google实现开源和商业化的共存

综上所述, Binder是Android系统中IPC的最好方式.


Binder 概述##

Binder是android内独有的跨进程通信方式, 它在native层有一套完整的C/S架构, framework层也通过jni技术实现了一套镜像功能的Binder C/S架构, framework层的binder功能最终都交给native的binder来完成. 引用一张Gityuan大神的Binder架构图:


  • 对于Android Driver层: Binder可以理解为一种虚拟的物理设备, 它的设备驱动是/dev/binder, 连接了Video,Camera等设备;
  • 对于Android Native层: Binder是创建Service Manager/BpBinder/BBinder模型、搭建与binder驱动的桥梁;
  • 对于Android Framework层: Binder是各种Manager(ActivityManager, WindowManager等)和对于ManagerService的桥梁;
  • 对于Android App层: Binder是客户端和服务端通信的桥梁, 服务端包括统一进程下的和需要使用AIDL的不同进程下的服务. bindService的时候, 服务端会返回一个包含服务端方法及数据的Binder对象, 通过这个Binder对象, 客户端就能与之通信了.

Binder如何工作

Binder的数据传输 就是发送端把binder_transaction节点,插入到目标进程或其子线程的todo队列中,等目标进程或线程不断循环地从todo队列中取出数据并进行相应的操作.

在Binder驱动层,每个接收端进程都有一个todo队列,用于保存发送端进程发送过来的binder请求. 线程在空闲时进入可中断的休眠状态,当自己的todo队列或所属进程的todo队列有新的请求到来时便会唤醒,执行新的请求事务, 执行完毕后再次休眠.

再引入一张图, 并添加了注释



App层的两种服务里的binder使用

App层的Service有同进程下的Service和不同进程的Service两种, 新开进程的Service需要在AndroidManifest.xml里的Service声明中添加 android:process=":remote", 也可以添加服务名称.

同进程下的Service

Client 端

public class FragSocketPresenter extends BasePresenter<IFragSocketView> {
    private PitPatService pitPatService;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            pitPatService = ((PitPatService.ServiceBinder) service).getService();
            pitPatService.setSocketStateListener(socketStateListener);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) { // 此方法只有在service异常时才调用
            pitPatService = null;
        }
    };

    public void socketConnect() {
        if (getView() != null) {
            Intent intent = new Intent(getView().getContext(), PitPatService.class);
            intent.putExtra("IP", getView().getIp());
            // 会触发onCreate()和onBind(),不触发onStartCommand; 多次点击不会多次触发
            getView().getContext().bindService(intent, connection, Context.BIND_AUTO_CREATE);
        }
    }
}

服务端

public class MyService extends Service {
    private String ip = "";

    @Override
    public IBinder onBind(Intent intent) {
        ip = intent.getStringExtra("IP");
        return new ServiceBinder();
    }

    public class ServiceBinder extends Binder {
        public PitPatService getService() {
            return PitPatService.this;
        }
    }
}

基于AIDL的跨进程服务

篇幅有限, 写到另一篇里了 AndroidStudio下使用 AIDL 构建跨进程 Service( 详细代码贴图 ), 填补网上的大多数坑


参考: 源码大神 Gityuan 的各类文章
http://gityuan.com/2015/10/31/binder-prepare/
https://www.zhihu.com/question/39440766/answer/89210950?from=profile_answer_card

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