@TryLoveCatch
2023-04-18T16:15:18.000000Z
字数 11184
阅读 644
Android知识体系
从机制来说,Binder是Android系统中进程间通讯(IPC)的一种方式,也是Android系统中最重要的特性之一。
从代码实现来说,Binder和BinderProxy是一个实现了IBinder接口的类。
Android是在Linux内核的基础上设计的。而在Linux中,已经拥有"管道、消息队列、共享内存、Socket等等"众多的IPC通信手段;但是,Android为什么单单选择了Binder,而不是其它的IPC机制呢?
首先,我们知道两个进程之前因为进程隔离的原因,是不能直接通信的,需要通过系统调用(copy_from_user, copy_to_user):
我们来看下传统的IPC是如何通信的:
可看出来,是经过了两次的数据copy。而Binder只有一次copy,如下图:
Binder机制只需1次,主要是使用到了内存映射,也就是mmap():
1. 首先 Binder 驱动在内核空间创建一个数据接收缓存区;
2. 接着在内核空间开辟一块内核缓存区,用于接手发送进程发送的数据。
3. 实现内存映射,内核缓存区和接收进程的用户空间地址都映射到同一个接收缓存区。
4. 发送进程通过系统调用 copy_from_user() 将数据 copy 到内核中的内核缓存区,这是唯一的一次数据copy。
5. 由于内核缓存区和接收进程的用户空间存在内存映射,因此也就相当于把数据发送到了接收进程的用户空间,这样就实现了一次跨进程通信。
service_manager的作用很简单就是提供了查询服务和注册服务的功能。
Server要注册服务,Client要获取服务,都需要通过service_manager,但是如何访问呢?
Binder机制为service_manager预留了一个特殊的位置。这个位置是预先定好的,任何想要使用service_manager的进程只要通过这个特定的位置就可以访问到Sservice_manager了
注意:在Binder驱动中,service_manager的引用其实是一个全局变量,通过handle = 0这个位置来访问service_manager。
Client要和Server通信,它就是通过保存一个Server对象的Binder引用,再通过该Binder引用在内核中找到对应的Binder实体,进而找到Server对象,然后将通信内容发送给Server对象。
进程1的BpBinder在发起跨进程调用时,向binder驱动传入了自己记录的句柄值,binder驱动就会在”进程1对应的binder_proc结构”的引用树中查找和句柄值相符的binder_ref节点,一旦找到binder_ref节点,就可以通过该节点的node域找到对应的binder_node节点,这个目标binder_node当然是从属于进程2的binder_proc啦,不过不要紧,因为binder_ref和binder_node都处于binder驱动的地址空间中,所以是可以用指针直接指向的。目标binder_node节点的cookie域,记录的其实是进程2中BBinder的地址,binder驱动只需把这个值反映给应用层,应用层就可以直接拿到BBinder了。这就是Binder完成精确打击的大体过程。
当Client需要向Server发送请求时,它会调用远程服务接口;远程服务能够获取到BpBinder对象,而BpBinder则通过IPCThreadState和Binder驱动进行通信。由于BpBinder中保存了Server在Binder驱动中的Binder引用;因此,IPCThreadState和Binder驱动通信时,是知道该请求是需要传给哪个Server的。Binder驱动通过Binder引用找到对应的Binder实体,然后将Binder实体中保存的"Server对应的本地服务对象的地址"返回给用户空间。当IPC收到Binder驱动反馈的内容之后,它从内容中找到"Server对应的本地服务对象",然后调用该对象的onTransact()。不同的本地服务都可以实现自己的onTransact();这样,不同的服务就可以按照自己的需求来处理请求
假设IDE生成的接口的java格式的名字位IMyAidlInterface.java,继承了android.os.IInterface(唯一方法:IBinder asBinder())。
Stub是IMyAidlInterface的静态内部类,Proxy是Stub的静态内部类。
- | Stub | Proxy |
---|---|---|
实现接口 | IMyAidlInterface | IMyAidlInterface |
继承类 | android.os.Binder | 无 |
构造函数 | 无参,会以(key,value)方式绑定描述信息和Stub | 需要传入android.os.IBinder对象,记为remote |
抽象类 | 是,没有实现IMyAidlInterface的方法 | 否,IMyAidlInterface的方法都调用remote#transact() |
asBinder()返回值 | 返回this | 返回remote |
重要方法 | 1、IMyAidlInterface asInterface(android.os.IBinder obj) 2、boolean onTransact() |
无 |
作用 | Server端使用 | Client主要使用的是这个类 |
特别的,Stub里面有一个重要的静态方法:IMyAidlInterface asInterface(android.os.IBinder obj)
假设接口为IMyAidlInterface,提供了一个String getName(),那么大体的步骤如下:
理解AIDL之后,再去看系统源码,就不会被各种乱七八糟的名字给绕晕了:
当然,系统比我们这个会复杂很多,它还会涉及到Binder的传递,Client会把Binder对象传递给Server,这样Server可以主动调用Client的能力,例如IApplicationThread,就是通过IActivityManager#attachApplication(),由App进程传递给system_server进程的。
平常,我们Binder的获取,是客户端调用bindService(),服务器onBinder返回的一个IBinder。
通过IPC传递Binder对象也可以获取到BinderProxy对象,这里涉及到几个方法:
1、APP进程
1.1、IInterface#asBinder()
1.2、Parcel#writeStrongBinder()
2、system_server进程
2.1、Parcel#readStrongBinder()
2.2、Stub#asInterface()
// ActivityManagerProxy
public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app.asBinder());
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
// ActivityManagerNative
case ATTACH_APPLICATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IApplicationThread app = ApplicationThreadNative.asInterface(data.readStrongBinder());
if (app != null) {
attachApplication(app);
}
reply.writeNoException();
return true;
}
这个是从service_manager进程里面获取系统的一些服务,一般我们自己提供的能力,不能通过这个来获取。
只有在获取系统的一些能力的时候,才会这样使用。
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
通过IBinder b = ServiceManager.getService("activity");
这种方式获取,也是IPC通信,是App进程去service_manager进程查询服务,因为系统开机的时候,system_server进程已经去service_manager进程注册了一些服务,查询到之后会返回BinderProxy对象给App进程,然后调用asInterface得到ActivityManagerProxy对象。
自己写的server不需要注册。
因为自己注册的Server,基本上都是通过上面提的到“获取BinderProxy对象的方式”的方法一和方法二来进行获取BinderProxy对象,不需要提前注册到SeviceManager。
每个应用程序都是运行在各自的Dalvik虚拟机中,应用程序每次运行都要重新初始化和启动虚拟机,这个过程会耗费很长时间。Zygote会把已经运行的虚拟机的代码和内存信息共享,起到一个预加载资源和类的作用,从而缩短启动时间。
原因是因为fork只能拷贝当前线程,不支持多线程的fork。
如果zygote使用binder的多线程模型与system_server进程进行通讯的话,fork()出的App进程的binder通讯没法用,那这样的就失去了fork的作用了。
https://blog.csdn.net/qq_39037047/article/details/88066589
https://www.zhihu.com/question/312480380
https://cloud.tencent.com/developer/article/1639738
普通的由Zygote孵化而来的用户进程,所映射的 Binder 内存大小是不到1M的,准确说是1M-8K。
Binder 的线程池数量默认是15个,由15个线程共享这 1MB-8KB 的内存空间,所以实际传输大小并没有那么大
Binder 通信,归根结底是位于不同进程中的线程之间的通信.假如进程 S 是 Server 端,提供 Binder 实体,线程 T1 从 Client 进程 C 中通过 Binder 的引用向进程 S 发送请求。S 为了处理这个请求需要启动线程 T2,而此时线程 T1 处于接收返回数据的等待状态。T2 处理完请求就会将处理结果返回给 T1,T1 被唤醒得到处理结果.这个是 Binder 通信的基本过程。
————————————————
版权声明:本文为CSDN博主「Big Skipper」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/liuwg1226/article/details/108570553
xxx
首先要管理线程池就要知道池子有多大,应用程序通过 BINDER_SET_MAX_THREADS 告诉驱动,最多可以创建几个线程。以后每个线程在创建,进入主循环,退出主循环时,都要分别使用 BC_REGISTER_LOOP,BC_ENTER_LOOP,BC_EXIT_LOOP 告知驱动,以便驱动标记当前线程池中各个线程的状态。
- 每当驱动接收完数据包,并且把数据包返回给读 Binder 线程的用户空间时,都要检查一下,线程池中是不是已经没有闲置线程了 .
- 如果是,并且线程总数还没有达到线程池设定的最大线程数,就会在当前读出的数据包后面再追加一条 BR_SPAWN_LOOPER 命令,告诉 Server 端,线程即将不够用了,请再启动一个新线程否则下一个请求可能不能及时响应。
- 新线程一启动,又会通过 BC_xxx_LOOP 等一系列命令告知驱动更新线程的状态.
- 这样确保了只要线程池的线程数量没有耗尽,总是会有空闲的线程在等待队列中随时待命,及时处理请求,这个就是 Binder 机制线程池管理的基本流程,
- 创建新的线程是Binder驱动来控制的,Binder驱动会判断service是否需要更多的线程来处理
- Server进程会创建很多线程处理Binder请求,这些线程采用Binder驱动的线程池,由Binder驱动自身进行管理。一个进程的Binder线程池默认最大是16个,超过的请求会阻塞等待空闲的线程。
————————————————
版权声明:本文为CSDN博主「Big Skipper」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/liuwg1226/article/details/108570553
默认是16个,包括main线程,所以可以新建的线程是15个。
https://zhuanlan.zhihu.com/p/475303968
https://blog.csdn.net/freekiteyu/article/details/70082302
https://blog.csdn.net/freekiteyu/article/details/79318031
https://www.an.rustfisher.com/android/binder/Binder_mechanism_intro/
https://www.jianshu.com/p/620a42759e8b