网站建设简介淄博,个人网站设计作品,wordpress2级域名插件,福建省住房和城乡建设厅网站作者#xff1a;义华 1、什么是binder
binder是android framework提供的#xff0c;用于跨进程方法调用的机制#xff0c;具有安全高效等特点。
我们知道#xff0c;在 Android 系统中#xff0c;每个应用程序都运行在一个独立的进程中#xff0c;各个进程之间需要进行… 作者义华 1、什么是binder
binder是android framework提供的用于跨进程方法调用的机制具有安全高效等特点。
我们知道在 Android 系统中每个应用程序都运行在一个独立的进程中各个进程之间需要进行数据交换和调用以实现各种功能。为了实现这个目的binder应运而生。
2、binder的历史
android基于linux内核linux提供了非常多的跨进程机制。 为什么android要使用binder而不使用linux已有的ipc机制呢这个抉择在android内部团队中有过争论。 部分工程师认为binder内部的线程等待带来了系统开销同时没有显示出更好的用处。 但最后binder还是凭借其优势胜出了。 其实binder是部分android工程师在PalmSource工作时开源的一种ipc机制负责开发ipc的工程师直接在此binder上进行了移植和开发。
在《Android传奇》一书中有介绍binder的相关历史。
3、binder基本使用
binder是一种架构这种架构提供了服务端接口、binder驱动和客户端三个模块。
客户端通过binder远程调用服务端接口binder驱动负责完成这次远程调用。 在android framework中提供了Binder类一个类如果扩展Binder类那么该类就有提供远程服务的能力该类对象一旦创建其内部就会创建一个隐藏的线程用来接收binder驱动发送的消息从而调用Binder类的onTransact()方法。
binder驱动从表现上看就是在客户端和服务端传递各种消息以完成跨进程调用。 在任意一个服务端binder对象创建时同时也会在binder驱动中创建一个对应的mRemote对象该对象也是binder类型。 客户端就是通过mRemote对象来访问远程服务的相当于经过了一层代理。 这种机制提供了更好的安全性。
客户端通过获取远程服务在binder驱动中对应的mRemote对象通过调用mRemote.transact方法从而实现对远程服务的调用。
从整个架构上看就是服务端提供binderbinder驱动负责转发消息客户端获取binder引用并调用。 粗略看很简单细节是魔鬼。
摘抄一个书中的例子从demo理解binder的调用过程。 比如要提供一个音乐播放的远程调用 可以提供一个MusicPlayerService代码如下
public class MusicPlayerService extends Binder {public void startPlay(String filePath) {}public void stop() {}Overridepublic void onTransact(int code, Parcel data, Parcel reply, int flag) {// 这个方法很重要由binder驱动调用// 根据约定的code值分别调用不同的业务方法此处是startPlay和stopif (code 0x100) {this.startPlay(file_path)} else if (code 0x101) {this.stop()}}
}如上MusicPlayerService就可以提供了远程调用服务了。 但是客户端如何使用呢。通过binder架构知道要想远程调用必须获取远程服务在binder驱动中对应的binder代理对象。此处假设已经获取到相关的引用mRemote那么客户端便可以如下调用。
IBinder mRemote null;
String filePath xxx;
int code 0x100;Parcel data Parcel.obtain();
Parcel reply Parcel.obtain(); // 接收远程调用的结果
data.writeString(filePath);
mRemote.transact(code, data, reply, 0)如上便完成了客户端对服务端的远程调用。 从这个demo就可以看出跨进程调用其实就是要通过Binder驱动来中转一下调用。 以前没看过这个示例时老是不理解aidl生成的规则不断的复习也总是记不住规则。但是通过这个示例一下就明白了这个过程在理解的基础上再去手动编写binder类就水到渠成了虽然一般也用不到手动去写binder类。
现在就只剩如何获取远程服务对应的binder对象了。 为了简化这个过程android frameworks通过service提供这个能力。 在service的生命周期方法中有一个onBind方法返回IBinder对象方法签名如下
override fun onBind(intent: Intent?): IBinder? {在调用context.bindService方法进行绑定时要求传入一个ServiceConnection的对象在服务绑定成功时会回调onServiceConnection方法一并传回服务端的Binder代理对象。 如下
Intent it new Intent(this, xxxService.class);
context.bindService(intent, new ServiceConnection() {Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 此处就拿到了远程服务对应的binder了客户端通过此binder就可以调用远程服务的方法了。 }Overridepublic void onServiceDisconnected(ComponentName name) {}
}, Service.BIND_AUTO_CREATE);仔细想想应用开发好像也只有这么一条路获取服务端的binder。 但是最初我们定义的MusicPlayerService并不是一个真正的service无法使用bindService方法故需要改造一下让MusicPlayerService继承Service类。 如下
public class MusicPlayerService extends Service {private XXXBinder mBinder;Overridepublic IBinder onBind(Intent intent) {return mBinder; // 此处返回服务端的binder}public void startPlay(String filePath) {}public void stop() {}// 由于android应用开发上只能通过service进行远程调用故在service内部类创建binder方便调用service定义的业务方法。 public xxxBinder extends Binder {Overridepublic void onTransact(int code, Parcel data, Parcel reply, int flag) {// 这个方法很重要由binder驱动调用// 根据约定的code值分别调用不同的业务方法此处是startPlay和stopif (code 0x100) {startPlay(file_path)} else if (code 0x101) {stop()}}}
}由于java不能多继承继承了service类就不能继承Binder类了。 那么可以在MusicPlayerService类内部构建一个内部类继承binder并通过onBind返回binder对象给客户端。 这个代码架构便是使用binder的基本雏形了。但是在日常开发过程中为了扩展性和解耦一般将业务方法通过接口抽象出来。 如下抽象出播放接口。
public interface IPlayer {public void startPlay(String filePath);public void stop();
}通过上面的代码可以发现播放的实现放在XXXBinder类或者MusicPlayerService都是可行的。 为了方便binder调用业务方法尝试用binder实现接口并实现业务。 改造后的代码如下
public class MusicPlayerService extends Service {private XXXBinder mBinder;Overridepublic IBinder onBind(Intent intent) {return mBinder; // 此处返回服务端的binder}// binder实现了IPlayer业务接口public xxxBinder extends Binder implemention IPlayer {Overridepublic void onTransact(int code, Parcel data, Parcel reply, int flag) {// 这个方法很重要由binder驱动调用// 根据约定的code值分别调用不同的业务方法此处是startPlay和stopif (code 0x100) {this.startPlay(file_path)} else if (code 0x101) {this.stop()}}public void startPlay(String filePath) {Log.i(test, startPlay);}public void stop() {Log.i(test, stop);}}
}至此使用binder的代码结构就较为清晰了。以上demo一步步的改造其实就是为了更加深刻的理解binder的使用并向aidl靠拢从而更好的理解aidl生成的代码。 从上代码可以看出使用binder的代码接口基本是固定的所以android framewrok提供了一个aidl的工具来简化这个过程。
4、aidl的使用
在对应模块上右键选择aidl会弹出创建aidl的对话框输入名字as会自动生成对应的aidl文件。 在aidl文件中加入自己的业务接口即可。 build一下as就会根据aidl自动生成相应的接口类和binder类具体文件此处省略。 需要注意的是aidl中只支持Parcelable对象和原子类如果有自定义的类需要跨进程访问时需要实现Parcelable接口。
客户端通过如下代码获取接口对象并实现调用。
class MusicClient {private var mIMusicPlayer: IMusicPlayer? nullprivate var mServiceConnection object: ServiceConnection {override fun onServiceConnected(name: ComponentName?, service: IBinder?) {// 这个方法中提供了是本地通信还是跨进程通信的判断// 这里就客户端进程就获取了远程服务的binder引用了。 aidl工具生成了Stub及Proxy类封装了直接通过binder.transact调用的逻辑让开发者只需和接口交互即可。 不必关心binder交互的细节。 mIMusicPlayer IMusicPlayer.Stub.asInterface(service)}override fun onServiceDisconnected(name: ComponentName?) {}}fun bindMusicService(context: Context) {val intent Intent(context, PlayerService::class.java)context.bindService(intent, mServiceConnection, Service.BIND_AUTO_CREATE)}
}注意在使用aidl时如果客户端和服务端在不同的工程时两端的aidl文件要是一样的。实际中可以直接拷贝。
5、binder架构
此处摘抄一张binder架构图 从这张图就可以清晰看到客户端、驱动及服务端的职责也能更好的理解binder的交互过程。这么看下来感觉binder驱动其实就是负责对消息进行了转发同时对交互的过程进行了一定控制。
6、总结
1.一个类要想序列化就要实现Serializable或Parcelable接口同理一个类要想提供跨进程服务就必须继承binder类。 binder就像一个标记类一样只要继承了就有资格在进程间通信了。 2.一个binder跨进程的通信包含了客户端、服务端和binder驱动三方。 3.在应用开发中主要通过aidl工具、Service及Context.bindService实现跨进程访问。 4.aidl是一个命令行工具协助生成跨进程调用的样板代码。 想了解Framework底层知识点的小伙伴可以参考一下在学习过程中我也查阅和收集了一堆的参考学习文档比如有Handler、Binder、AMS、WMS、PMS、事件分发机制、UI绘制……等等为了便于自己查阅将其知识点整合在一起并命名为了《Android Framework 核心学习手册》https://qr18.cn/AQpN4J 《Framework 核心知识点汇总手册》:https://qr18.cn/AQpN4J
Handler 机制实现原理部分 1.宏观理论分析与Message源码分析 2.MessageQueue的源码分析 3.Looper的源码分析 4.handler的源码分析 5.总结 Binder 原理 1.学习Binder前必须要了解的知识点 2.ServiceManager中的Binder机制 3.系统服务的注册过程 4.ServiceManager的启动过程 5.系统服务的获取过程 6.Java Binder的初始化 7.Java Binder中系统服务的注册过程 Zygote
Android系统的启动过程及Zygote的启动过程应用进程的启动过程 AMS源码分析
Activity生命周期管理onActivityResult执行过程AMS中Activity栈管理详解 深入PMS源码
1.PMS的启动过程和执行流程 2.APK的安装和卸载源码分析 3.PMS中intent-filter的匹配架构 WMS 1.WMS的诞生 2.WMS的重要成员和Window的添加过程 3.Window的删除过程 《Android Framework学习手册》https://qr18.cn/AQpN4J
开机Init 进程开机启动 Zygote 进程开机启动 SystemServer 进程Binder 驱动AMS 的启动过程PMS 的启动过程Launcher 的启动过程Android 四大组件Android 系统服务 - Input 事件的分发过程Android 底层渲染 - 屏幕刷新机制源码分析Android 源码分析实战