Android Framework -- Binder

Binder通信篇

Binder的通信部分其实很简单,但源码中的业务封装太过复杂使得Binder看起来很复杂。抛开业务封装看下Binder通讯原理。ServiceManager就抛开了Binder的业务封装,直接使用它的通信功能。

首先我们知道,逻辑地址空间有4G,其中3G为用户空间,1G为内核空间;我们的应用进程都在用户空间中且相互隔绝无法直接互相访问。于是乎有了进程间通信的需求。Android基于Linux,Linux提供了很多进程间通信的方案:管道(Pipe)、信号(Signal)、消息队列(Message)、共享内存(Share Memory)、插口(Socket)等。而Android系统有自己独特的Binder进程间通信机制。Android源码中大量的使用Binder进行进程间通信(当然,有些地方也还是会用其他的进程间通信方式的)。Binder有很多优势,其中一个就是性能高,其他进程间通信基本上都需要进行两次的数据拷贝,而Binder只需要一次。
下面看看Binder通信的过程
这里写图片描述

1.每个进程(C端和S端都一样)在于Binder初次接触的时候,Binder都会为其建立一个物理地址映射,该进程在用户空间地址和Binder在内核空间的地址映射到一个物理内存上(如图:进程C和Binder进程K的地址映射到某物理内存上)。这样的映射在第一次接触的时候只会分配一个物理页大小(映射的最小值),后面在传输有效数据的时候会进行扩充,使用完毕立刻释放。
2.C端向S端传输有效数据的时候,C端需要向Binder驱动写入数据,数据包含Binder实体(即S端)的信息、有效数据在用户空间的地址等。Binder拿到数据后,先找到S端的信息,然后通过Binder与C端的映射(如图中的a)读取有效数据,然后拷贝到Binder与S端的映射(如图中的b)(一次数据拷贝);这个时候S端发现有数据之后就会通过映射去读取数据,完成一次进程间通信。

下面看下具体的ServiceManager注册到Binder成为Binder过程解析
init进程在启动各种服务的时候会启动SM服务,附上init.rc的相关部分
这里写图片描述
第一行:以服务的形式启动
第二行:以系统用户system的身份运行
第三行:critical表示SM是系统的关键服务(关键服务一旦退出会立刻重启,4分钟退出次数>4则系统重启)
第四、五行:如果SM重启则zygote、media也得重启
下面看下SM注册成为Binder管理的过程
这里写图片描述
第8行:打开Binder驱动,该动作同时会调用mmap分配一页的物理页来映射SM与Binder
第10行:binder_become_context_manager注册成为Binder的管理者,其实就是把自己的标记设置为0(每个服务在SM中注册都会有一个标记,客户端需要某服务会向SM查询就是查询到这个标记就可以通过Binder访问对方,而SM本身也是一个服务,它的服务标记为0)
第16行:等待客户端的请求

这个过程就是最简单的与Binder交流了。

PS:通常情况下,客户端与Binder交流略过业务逻辑部分最终会调用IPCThreadState来做通信,IPCThreadState负责对Binder的写入与读取,每个线程有且只有一个IPCThreadState。下面业务篇有具体描述

Binder业务篇

Binder对于业务层的封装非常繁杂,而对于应用程序来说接触的比较多的应该就是AIDL。
Binder的业务层从上至下包含诸多对象,Java层Binder、BinderProxy、BinderInternal;Native层BpBinder、BBinder、Bpxxx等等等…其实Java层基本上是Native的一个映射。在Java世界初创之时,会注册一些JNI函数,其中register_android_os_Binder函数会把Java层的Binder进行初始化工作。主要就是通过JNI把Binder、BinderProxy、BinderInternal分别保存在Native层的全局变量gBinderOffsets、gBinderProxyOffsets、gBinderIntenalOffsets中,并将三个类的Native初始化好。
这里写图片描述
接下来我们看一个小例子:AMS将自己注册到SM中
以及AMS如何响应请求
这里写图片描述
上图,蓝色部分表示Java层,黑色部分表示Native层。左侧是AMS将自身注册到SM,SM上面介绍过,直接读取Binder驱动数据,上图没画出来。右侧则是客户端向AMS发起请求后从Binder到S
端的过程,其他服务也差不多。另外,还有一些服务
直接在Native层发起请求或处理请求与Binder交互的。其过程其实类似,这边做下简单笔记,可跳过。

//MediaServer的注册
//①这里会做两件事:打开Binder驱动;mmap 分配一个物理页
sp<ProcessState> proce(self())
//②defaultServiceManager
sp<IServiceManager> sm = defaultServiceManager()
//③instantiate
instantiate()

defaultServiceManager做的事就是获得一个与SM通信的Bp代理
这里写图片描述
instantiate则利用sm进行注册
这里写图片描述

AIDL: Android:学习AIDL,这一篇文章就够了
总结来说

private ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(getLocalClassName(), "service connected");
            mProxy = Proxy.getRemoteProxy(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(getLocalClassName(), "service disconnected");
            mBound = false;
        }
    };

然后

Intent intent = new Intent();
        intent.setAction("com.lypeer.binder");
        intent.setPackage("com.lypeer.ipcserver");
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);

这样一来客户端就拿到服务端的“标记”了,即IBinder service。
最后客户端调用

mRemote.transact(CHAT, data, reply, 0);

这里的mRemote就是IBinder了,实现类就在Binder.java中的BinderProxy,调用transact()向Binder写入数据,这部分前面有了。
后面Service端就更简单了,Stub继承Java层Binder把业务逻辑实现了,返回数据给客户端。至于Binder驱动到Java层Binder部分上面也介绍了

public abstract class Stub extends Binder {

    private static final int CHAT = 0;

    public abstract String chat(String message);

    @Override
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            case CHAT:
                String dataString = "";
                String replyString = "";
                if(0 != data.readInt()){
                    dataString = data.readString();
                }
                replyString = chat(dataString);
                reply.writeNoException();
                if(TextUtils.isEmpty(replyString)){
                    reply.writeInt(0);
                }else {
                    reply.writeInt(1);
                    reply.writeString(replyString);
                }
                return true;
            default:
                return super.onTransact(code, data, reply, flags);
        }
    }
}

这是AIDL实现自动生成的代码,chat()部分由实际的业务类去实现。

最后附两图
这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/xiaoru5127/article/details/73555936