Giter Club home page Giter Club logo

test's People

Contributors

xiewenfeng avatar

Stargazers

 avatar

Watchers

 avatar

test's Issues

Binder机制

1. 为什么Android要采用Binder来进行跨进程通信?

传统的Linux进么IPC通信机制有:pipe/signal/trace/管道/共享内存/消息队列/Socket,Android中使用Binder通信的原因有以下几点:
(1) C/S通信
采用C/S通信模式的,只有Socket支持C/S,但socket是一个通用接口,传输效率低;
(2) 传输效率高
相比于管理和消息队列等采用存储转发方式,需要拷贝2次数据,效率低;而共享内存传输过程中不需要数据拷贝,但控制机制复杂,想在IPC通信时,获取对方进程pid,需要多种机制协同操作。Binder机制只需要拷贝数据一次,效率高;
(3) 安全性高
Linux的IPC机制,没有采取一些安全措施,得依赖上层协议来进行安全控制,而Binder机制在内核空间添加身份标识UID/PID,安全性高;且Binder可以建立私有通道。
匿名Binder就是建立私有点对点通道,在Binder通信中,不需注册给SM广而告之,Server可以通过已建立的实体Binder连接将创建的Binder实体传给Client。

2. Binder通信机制

Binder框架定义了四个角色:Client, Server, ServiceManager, Binder驱动,其中Client, Server, ServiceManager位于用户空间,Binder驱动在内核空间,ServiceManager作为守户进程,处理所有客户端请求,管理所有服务项。
具体通信过程如下:
(1)Server在自己进程中创建服务的Binder实体,并将Binder实体和名字打包传给Binder驱动;
(2)Binder驱动为服务建立位于内核空间的Binder实体节点及Binder引用;
(3)Binder驱动将Binder名字及Binder引用打包传给ServiceManager,通知SM注册名XX的服务;
(4)SM收到数据包后,取出服务名字及Binder引用,填入查找表;
(5)当Client向SM发起服务查询请求,SM在查找表中找到该Service的Binder引用,并把Binder引用传给Client;
(6)Client通过Binder引用调用Server端函数。
这四种角色的作用:

  1. Binder驱动:负责进程间Binder通信的建立,Binder在进程中的传递,Binder引用计数管理,数据包在进程间的传递和交互等一系列底层支持;
  2. ServiceManager:将字符形式的Binder转化成Client中对该Binder的引用,使Client能通过Binder名字获取对Server中Binder实体的引用。
  3. Client向ServiceManager发起服务查询请求,获取实名Binder的引用,Client就可通过名字获得该Binder的引用。
  4. Server创建Binder实体,向ServiceManager注册Binder的实体及其名字后。

3. 怎么理解Binder实体和Binder引用?

Binder对象是一个可以跨进程引用的对象,Binder实体位于Server对象中,该对象提供一套方法用以实现对服务的请求,Binder引用位于各个Client进程中。
Server提供的实现某个特定服务的访问接入点;
Client通过这个接入点向Server发送请求来使用服务。

4. Server和Client端如何获取访问接入点(远程接口)?

4.1 ServiceManager和Server\Client都是进程,Servcer向SM注册Binder需要进程间通信,即实现进程间通信又要用到进程间通信,这在Android中是怎么解决的?

ServiceManager使用binder_becom_context_manager(bs)命令通知Binder驱动程序自己是守户进程,它是所有进程的Server端,其他进程都作为Client端,若想获得ServiceManager远程接口,不必通过进程间通信机制获得,ServiceManger远程接口是一个特殊的Binder引用,它的引用名柄一定是0.该Binder实体没有名字也不需要注册,所有client都认为handle值为0的引用是专门与SM通信用的。

4.2 C/S获得ServiceManager远程接口对象

获取ServiceManager远程接口对象就是获取ServiceManagerProxy对象,它是一个IServiceManager接口,它是通过调用Framework层的ServiceManager.getIServiceManager()方法获得,而ServiceManager.getIServiceManager是通过调用Native层的ServiceManagerNative.asInterface(new BinderProxy())获得的,asInterface()方法获取到的是一个BpProxy对象,通过IPCThreadState来调用Binder驱动。而new BinderProxy()则是将Native层的Bp proxy对象转化成Java中的BinderProxy对象。
ServiceManagerProxy它本质上是一个BpServiceManager,它包含一个名柄为0的Binder引用。

4.3 Server获取远程接口过程

Server注册服务是通过调用ServiceManager.addService("xxx", new xxxService())
(1) new xxxService()调用的是xxxService()的构造函数,xxxService继承自IxxxService.Stub类,而Stub类继承自Binder类,它的构造函数用于创建Native层的JavaBBinderHolder对象,并把对象保存在Binder的mObject中。
(2) addService()函数主要有三步:
a) 获得Parcel类型的data和reply;
b) 调用data.writeStrongBinder(service)
c) 调用mRemote.transact(ADD_SERVICE_TRANSACT, data, reply, 0)
server通过调用SM的addService函数,传递一个字符串和实际Binder对象在自己虚拟空间的地址到Binder驱动,Binder驱动记录下该地址,在SM申请的物理内存中分配一个虚拟地址并连同字符串一起传给SM,Binder驱动会记录下两个地址间对应关系。

4.4 Client获取远程接口过程

IServiceManager.getService("xxx")
IServiceManager是一个IxxxService.Stub.asInterface(ServiceManager.getService("xxx))对象,它查询是否属于本地进程,属于则直接返回BbBinder,不属于则返回android.os.IxxxService.Stub.Proxy()对象;
ServiceManager.getService("xxx)则是调用ServiceManagerProxy.getService("xxx"),它会调用mRemote.transact()方法;
client通过调用SM的getService函数,将一个字符串传给SM,SM将相应的虚拟地址传给Binder驱动,Binder驱动查询出实际对象地址,在client申请的物理内存中分配一个虚拟地址传给Binder,这样client就获得Binder的引用。

5. Client端调用Server端实现

(1)通过IxxxService.Stub.asInterface通过服务端的访问通道获取BinderProxy引用对象

private ServiceConnection mService = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mCalcAidl = IxxxService.Stub.asInterface(service);
        }
};
//asInterface函数查询是否属于本地进程,是则返回BBinder对象本身,不是,则返回Proxy对象
public static IxxxService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof IxxxService))) {
                return ((IxxxService) iin);
            }
            return new IxxxService.Stub.Proxy(obj);
        }

(2)根据获取到的IxxxService访问服务端方法,它的调用顺序如下:
a) 客户端调用的方法会进入IxxxService.Stub.Proxy类中的对应方法,先将数据打包成Parcel对象,调用mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0)方法,mRemote是BpBinder对象;
b) Binder的onTransact方法,它的子类的IxxxService.Stub类重写了onTransact方法,所以会进入子类IxxxService.Stub类的onTransact方法,根据code码标识当前调用的方法,读入数据;
c) onTransact根据不同的方法调用接口实现类方法,即我们写好的服务类的方法;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.