Binder框架及AIDL解析
2015-12-26 12:45
489 查看
Binder其实就是,连接服务端和客户端的桥梁,Binder可以提供系统中任何程序都可以访问的全局服务。(这时,我们可能会想到AIDL,因为提到全局的服务,我们一般都会用到AIDL,这和Binder有什么关系呢?其实,AIDL的内部实现,归根结底也是利用Binder的框架,只不过AIDL的代码是系统自动帮我们生成的,所以我们一般借助AIDL以简化不同应用程序间访问的全局服务。)
我们可以把任意的应用程序看做是客户端,全局的服务看作是服务端。
客户端:客户端的请求通过客户端Binder对象,调用tansact方法,传递到服务端。
服务端:服务端同样通过服务端Binder对象,接收客户端传递过来的请求,然后处理请求(调用Binde对象的onTansact方法)。
为了简化,先先借助AIDL实现全局服务。
下面以一个加减运算的服务,简单介绍Binder实现全局服务,首先新建AIDL文件:
服务端代码:CalService类
下面往清单文件里注册服务:
这里我们给Service指定了一个name,因为我们一会会在别的应用程序中通过Intent来查找此Service;这个不需要Activity,所以我也就没写Activity,安装完成也看不到安装图标,悄悄在后台运行着。
客户端UI显示:activity_main.xml
客户端代码:
ICalcAIDL.Stub.asInterface(iBinder)方法返回的是ICalcAIDL.Stub.Proxy对象。顾名思义就是ICalcAIDL的代理类,也是ICalcAIDL类型的。这里的iBinder对象就是客户端与连接服务器端建立连接时的IBinder,(也就是说是在服务器端初始化的mBinder)
所有代码到此结束!
下面具体结合自动生成的文件与服务端和客户端的联系。
自动生成的ICalcAIDL.java文件,看起来感觉很多,其实只需要关心几个模块即可,首先先看Stub定义:继承Binder,实现ICalcAIDL(我定义的aidl文件)
因此我们服务端CalcService里面实例化Binder对象mBInder通过如下代码:(实现ICalcAIDL.aidl文件里面定义的方法)
再看
Stub类的onTansact方法:服务端的Binder实例会根据客户端发来的消息(依靠Binder对象),执行onTransact方法,然后由其参数决定执行服务端的代码。相信大家都看到里面的case判断语句了。
Stub类的asInterface()方法:这个方法关乎客户端代码,再次贴出客户端相关代码:
直接看Proxy的add方法。
总的过程可以这么理解:AIDL只不过是简化BInder框架的一个机制,(帮我们自动生成了代码)
下面是原生Binder框架实现与AIDL实现的具体细节:
我们需要了解里面的内部细节,1,在服务端:首先需要客户端与服务器建立连接时生成一个IBinder对象(这个IBinder对象是继承自Binder类,)
原生的Binder框架:在这个Binder类的内部需要复写onTransact(),方法内部是根据该方法的参数选择case语句分支,也就是选择不同的方法(需要提供的服务方法对应于AIDL用法里面建立的aidl文件)。
AIDL实现:先定义一个AID文件同样是需要一个IBinder对象,不过这里只需要实线Stub类的各种方法即可(Stub里面的各种方法就是定义的AIDL文件)。
2,在客户端:需要拿到在服务端初始化的IBInder对象,也即是在第一部中得到的IBinder对象,一般是从ServiceConnnectin类的onConnection方法中获取。
原生Binder框架:从ServiceConnnectin类的onConnection方法中获取,拿到IBinder对象,在需要调用服务的地方,向IBinder对象一步一步传入具体参数,并调用IBinder对象的onTransact()方法,向服务其传递参数,并等待服务器返回结果后,接收服务器返回的数据,(其实这里的onTransact方法就是第一部中生成IBInder对象时复写的onTransact方法)。
AIDL实现:在erviceConnnectin类的onConnection方法中通过IBinder对象,获取的是AIDL类型的类(提供服务的类)的代理对象,在需要调用服务的地方,直接调用该代理对象的相应方法就行,不需要向上面那样进行复杂的传递和接收工作。
我们可以把任意的应用程序看做是客户端,全局的服务看作是服务端。
客户端:客户端的请求通过客户端Binder对象,调用tansact方法,传递到服务端。
服务端:服务端同样通过服务端Binder对象,接收客户端传递过来的请求,然后处理请求(调用Binde对象的onTansact方法)。
为了简化,先先借助AIDL实现全局服务。
下面以一个加减运算的服务,简单介绍Binder实现全局服务,首先新建AIDL文件:
package com.example.administrator.myaidl; // Declare any non-default types here with import statements interface ICalcAIDL { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); int add(int a , int b); int min(int a,int b); }
服务端代码:CalService类
package com.example.administrator.myaidl; import android.app.Service; import android.content.Intent; import android.content.ServiceConnection; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; /** * Created by Administrator on 2015/12/25. */ public class CalService extends Service { private static String Tag="Service"; @Override public void onCreate() { super.onCreate(); Log.e(Tag,"OnCreate()"); } //绑定返回Binder对象mBinder,mBinder是ICalcAIDL.Stub的引用(ICalcAIDL是我上面新建的AIDL文件名,Stub是继承于Binder的) @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onDestroy() { Log.e(Tag,"OnDestroy()"); super.onDestroy(); } @Override public boolean onUnbind(Intent intent) { Log.e(Tag,"onUnBinder()"); return super.onUnbind(intent); } @Override public void onRebind(Intent intent) { Log.e(Tag,"OnRebind()"); super.onRebind(intent); } private final ICalcAIDL.Stub mBinder=new ICalcAIDL.Stub(){ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public int add(int a, int b) throws RemoteException { return a+b; } @Override public int min(int a, int b) throws RemoteException { return a-b; } }; }在此Service中,使用生成的ICalcAIDL创建了一个mBinder的对象,并在Service的onBind方法中返回.此时系统会自动为我们生成ICalcAIDL.java文件,如下:
/* * This file is auto-generated. DO NOT MODIFY. * Original file: F:\\duan\\Linux\\CSDNDemo\\myaidl\\src\\main\\aidl\\com\\example\\administrator\\myaidl\\ICalcAIDL.aidl */ package com.example.administrator.myaidl; // Declare any non-default types here with import statements public interface ICalcAIDL extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.example.administrator.myaidl.ICalcAIDL { private static final java.lang.String DESCRIPTOR = "com.example.administrator.myaidl.ICalcAIDL"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an com.example.administrator.myaidl.ICalcAIDL interface, * generating a proxy if needed. */ public static com.example.administrator.myaidl.ICalcAIDL asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.example.administrator.myaidl.ICalcAIDL))) { return ((com.example.administrator.myaidl.ICalcAIDL)iin); } return new com.example.administrator.myaidl.ICalcAIDL.Stub.Proxy(obj); } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_basicTypes: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); long _arg1; _arg1 = data.readLong(); boolean _arg2; _arg2 = (0!=data.readInt()); float _arg3; _arg3 = data.readFloat(); double _arg4; _arg4 = data.readDouble(); java.lang.String _arg5; _arg5 = data.readString(); this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5); reply.writeNoException(); return true; } case TRANSACTION_add: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.add(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } case TRANSACTION_min: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _arg1; _arg1 = data.readInt(); int _result = this.min(_arg0, _arg1); reply.writeNoException(); reply.writeInt(_result); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.example.administrator.myaidl.ICalcAIDL { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(anInt); _data.writeLong(aLong); _data.writeInt(((aBoolean)?(1):(0))); _data.writeFloat(aFloat); _data.writeDouble(aDouble); _data.writeString(aString); mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } @Override public int add(int a, int b) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(a); _data.writeInt(b); mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public int min(int a, int b) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(a); _data.writeInt(b); mRemote.transact(Stub.TRANSACTION_min, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_min = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException; public int add(int a, int b) throws android.os.RemoteException; public int min(int a, int b) throws android.os.RemoteException; }后面再解释自动生成的代码。
下面往清单文件里注册服务:
<service android:name=".CalService"> <intent-filter> <action android:name="com.dfy.myaidl"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </service>
这里我们给Service指定了一个name,因为我们一会会在别的应用程序中通过Intent来查找此Service;这个不需要Activity,所以我也就没写Activity,安装完成也看不到安装图标,悄悄在后台运行着。
客户端UI显示:activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="bindService" android:text="BindService" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="unbindService" android:text="UnbindService" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="addInvoked" android:text="12+12" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="minInvoked" android:text="50-12" /> </LinearLayout>
客户端代码:
package com.example.administrator.myaidl; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; import android.os.RemoteException; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { private static final String Tag = "client"; private ICalcAIDL mCalcAidl; private ServiceConnection mConn=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.e(Tag,"onServiceConnection"); mCalcAidl = ICalcAIDL.Stub.asInterface(iBinder); } @Override public void onServiceDisconnected(ComponentName componentName) { Log.e(Tag,"OnServiceDisconnected()"); mCalcAidl=null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void bindService(View view ) { Intent intent =new Intent(); intent.setAction("com.dfy.myaidl"); super.bindService(intent, mConn, Context.BIND_AUTO_CREATE); } public void unbindService(View view) { super.unbindService(mConn); } public void addInvoked(View view) throws RemoteException { if(mCalcAidl!=null){ int res= mCalcAidl.add(12,12); Log.e("Tag","addInvoke()的结果:"+res); Toast.makeText(this,res+"",Toast.LENGTH_SHORT).show(); }else { Toast.makeText(this,"服务器被异常杀死,重新连接!",Toast.LENGTH_SHORT).show(); } } public void minInvoked(View view) throws RemoteException { if(mCalcAidl!=null){ int res=mCalcAidl.min(50,12); Log.e(Tag, "minInvoke()的结果:"+res); Toast.makeText(this,res+"",Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(this, "服务器异常,重新连接!",Toast.LENGTH_LONG).show(); } } }
ICalcAIDL.Stub.asInterface(iBinder)方法返回的是ICalcAIDL.Stub.Proxy对象。顾名思义就是ICalcAIDL的代理类,也是ICalcAIDL类型的。这里的iBinder对象就是客户端与连接服务器端建立连接时的IBinder,(也就是说是在服务器端初始化的mBinder)
所有代码到此结束!
下面具体结合自动生成的文件与服务端和客户端的联系。
自动生成的ICalcAIDL.java文件,看起来感觉很多,其实只需要关心几个模块即可,首先先看Stub定义:继承Binder,实现ICalcAIDL(我定义的aidl文件)
public static abstract class Stub extends android.os.Binder implements com.example.administrator.myaidl.ICalcAIDL
因此我们服务端CalcService里面实例化Binder对象mBInder通过如下代码:(实现ICalcAIDL.aidl文件里面定义的方法)
private final ICalcAIDL.Stub mBinder=new ICalcAIDL.Stub(){ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { } @Override public int add(int a, int b) throws RemoteException { return a+b; } @Override public int min(int a, int b) throws RemoteException { return a-b; } };
再看
Stub类的onTansact方法:服务端的Binder实例会根据客户端发来的消息(依靠Binder对象),执行onTransact方法,然后由其参数决定执行服务端的代码。相信大家都看到里面的case判断语句了。
Stub类的asInterface()方法:这个方法关乎客户端代码,再次贴出客户端相关代码:
private ServiceConnection mConn=new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.e(Tag,"onServiceConnection"); mCalcAidl = ICalcAIDL.Stub.asInterface(iBinder); } @Override public void onServiceDisconnected(ComponentName componentName) { Log.e(Tag,"OnServiceDisconnected()"); mCalcAidl=null; } };
public static com.example.administrator.myaidl.ICalcAIDL asInterface(android.os.IBinder obj)这个方法返回一个Proxy实例,这个Proxy实例传入了我们的Binder对象,并且封装了我们调用服务端的代码,客户端会通过Binder对象的transact()方法调用服务端代码。
直接看Proxy的add方法。
android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR);//读取服务端端口,与服务器端enforceInterface(DESCRIPTOR)相对应 _data.writeInt(a); _data.writeInt(b); mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); _reply.readException(); _result = _reply.readInt();//客户端接收服务端返回的数据, } finally { _reply.recycle(); _data.recycle(); } return _result;Proxy的min方法类似,略...
总的过程可以这么理解:AIDL只不过是简化BInder框架的一个机制,(帮我们自动生成了代码)
下面是原生Binder框架实现与AIDL实现的具体细节:
我们需要了解里面的内部细节,1,在服务端:首先需要客户端与服务器建立连接时生成一个IBinder对象(这个IBinder对象是继承自Binder类,)
原生的Binder框架:在这个Binder类的内部需要复写onTransact(),方法内部是根据该方法的参数选择case语句分支,也就是选择不同的方法(需要提供的服务方法对应于AIDL用法里面建立的aidl文件)。
AIDL实现:先定义一个AID文件同样是需要一个IBinder对象,不过这里只需要实线Stub类的各种方法即可(Stub里面的各种方法就是定义的AIDL文件)。
2,在客户端:需要拿到在服务端初始化的IBInder对象,也即是在第一部中得到的IBinder对象,一般是从ServiceConnnectin类的onConnection方法中获取。
原生Binder框架:从ServiceConnnectin类的onConnection方法中获取,拿到IBinder对象,在需要调用服务的地方,向IBinder对象一步一步传入具体参数,并调用IBinder对象的onTransact()方法,向服务其传递参数,并等待服务器返回结果后,接收服务器返回的数据,(其实这里的onTransact方法就是第一部中生成IBInder对象时复写的onTransact方法)。
AIDL实现:在erviceConnnectin类的onConnection方法中通过IBinder对象,获取的是AIDL类型的类(提供服务的类)的代理对象,在需要调用服务的地方,直接调用该代理对象的相应方法就行,不需要向上面那样进行复杂的传递和接收工作。
相关文章推荐
- 如果将synthesize省略,语义特性声明为assign retain copy时,自己实现setter和getter方法
- iPhone开发教程之retain/copy/assign/setter/getter
- Intellij Idea 主题下载(Eclectide Monokai)
- HDU3537-Daizhenyang's Coin(博弈SG-打表)
- 时间复杂度和空间复杂度详解 http://blog.csdn.net/booirror/article/details/7707551
- 5.3.1.1 ChainMap的例子和技巧
- 5.3.1.1 ChainMap的例子和技巧
- VS2010升级VS2013后,出现没有定义类型“PowerPacks.ShapeContainer”错误解决方法
- RAID 各级别特性
- Gfx.WaitForPresent
- POJ 3735 Training Little Cats
- error TRK0005: Failed to locate: "CL.exe"
- ubuntu sendmail(只作为本机发送)
- 【Codeforces Round 272 (Div 2)B】【暴力dfs or 组合数】Dreamoon and WiFi 问号填加减方案数使得最后恰好增量为aim
- (转)图灵测试与人工智能
- LNMP环境下SendMail+OpenWebMail的详细配置
- Linking Containers Together
- 如何用UltraISO制作大于4G文件的光盘映像可启动U盘
- CodeBlock编辑器GCC环境下,编译报错:Execution of 'mingw32-g++.exe -o bin\Debug\test.exe obj\Debug\main.o' in 'C
- 菜鸟初识AIDL进程通信