android开发-Binder

两个进程 分配的是

AIDL中产生的Binder 文件中 有两个类

一个是Stub、一个是Proxy

进程A想访问进程B   需要访问 进行B在binder中的一个引用  这个引用就存着进程B 的AIDL的描述

Binder驱动要放着很多Binder引用,因为不止一个服务要进行进程间通信,准定有很多的服务要进行进程间通信


定义的AIDL文件,系统会自动帮我们生成一个同名的java文件
这个java文件 是一个继承自IInterface接口,所有可以再Binder中传输的接口都需要继承自IInterface这个接口

这个接口的机构是这样的


1、实现了本接口的Stub而且继承自Binder的抽象类,,但是实质上还是没有实现,需要我们具体事例去实现抽象方法
2、声明的接口方法,就是我们AIDL中声明的方法
3、还声明了几个整型的id,分辨用于标识这几个定义的方法,用于标识在transact过程中客户端所请求的到底是哪个方法


而这个Stub中还有一个内部类Proxy,还有asInterface、asBinder、onTransact
Proxy具体的实现了我们声明的接口的方法
当客户端与服务端在同一个进程中的时候,方法不会走跨进程的transact过程,如果客户端与服务器端不在同一进程时候,要走tansact过程。
这个过程是有Stub的内部代理类Proxy来完成的


asInterface(android.os,IBinder obj);
用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象,这种转换是区分进程的,
如果客户端与服务端在同一进程 那么此方法返回的就是服务端的Stub对象本身,否则返回的是系统封装后的Proxy对象

onTransact
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
这个方法运行在服务端的Binder线程池,当客户端发起跨进程的请求的时候,远程请求会通过系统底层封装后交由此方法来处理。
服务端通过code来确定客户端请求的目标方法是什么
接着从data中获取目标方法所需要的参数(如果目标方法有参数的话)
当目标执行完毕之后,就像reply中写入返回值
如果方法返回值返回false 那么客户端的请求会失败,因此我们可以用这个特性做权限验证


Proxy#getBookList
这份方法运行在客户端 但客户端远程调用此方法的时候,它的内部实现是这样的
创建发方法所需要的输入类型Parcel对象_data,输出类型Parcel对象_reply和返回值对象List,然后把该方法的参数信息写入_data中(如果有参数的话);
接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起;
然后服务端的onTransact犯法会被调用,直到RPC过程返回后,当前线程继续执行,并从reply中获取RPC过程的返回结果;
最后返回_reply中的数据


Proxy#addBook
这个方法的执行过程与getBookList方法是一样的,只是addBook没有返回值 锁踏不需要从_reply中取出返回值

需要注意的是,客户端发起请求的时候,由于当前的线程会被挂起,直到服务端返回数据,所以是一个很耗时的方法,那么就不能再UI线程中发起远程请求
由于服务端的Binder方法运行在Binder线程池中,所以Binder方法不管是否耗时都应采用同步的方式去实现,因为他已经在一个线程中了




进程间通信 相当于一个CS结构
Binder属于中间的中介者


如果A想访问B进程,那么需要A访问底层binder
底层Binder再去访问B的Stub服务端
获取完结果 再去访问Binder,Binder再去访问A的Stub服务


stub是服务端 接受访问,提供服务的
proxy用来主动 访问底层Binder


DESCRIPTOR是用来标识你的aidl的标识符 类似于一个id
在Stub的构造函数中调用attachInterface 会将本服务端的aidl与DESCRIPTOR绑定在一


起,然后将IBinder与DESCRIPTOR存放到Binder的驱动中


调用 asInterface的时候 获取判断queryLocalInterface,而queryLocalInterface的


源码是
 public IInterface queryLocalInterface(String descriptor) {
        if (mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }
如果我们本地已经初始化了IBinder服务,并且descriptor 那么就用本地的Service
而不会使用binder底层中的Ibinder,也就不用跨进程了




当我们的Activity 启动bindService的时候 
需要跟ActivityManagerService进行通信
会调用ContextImpl类里面的bindService
然后会走到ActivityManagerNative
这里他也是一个AIDL生成的java接口
ActivityManagerNative.getDefault
这个函数里面 调用了
IBinder b=ServiceManager.getService("activity");
IActivityManager am=asInterface(b);
这样就获取了系统进程ActivityManagerService的 IBinder的引用了, 这样就可以与


之进行进程间通信了
这样就连接上了IActivityManager 的实现服务端,也就是ActivityManagerService,
调用了ActivityManagerService中的bindService()
这个方法里 有一个ActivityServcie  mService,这个类是专门去管理Service
mService.bindServiceLocked->requestServiceBindingLocked
r.app.thread.scheduleBindService();
启动一个app的入口函数 是ActivityThread的main方法
scheduleBindService是一ApplicationThread接口中的方法 而实现的类就是


ActivityThread,所以r.app.thread 就是ActivityThread类型的
而ActivityThread中的scheduleBindService->BIND_SERVICE->handleBindService
>handleBindService的时候会拿到我们创建的Service,那么Service创建的过程是:
创建Service的过程
scheduleCreateService->CREATE_SERVICE->handleCreateService
在>handleCreateService里面 是通过 反射的方式创建的Service对象
然后在service.onCreate()
然后把创建的Service对象 放在了mServices.put(data.token,service);


而在handleBindService的时候 就会用到mServices保存的Service对象了
如果Service 不为空,并且data.rebind为false 那么会调用Service中的IBinder 


binder=onBind(data.intent)方法  返回一个IBinder对象
这个binder就是我们创建的binder  
而这个binder就是为了跟底层Binder通信的服务端的binder
ActivityManagerNative.getDefuault().publishService


(data.token,data.intent,binder)
这里是通知客户端 已经连接


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值