正在我们在开发的时候,涉及到需要跨进程通信,尤其是较为复杂的,需要拿到服务端 binder 代理进行交互的方式。
一般流程为:
- 编写 aidl 文件;
- 实现一个 Service 子类(独立进程),复写 onBind 方法,返回 Binder's Stub;
- 主进程通过调用 bindService,间接拿到 binder 驱动,然后实现 binder 通信;
更进一步的说,很多时候,我们也可以不依赖 aidl 文件,自己去实现Stub、Proxy类,利用 binder 驱动通过 transact 方法与服务端 Stub onTransact 进行跨进程交互。
但是依然是需要依赖 bindService 方法,去获取 binder驱动。
不过我们今天的关注点在于:
- 可以不通过 bindService ,利用别的方式来传递 “binder 驱动”来实现跨进程通信吗?
- framework 层有哪些地方使用了 1 的方式进行通信?
更多问答 >>
-
2022-05-06 11:37
-
每日一问 | Service onStartCommand 返回STICKY是如何做到被拉活的?
2022-07-24 11:50 -
2022-05-27 20:55
-
2022-06-12 14:41
-
每日一问 | 被声明为private final 的内部类,能生成一个子类对象吗?逆天篡改~
2022-04-15 21:13 -
每日一问 .class vs Class.forName() vs loadClass() 类加载傻傻分不清楚?
2022-02-11 14:22 -
每日一问 | 脱糖对于Android 打包期间插桩的有什么影响?
2022-03-07 21:26 -
每日一问 | 如何构造一个 hide interface 的实现类?
2022-02-08 23:51 -
每日一问 | android hidden api 不是禁用反射,以及如何突破,「元反射」不行了?
2022-02-08 23:51
每日一问 | 可以不借助 bindService,实现跨进程 binder 通信吗?
正在我们在开发的时候,涉及到需要跨进程通信,尤其是较为复杂的,需要拿到服务端 binder 代理进行交互的方式。一般流程为:
更进一步的说,很多时候,我们也可以不依赖 aidl 文件,自己去实现Stub、Proxy类,利用 binder 驱动通过 transact 方法与服务端 Stub onTransact 进行跨进程交互。但是依然是需要依赖 bindService 方法,去获取 binder驱动。可以参考:Android aidl Binder框架浅析
不过我们今天的关注点在于
1.关于bindService
Service组件bindService()大概流程如下:
3.最后,AMS将目标进程对应的Service Binder对象通用InnerConnection.connect()回调ServiceConnection.onServiceConnected()传递到发起进程。
正如上图所述,Service组件的bind本质是通过AMS完成Binder对象的传递。2.传递Binder句柄
根据原问题的描述:可以不通过 bindService ,利用别的方式来传递 “binder 驱动”来实现跨进程通信吗? ,显然问题并不是在说单纯的进程间通讯(如果是的话,应该往Unix Socket、共享内存、管道方面展开吧),我理解的是:不通过Service组件bind来传递Binder句柄实现跨进程通讯。其实传递Binder句柄过程中永远离不开Binder Driver(内核驱动)和ServiceManager(Service路由)的支持,下图是Binder抽象分层模型:
Framework传递Binder
java层实现BinderProxy、Binder
Service端
Client端
Service的注册和获取及验证
先用ADB命令将ServerDemo,ClientDemo可执行文件,以及ServerDemo.jar,ClientDemo.jar都push到手机:
如果上述开启成功,通过开启两个窗口运行(一个运行client端,另一个运行server端)
Native层实现BpBinder、BBinder
Service端和Client端
Service的注册和获取及验证
如果上述开启成功,通过开启两个窗口运行(一个运行client端,另一个运行server端)
3.Framework 层有哪些地方使用了这些方式进行通信
java层
对于java层来说,注册服务最多的地方无疑是SystemServer进程(从Zygote启动进程fork而来,主要负责注册启动各种系统必要的Service),然后应用进程向ServiceManagerService.getService()就能获取到Binder句柄了,因为服务太多,这里只举例WMS和IMS:
native层
因为native层是cpp文件,注册Service有点和java层不一样,以SurfaceFlinger(负责绘制应用UI的核心,其功能是将所有Surface合成工作)为例,因为在系统启动过程中指定rc文件执行初始化cpp文件:
surfaceflinger服务属于核心类(core class),另外,当surfaceflinger重启时会触发zygote的重启。 surfaceflinger服务启动的起点便是如下的main()函数,完成注册后从Native层的ServiceManager获取Binder句柄即可。
4.题外话
有同学看到这些觉得难,其实,这并不奇怪,一般写应用界面根本就不会接触到,因为这需要了解Framework基本的知识才行。我认为学习Framework层需要具备以下基础:
如果没有以上这2个必备的基础,你在看Binder源码很可能停留在表面,当然前面所说的也只不过是整个Binder的冰山一角而已。学习新东西往往有共性所在,正如你会Jetpack Compose,那么你也会70%的Flutter了。不管看多少书,更重要的是自己思考,动手重复的实践!也许这个过程很耗时间,但是,这个不断以代码去验证自己的某些猜想的过程,也许便是这是鸿洋、郭霖前辈们的技术成长的历程吧。
能否不用 service manager 的 addService?这玩意儿会被 selinux 挡掉。
系统不允许没权限user添加service是出于binder安全、高效的设计,因为binder句柄传递永远绕不开ServiceManager、BInder Driver,所以你考虑换一种IPC跨进程通 ...查看更多
系统不允许没权限user添加service是出于binder安全、高效的设计,因为binder句柄传递永远绕不开ServiceManager、BInder Driver,所以你考虑换一种IPC跨进程通讯方式,如Socket、Pipe、共享内存等等。
这个和launcher进程有什么关系呀?
这里launcher进程是指请求bindService的Client进程,表示发起请求的进程,不是桌面launcher进程。
可通过Contentprovider
参考https://github.com/luckybilly/CC/blob/master/cc/src/main/java/com/billy/cc/core/component/remote/RemoteCursor.java还可以通过广播接收器peek
1.有权限就用ServiceManager#addService,没权限用ContentProvider传递binder
2.framework里几乎所有的各种Manager都是ServiceManager#addService实现的好处是获取方法是同步的是否可以用 socket 通信呢?
可以
爱奇艺有个方案也不知适不适用https://github.com/iqiyi/Andromeda
这个的核心还是bindService实现的