android机制系列之二 Binder机制

系列目录 https://blog.csdn.net/jzlhll123/article/category/7671581

引用了很多网上的图片,具体链接未能及时保存,致歉。
20180625 再探binder https://blog.csdn.net/jzlhll123/article/details/80806584

  在学习Binder的过程中有很多迷惑和难度。而且app开发很少接触到这个。翻看了无数的帖子,3-4本PDF/书,都是上来就将驱动的binder,然后将c++,再将到java层。诚然这是合理的架构设计顺序。但是对于java开发人员就痛苦了。我习惯的是从用法->原理的理解过程。

  我建议android app开发人员,学习过程按照一层一层往下。在不熟悉下一层的时候没关系,就当它是黑盒,这也是面向对象的思想,抽象后的对象(比如ActivityManagerService,ServiceManager等)我们都可以当它为黑盒。

  根据我踩坑后得到的浅浅经验,建议纯app开发人员如此开始:

第一步,AIDL

  阅读之前请结合自己实现AIDL和AIDL使用和原理,先从AIDL学起的使用,自己生成一个AIDL文件,分析AIDL自动生成的代码。

package com.service;
interface IMyRemote {
    void func(String info);
}

学完以后,大概能理解到android机制系列之一 AIDL实现原理这个层次。

第一步,学到


AIDL
1. 接口IMyRemote继承IInterface,把方法添加了远程异常;
2. 内部类Stub(故意写成MyStub)继承Binder,初始化, asInterface转换接口,和处理回调onTransact();
3. MyProxy实现IMyRemote,将Ibinder封装成具体同名方法transcat()给底层传递数据。
使用层面来讲,只要asInterface()后就是具体的接口可以正常使用了。

Service
  onBinder() return IInterface回去binder对象,在自动代码中会attachInterface()保留该实体对象

Client
  onServiceConnected() 会返回IBinder对象(mRemote#1), Client拿到后,需要asInterface()->queryLocalInterface()转成我们需要的代理对象(不同进程)或实体对象(同进程)

通信过程
  同进程实体方法调用: 同一进程空间,直接调用;
  不同进程代理对象方法调用:
  client将调用方法,参数_data和返回结果_reply序列化,mRemote#1(注意是Ibinder)transact(code, _data, _reply, flag)到黑盒Binder机制里面去,挂起;
service收到黑盒Binder机制回调给Stub的onTransact(code, data, reply, flag) , 将data读取出来执行,如果有返回值就填充reply,然后结束,唤醒client;
client唤醒后,如果有返回值,就将_reply反序列化,拿到结果。

20180622补充说明:
这是由bindService后得到的Ibinder决定的,绑定后,同进程将直接拿到实例对象,同你service保存的对象,调用的方法也就是直接使用func(); 而不同进程,Ibinder实际上BinderProxy, 因此func()分装了JNI transact()动作来传达到server端最终调用onTransact()

第一步,黑盒
Binder.java是怎么运作的?
context.bindService(intent, serviceConnection, flag)怎么个流程?
这个serviceConnection给谁去运作和怎么回调的?
第二步,bindService, onBindonServiceConnected的过程

​ 继续当Binder.java提供的方法为黑盒。暂时我们知道transact, onTransact的用处就够。我们一般bindService会在Activity/service中绑定。我们先看2张类图。

  理解下为何会使用wrapper(装饰/包装)模式,继承父类,又传入父类。查看源码ContextWrapper相当于完全照抄了一遍一些跟应用相关的方法,并可以初始化或者重设mBase。设想如果我们采用继承方式来做会丢失如下2点优势。
  好处有2点,第一,扩展(目前来说没有扩展)但不能修改父类;第二,可以方便的替换掉Impl类,而不用影响ContextWrapper的子类

不懂不要紧,我们来稍微类比下AIDL:

  第一步中自动实现的AIDL的IManager整个大类,就相当于这里的IActivityManager,实现了IInterface;

  ActivityManagerNative相当于我们AIDL的Stub类,内部可以拿到ActivityManagerService实现的接口,实现了OnTract(),外加Proxy代理类;

该类类图:

  所以,ActivityManagerNative.getDefault().xxx(),其实都是跨进程调用(如果它自己则不用)到ActivityManagerService的具体实现。而这里并没有超出我们学习AIDL相关的范畴。因此,暂时不深入研究Binder,我们目前只要知道transact()和onTransact()是谁调用,在哪里用的即可,而且我们已经掌握。

  好了,这个时候,我们已经追到AMS的bindService了:然后学习Android服务之bindService源码分析

​ 里面很多的LoadedApk,ActivityThread,ActivityManagerService,ActivityServices等跳来跳去,一时之间很难理清楚。模模糊糊我们有了一些概念,留着后续继续学习,这里留一个黑盒。因为Activity,Service的启动流程等等都会涉及到这里。参考:https://blog.csdn.net/zhangfei2018/article/details/46518615

第二步,学到

这里写图片描述

  我自己画的这张图, 而且是真的理解了。注意进程的关系,和子类归属关系。虚线是跨进程,实线是父类方法或者成员变量的方法。

ContextImpl相当于Activity/Service的父类(本质上是包装过的);

ActivityManagerNative其实是静态类,我们拿到的静态对象去bindService的时候,其实还是在client进程;

ActivityThread是每一个应用程序都需要通过标准java的main()函数创建出来的, 并且每个Service都有一个ActivityThread的成员变量(即我们常说的主线程);

ActivityManagerService是SystemServer进程里的,他也有一个标记为system的ActivityThread;

所以在这里面涉及到3个进程,client的activity/service bindService的地方, service提供IBinder的地方以及framework的AMS。那么, 可以大致看出ActivityManagerService维护了一个所有应用层服务的表,client启动的时候添加进去;当client通过binder绑定的时候, 从表中找到对应intent的service,将serviceConnection封装进去,返回Ibinder,最后又通过Binder转达到client

回来来看,我们是想了解Binder,但是事实上,Binder的用法在上述流程中并没有太多的变化。所以回头来,再次巩固下java层的Binder知识。

一个接口实现类:实现 IInterface;如 IActivityManager, IServiceManager, 如AIDL文件,如;

一个主类: 继承Binder; 如AIDL的Stub类,如ActivityManagerNative;

一个代理类,一般是主类内部类:实现接口实现类:如AIDL Stub内的Proxy类,如ActivityManagerNative内的ActivityManagerProxy类;

主类方法具体实现:真正的实现方法,如ActivityManagerNative的ActivityManagerService,如AIDL的我们在service中实现的Stub的实例;

主类Binder驱动回调方法onTransact():将Binder调过来的指令调用上述具体实现,并返回;

Proxy类方法抽象实现:将同名方法,使用binder驱动transact()传递指令同步等待结果。

至此,Java层的binder使用和阅读framework java层,在多次折腾下,基本算是懂了个大概。

第二步,留下的黑盒

Binder底层机制;

ActivityManagerService,ActivityThread,Activity启动过程,Service启动过程,Application启动过程…

第三步 Binder C++使用学习

TODO

第四步 其他帖子的学习

只有到了这个阶段,再去看后面引用的几篇文章才有意义!, 否则App开发工程师,上来就是驱动,很吃力。
引用贴说的好,学习顺序。目前我已经达到了3阶段水平了。对于app工程师,基本能够比较轻松的继续研究Activity启动流程,广播机制,ContentProvider机制等framework机制就够了。否则,Binder学1个月也不能完成。
引用灰太狼一句话:我还会回来的

  1. 先学会熟练使用AIDL进行跨进程通信(简单来说就是远程Service)
  2. 看Android文档,Parcel, IBinder, Binder等涉及到跨进程通信的类
  3. 不依赖AIDL工具,手写远程Service完成跨进程通信
  4. 看《Binder设计与实现》
  5. 看老罗的博客或者书(书结构更清晰)
  6. 再看《Binder设计与实现》
  7. 学习Linux系统相关知识;自己看源码。

背景知识:
  1. 进程间是隔离的,进程间,虚拟地址空间,无法共享数据;所以需要IPC,性能上讲,相对较少,一次内存拷贝,其他的一般2次;共享内存不用拷贝,但是很复杂难以使用,也不利于安全;socket适合网络通信或者一些低速的通信;安全上讲,传统linux的IPC相对来说很少涉及UID/PID,一些权限管理不够安全;

  2. Binder驱动,内核模块虚拟成一种硬件设备,操作不同进程的内存;

  3. 在阅读Binder的通信模型的时候,经常会被他们提到Binder驱动,ServiceManager,Server,Client四个角色。

    serviceManager进程向binder驱动申请成为0号管理者;

    其他Server向serviceManager注册;

    Client通过serviceManager获取具体Server的proxy引用对象。

    这里的Server并不是我们平时使用的组件service(https://blog.csdn.net/sinat_26158619/article/details/51184927)。binder提供了实名server和匿名server,framework java层使用了匿名server的技术,实现了组件service,https://blog.csdn.net/zhangyongfeiyong/article/details/51953300,也可以自己去追相关的源码,可以看到bindService的时候,是通过activityManagerService查询到对应的intent的服务,最终拿到的service代理。

    所以理解这里的AIDL服务service和binder server的区别。

    但是,不管怎么样,如果不是同一进程,拿到的代理引用对象,都会通过binder驱动代码完成跨进程通信。


    参考学习引用:

    1. Android深入浅出之Binder机制
    2. Binder设计与实现
    3. Android进程间通信(IPC)机制Binder简要介绍和学习计划系列
    4. http://qiangbo.space/2017-03-15/AndroidAnatomy_Binder_Java/ 3篇


title bindService时序图

client->client: bindService:ContextWrapper
client->client: bindService:ContextImpl
client->client: bindServiceCommon:ContextImpl
client->ActivityManagerNative: bindService:ActivityManagerNative
ActivityManagerNative-->ActivityManagerService: bindService:ActivityManagerService
ActivityManagerService->ActivityManagerService: bindServiceLocked:ActivityServices
ActivityManagerService-->AcitivityThread: scheduleCreateService-->handleCreateService
ActivityManagerService-->AcitivityThread: scheduleBindService-->handleBindService
AcitivityThread->Service:onBind() 
AcitivityThread->Service:onBind() 
AcitivityThread-->ActivityManagerService:publishService()
ActivityManagerService->ActivityManagerService:publishServiceLocked:ActivityServices
ActivityManagerService->ActivityManagerService:doConnect handler:LoadedApk
ActivityManagerService-->client: onServiceConnected()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值