Binder Java层的使用介绍
来源:互联网 发布:c语言中‖是什么意思 编辑:程序博客网 时间:2024/05/29 07:37
1: 概述
Binder这个东西, 之前看过, 迷糊的狠, 只是了解了基本的原理, 具体到代码层就比较模糊了。
关键是脑袋里没有一个基本的Binder的通信模型。
所以先从上层开始分析使用, 然后分析模型, 最后再到代码。 任何东西如果脑袋里有了一个基本的模型后, 任何事情的分析都会事半功倍。 细节的分析, 只是丰富这个模型罢了。
废话结束。
2: Java层的AIDL
如果不了解什么是AIDL就没法说java层的Binder。
AIDL超级简单就是辅助用户编写Java端的Binder通信的代码使用。
例如你想写一个基于Binder的跨进程远程通信机制:
1) 准备工作
先写一个简单的AIDL接口文件(IGank.aidl), 然后用工具生成JAVA文件(IGank.java 这个接口文件包含三部分: 【1】你在AIDL文件里面定义的接口(IGank) 【2】 一个Stub类(IGank.stub), 用于服务端 【3】 一个Proxy类(IGank.stub.Proxy), 用于客户端), 准备工作结束。
2) 服务端
服务端继承 Stub 类, 并实现接口, 就这么简单。
3) 客户端
客户端更加简单, 只要使用IGank.Stub.asInterface方法, 把一个Binder对象转换成IGank对象就可以了。 用户可以直接使用IGank的方法, 这里通过Binder, 服务端相应的方法也会被调用。
3: 以一个JAVA层系统的Binder服务进行分析
这里选的是InputManagerService。 先上图有一个大致了解。
1) 服务端分析
服务端按照上面分析AIDL的方式分析, 就特别简单。
首先InputManagerService 需要定义了一系列的方法用于客户端的调用 (定义方法的文件是 IInputManager.aidl文件)
接着InputManagerService 就需要实现了, 这个时候只需要继承 IInputManager.Stub 类就可以了 (这个文件上面已经介绍是通过工具自动生成的)
2) 客户端分析
客户端的分析, 我们以一次 InputManagerService 中方法调用的过程进行介绍。
1: 如何获取InputManager
通常使用 Context 的 public Object getSystemService(String name) 方法。
然后强制转换成响应的SystemService.
这个方法实现在ContextImpl.java
public Object getSystemService(String name) { ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); }
registerService(INPUT_SERVICE, new StaticServiceFetcher() { public Object createStaticService() { return <span style="color:#ff0000;">InputManager.getInstance();</span> }});
可以看到所有系统服务都注册到到一个以服务名为Key的Map上(SYSTEM_SERVICE_NAME).
由于InputManager是就是一个Singleton模式, 所以实际返回的InputManager就是一个静态对象。
2: InputManager初始化流程
public static InputManager <span style="color:#ff0000;">getInstance</span>() { synchronized (InputManager.class) { if (sInstance == null) { IBinder b = ServiceManager.<span style="color:#ff0000;">getService</span>(Context.INPUT_SERVICE); sInstance = new InputManager(IInputManager.Stub.<span style="color:#ff0000;">asInterface</span>(b)); } return sInstance; } }第一步是获取服务端注册的Binder对象。 这部分主要是到ServerManager中去查找相应的Service的Binder。
Slog.i(TAG, "Input Manager"); inputManager = new InputManagerService(context, wmHandler); ServiceManager.addService(Context.INPUT_SERVICE, inputManager);在SystemServer.java中开启相应的服务的时候, 把相应的服务注册到系统的systemserver服务中, 以供上面 ServiceManager.getService(Context.INPUT_SERVICE); 通过服务名获取相应的Binder对象。
public static android.hardware.input.IInputManager asInterface(android.os.IBinder obj) {if ((obj == null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin != null) && (iin instanceof android.hardware.input.IInputManager))) {return ((android.hardware.input.IInputManager) iin);}return new android.hardware.input.IInputManager.Stub.Proxy(obj);}通过这部分的代码不难看出, 转换的最终调用new android.hardware.input.IInputManager.Stub.Proxy(obj);
这里就看到了InputManager端实际是InputManagerService的一个代理端(PS: Proxy 实现IInputManager接口, 所以可以被强制转换成IInputManager对象)。
private final IInputManager mIm; private InputManager(IInputManager im) { mIm = im; }这里看到InputManager会保存一个InputManagerService的代理对象。
看图上的虚线, 可以看出来InputManager实际上保存一个InputManagerService的一个代理对象。
3: 服务端InputMangerService如何响应
这个就是Proxy如何调用Stub的问题了。
假设服务端调用InputManager.deviceHasKeys方法
public boolean[] deviceHasKeys(int id, int[] keyCodes) { boolean[] ret = new boolean[keyCodes.length]; try { mIm.hasKeys(id, InputDevice.SOURCE_ANY, keyCodes, ret); } catch (RemoteException e) { // no fallback; just return the empty array } return ret; }实际调用的是Proxy的hasKeys方法。
@Overridepublic boolean hasKeys(int deviceId, int sourceMask, int[] keyCodes,boolean[] keyExists) throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();boolean _result;try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeInt(deviceId);_data.writeInt(sourceMask);_data.writeIntArray(keyCodes);if ((keyExists == null)) {_data.writeInt(-1);} else {_data.writeInt(keyExists.length);}<span style="color:#ff0000;">mRemote.transact(Stub.TRANSACTION_hasKeys, _data, _reply, 0);</span>_reply.readException();_result = (0 != _reply.readInt());_reply.readBooleanArray(keyExists);} finally {_reply.recycle();_data.recycle();}return _result;}这个函数实际调用了远程的transact方法, 也就是Stub.transact方法。
由于Stub继承了Binder, transact实际是Binder中的方法, 这个方法只是简单的调用相应的onTransact方法。
public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { data.setDataPosition(0); } boolean r = <span style="color:#ff0000;">onTransact(code, data, reply, flags);</span> if (reply != null) { reply.setDataPosition(0); } return r; }
@Overridepublic boolean onTransact(int code, android.os.Parcel data,android.os.Parcel reply, int flags)throws android.os.RemoteException {switch (code) {...case TRANSACTION_hasKeys: {data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();int _arg1;_arg1 = data.readInt();int[] _arg2;_arg2 = data.createIntArray();boolean[] _arg3;int _arg3_length = data.readInt();if ((_arg3_length < 0)) {_arg3 = null;} else {_arg3 = new boolean[_arg3_length];}boolean _result = <span style="color:#ff0000;">this.hasKeys(_arg0, _arg1, _arg2, _arg3);</span>reply.writeNoException();reply.writeInt(((_result) ? (1) : (0)));reply.writeBooleanArray(_arg3);return true;}...}}可以看到这里根据Code解析相应的参数, 然后再调用InputManagerService中实际的方法, 至此整个调用逻辑结束, 最后用一张图总结一下。
总结
Java层的Binder, 即使对于App的开发者来说也是透明的。
其作用很简单就是跨进程间的通讯。
实现方式, 使用了代理模式来实现。
服务端实现Stub, 客户端通过Proxy对象调用服务端, 中间的通信逻辑是急于Binder的通信, 并且封装到用户不知道是用Binder来通信的。
0 0
- Binder Java层的使用介绍
- Java 层Binder的使用(Android framework)
- Java层Binder使用(ServiceManager)
- Java层Binder使用(ServiceManager)
- Java层的Binder服务实现
- Java层到Native层Binder的流程
- Java层Binder机制详解
- Binder java层实现原理
- Java层Binder机制详解
- Java层Binder机制详解
- Java层Binder全解析。
- Android------Binder java层浅析
- Binder框架在Framework层的C++中的使用
- Binder框架在Framework层的C++中的使用
- Binder框架在Framework层的C++中的使用
- Binder框架在Framework层的C++中的使用
- Binder框架在Framework层的C++中的使用
- Binder框架在Framework层的C++中的使用
- 程序员的成功是否有规律可循?
- (Errcode: 13) when executing 'SELECT INTO OUTFILE'
- 9、决不在构造函数和析构函数中调用virtual函数
- 125个基本的C#面试问答
- 【机器学习】线性回归
- Binder Java层的使用介绍
- jQuery幻灯片插件Skippr
- 使用OpenSessionInViewFilter解决lazy failed问题
- 技术总结--android篇(二)--布局的优化
- hd 2187 悼念512汶川大地震遇难同胞——老人是真饿了
- eclipse中的Java文件自动根据svn版本号生成注释
- abercrombie online italia the Japanese steel powerless because of the lack of new stadiums
- 杭电acm1008 hdu-acm-1008解题报告
- (c语法百题16)一元二次方程的实数根