1,Binder介绍
在Android中,activity,service等组件都需要和AMS(System_server)进行通信,这种跨进程的通信都是Binder完成的
机制:Binder是一种跨进程通信机制
驱动: Binder是一个虚拟的物理设备驱动
应用:Binder是一个能够发起通信的java类
Framework/Native:Binder连接了Client、Server、ServerManager和Binder设备驱动,形成了一套C/S的通信框架
程序的多进程:虚拟机分配给我们应用运行的内存是有限制的,LMK(Low Memory Killer 低内存杀死机制)会优先回收系统资源占用多的进程
突破内存限制,如图库占用内存较大
功能稳定性:独立的进程保证长连接的稳定性
规避系统内存泄漏:独立的webview阻隔内存泄漏导致的问题
隔离分险:对于不稳定的功能放入独立的进程,避免导致主进程奔溃
2,Binder原理
内存被系统划分为两块,用户空间和内核空间,用户空间就是用户程序运行的地方,内核空间是内核代码运行的地方,为了安全,他们是隔离的,即使用户程序崩溃,内核空间也不受影响
系统调用就是调用linux系统提供的API,只能由系统发起调用:copy_from_user和copy_to_user
IPC中的Socket有两种Internet Socket和Unix domain Socket
传统的跨进程通信需要两次数据copy
共享内存:数据发送方、数据接收方和内核地址空间有一块内存共享区域,所以无需copy
Binder通信
传统IO
写文件流程:调用write,告诉内核需要写入的数据的开始地址和长度;内核将数据copy到内核缓存页;由系统调用将数据copy到磁盘,完成写入
MMAP
Linux通过将一个虚拟内存区域和文件描述符关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射(memory mapping)
对文件进行mapp,会在进程的虚拟内存分配地址空间,创建映射关系
在用户空间调用mapp后,会在当前进程的虚拟空间中分配一段区域并使用vm_area_struct(vma)结构记录这个区域;通过文件描述符链接到内核中的文件结构体,每个文件结构体维护着打开文件的相关信息;通过文件结构体file* 定位到文件,建立页表,将文件对应的物理地址和vma映射关联;进程的读或写操作访问虚拟地址空间这一段映射地址,但是目前只建立了地址映射,真正的磁盘数据还没有copy到内存中,因此引发缺页异常,触发将文件copy到vma(虚拟内存)关联的物理内存。
驱动binder_mmap:通过用户空间的虚拟内存大小-分配一块内核的虚拟空间;分配了一块物理内存4K(刚开始没有通信时只分配了4K,为了避免内存的浪费,等正真进行binder通信时,需要多少内存,分配多少);把这块物理内存分别映射到用户空间的虚拟内存和内核空间的虚拟内存
ServiceManager的注册
1,打开驱动,内存映射(设置大小为128k)
2,设置Sm为大管家--sm的作用时为了管理系统服务
1,创建binder\_node结构体对象
2,proc--binder-node
3,创建work和todo ---》类似于MessageQueue
3,BC_ENTER_LOOPER命令
1,写入状态loop
2,去读数据binder_thread_read: ret = wait_event_freezable_exclusive(proc->wait,
binder_has_proc_work(proc,thread)),进入等待
获取SM的情况
1,注册服务到SM
2,通过sm去获取服务---> Java
也是服务端
1,ProcessState::self->getContextObject(NULL)
ProcessState
1,打开驱动:binder
2,设置线程最大数目15个
3,mmap--> 设置共享内存大小1M-8K(同步,异步除于2)普通服务的大小
getContextObject
1,创建一个BPBinder ---客户端对象
2,服务端对象是BBinder
2,interface--cast(native层)
1, BPServiceManager(new BPBinder)
2, remote.transact--> 远程调用
3, remote == BPBinder
3,Java层
1,new ServiceManagerProxy(New BinderProxy)
2, mRemote == BinderProxy
3, BinderProxy.mObject == BPBinder
4, mRemote.transact == BPBinder.transact
服务的注册获取,线程池管理
从Java-- AMS
如何注册到SM中
getIServiceManager().addService(name, service, false)
getIServiceManager
ServiceManagerNative.asInterface(BinderInternal.getContextObject())
BinderInternal.getContextObject ---> 返回BinderProxy对象
ProcessState::self() --> getContextObject: 创建一个BPBinder
javaObjectForIBinder---BinderProxy和BpBinder互相绑定
ServiceManagerNative.asInterface
返回ServiceManagerProxy
addService
Binder使用过程
1.server注册过程
1.server传入一个flat_binder_object给内核态。内核根据这个flat_binder_object创建binder_node节点,为每个进程服务,内部有个binder_proc.proc = server进程
2.serviceManager在内核态创建binder_ref引用这个binder_node,内部有一项desc = 1,2,3..,在用户态会创建一个服务链表{name ="server name",handle = "server handle"}
2.client获取服务过程
3.client向sm查询服务,传递name
4.sm返回handle给驱动程序
5.驱动程序在sm的binder_ref_desc红黑树中根据handle找到binder_ref,再根据binder_ref.node找到 binder_node,最后给client创建新的binder_ref指向这个binder_node,他的desc从1开始binder_ref{desc=1,node = binder_node},驱动返回desc给client,即handle总结:sm中的handle顺序是根据服务注册顺序显示,返回给client中的handle是根据服务获取的顺序显示的
3.client使用handle过程
6.:驱动里面根据handle找到找到binder_ref,根据binder_ref找到binder_node,根据binder_node找到进程server
AIDL
3,BindService的流程
1,客户端进程与ServiceManager通信获得AMS的IBinder
2,客户端通过AMS的IBinder与AMS通信,请求bindService
3,AMS与服务进程通信执行Service的onBind
4,服务端进程与ServiceManager通信获得AMS的IBinder
5,服务端的进程通过AMS的IBinder与AMS通信,发布自己的IBinder给AMS
6,AMS与客户端通信,转发服务端的IBinder(代理的IBinderProxy)
4,Binder传递数据的大小
在processState.cpp
define BINDER_VM_SIZE((1 * 1024 * 1024)- sysconf(_SC_PAGE_SIZE))
上面大小就是1M-8k
bindProxy.transact(Stub.TRANSACTION_setData, _data,_reply, IBINDER_FLAG_ONEWAY)
IBINDER_FLAG_ONEWAY是传递数据的类型:同步是0,异步是1
异步的时候传递的数据大小是(1M-8K)/2
Intent的数据传输