【Android】由浅到深理解AIDL
来源:互联网 发布:怪物猎人ol运营数据 编辑:程序博客网 时间:2024/06/05 10:48
一、 Binder概述
1.1 为什么要用binder
- 出于安全性、稳定性和内存管理的考虑,Android的应用和系统服务运行在分离的进程中,但是它们之间需要通信和共享数据
- 避免传统IPC开销和服务拒绝的问题
- android的库不支持System V 的IPC
- Binder加入了对象引用的引用计数器,消亡提醒机制。当一个Binder服务没有任何终端引用时,它的所有者可以自动提醒它去处理自己
- Binder通过UID/PID来分辨发送者和接受者(对于安全很重要)
但是:
- Binder不支持RPC,只有本地
- 客户端和服务端基于消息通信,不适用于流
- 不符合POSIX标准
1.2 binder通信流程
客户端使用服务
进程之间无法进行直接通信,所以通过Binder驱动
客户端和服务端不需要了解binder协议,所以使用代理和存根
客户端不想要知道正在使用IPC,也不关心binder和代理,所以,需要管理对象进行抽象
但是客户端怎样获取它想要通信的服务的handle,只需要问问sevicemanager(Context Manager),服务是否已经注册
最后,我们看下总体的架构
二 、 AIDL示例
使用aidl实现跨进程的加减法
2.1 服务端
新建android工程,创建包com.realize.calc.aidl,新建文件ICalcAIDL.aidl,内容如下
package com.realize.calc.aidl;interface ICalcAIDL{int add(int x , int y);int min(int x , int y );}
创建包com.realize.lizijun.binder_server,新建服务CalcService.java,内容如下
package com.realize.lizijun.binder_server; import com.realize.calc.aidl.ICalcAIDL; import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log; public class CalcService extends Service{private static final String TAG = "server"; public void onCreate(){Log.e(TAG, "onCreate");} public IBinder onBind(Intent t){Log.e(TAG, "onBind");return mBinder;} public void onDestroy(){Log.e(TAG, "onDestroy");super.onDestroy();} public boolean onUnbind(Intent intent){Log.e(TAG, "onUnbind");return super.onUnbind(intent);} public void onRebind(Intent intent){Log.e(TAG, "onRebind");super.onRebind(intent);} private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub(){ @Overridepublic int add(int x, int y) throws RemoteException{return x + y;} @Overridepublic int min(int x, int y) throws RemoteException{return x - y;} }; }
AndroidManifest.xml中注册服务
<service android:name="com.realize.lizijun.binder_server.CalcService" > <intent-filter> <action android:name="com.realize.calc.aidl" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service>
2.2 客户端
新建android工程,创建包com.realize.calc.aidl,新建文件ICalcAIDL.aidl(与服务端是一样的),内容如下
package com.realize.calc.aidl;interface ICalcAIDL{int add(int x , int y);int min(int x , int y );}
主activity内容如下
package com.realize.lizijun.binder_client; import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.util.Log;import android.view.View;import android.widget.Toast; import com.realize.calc.aidl.ICalcAIDL; public class MainActivity extends Activity{private static final String TAG = "client";private ICalcAIDL mCalcAidl; private ServiceConnection mServiceConn = new ServiceConnection(){@Overridepublic void onServiceDisconnected(ComponentName name){Log.e(TAG, "onServiceDisconnected");mCalcAidl = null;} @Overridepublic void onServiceConnected(ComponentName name, IBinder service){Log.e(TAG, "onServiceConnected");mCalcAidl = ICalcAIDL.Stub.asInterface(service);}}; @Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); } /** * 点击BindService按钮时调用 * @param view */public void bindService(View view){Intent intent = new Intent();intent.setAction("com.realize.calc.aidl");bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);}/** * 点击unBindService按钮时调用 * @param view */public void unbindService(View view){unbindService(mServiceConn);}/** * 点击12+12按钮时调用 * @param view */public void addInvoked(View view) throws Exception{ if (mCalcAidl != null){int addRes = mCalcAidl.add(12, 12);Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();} else{Toast.makeText(this, "服务器被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show(); } }/** * 点击50-12按钮时调用 * @param view */public void minInvoked(View view) throws Exception{ if (mCalcAidl != null){int addRes = mCalcAidl.min(50, 12);Toast.makeText(this, addRes + "", Toast.LENGTH_SHORT).show();} else{Toast.makeText(this, "服务器未绑定或被异常杀死,请重新绑定服务端", Toast.LENGTH_SHORT).show(); } } }
界面如下:
2.3 结果说明
- 点击BindService之后,服务端执行了onCreate和onBind的方法, 客户端执行onServiceConnected方法
- 然后点击12+12,50-12可以成功的调用服务端的代码并返回正确的结果
- 再点击unBindService, Service调用了onUnbind和onDestory
- 然后点击12+12,50-12,仍然能够看到正确的结果,说明客户端与服务端的连接仍然存在
- 我们通过后台,把服务强制停止掉,可以看到调用了onServiceDisconnected方法,此时,再点击12+12,50-12,就获取不到结果了
三、 分析AIDL生成的接口代码
上面创建ICalcAIDL.aidl之后,在gen目录下回生成文件ICalcAIDL.java, 该文件实现了客户端和服务端的代理(proxy)和存根(stub)
3.1 服务端
服务端代码中调用ICalcAIDL.Stub
private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub(){ @Overridepublic int add(int x, int y) throws RemoteException{return x + y;} @Overridepublic int min(int x, int y) throws RemoteException{return x - y;} };
而在CalcService.java中,很明显Stub就是Binder的子类
public static abstract class Stub extends android.os.Binder implements com.realize.calc.aidl.ICalcAIDL
接着看看Stub下面的方法onTransact,该方法内部实现了加减法的操作
@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_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);}服务端会根据客户端发送来的消息执行onTransact方法,该方法有四个参数code 是一个整形的唯一标识,用于区分执行哪个方法data 客户端传递过来的参数reply 服务器返回的值flags 标明是否有返回值,0为有(双向),1为没有(单向)
3.2 客户端
客户端代码中,调用了ICalcAIDL.Stub.asInterface
private ServiceConnection mServiceConn = new ServiceConnection(){@Overridepublic void onServiceDisconnected(ComponentName name){Log.e(TAG, "onServiceDisconnected");mCalcAidl = null;} @Overridepublic void onServiceConnected(ComponentName name, IBinder service){Log.e(TAG, "onServiceConnected");mCalcAidl = ICalcAIDL.Stub.asInterface(service);}};
而ICalcAIDL.java文件中,asInterface,最终是调用到Proxy
public static com.realize.calc.aidl.ICalcAIDL asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.realize.calc.aidl.ICalcAIDL))) {return ((com.realize.calc.aidl.ICalcAIDL)iin);}return new com.realize.calc.aidl.ICalcAIDL.Stub.Proxy(obj);}
所以,我们看下Proxy的add方法
@Override public int add(int x, int y) 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(x);_data.writeInt(y);mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);_reply.readException();_result = _reply.readInt();}finally {_reply.recycle();_data.recycle();}return _result;}声明了两个android.os.Parcel对象,_data用于传递数据,_replay用于接收返回的数据最后调用transact方法,与服务端进行通信
四、不依赖AIDL的示例
怎样不通过AIDL文件,实现跨进程通信呢,从上面的分析中,我们可以知道,不通过AIDL文件,实现跨进程通信,那么实际上,就是要实现自动生成的AIDL文件中的接口功能, 下面我们实现跨进程的乘除调用
4.1 服务端
创建工程,实现CalcService.java,代码如下
package com.realize.lizijun.noaidl_binder_server; import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.os.Parcel;import android.os.RemoteException;import android.util.Log; public class CalcService extends Service{private static final String DESCRIPTOR = "CalcService";private static final String TAG = "server"; public void onCreate(){Log.e(TAG, "onCreate");} @Overridepublic int onStartCommand(Intent intent, int flags, int startId){Log.e(TAG, "onStartCommand");return super.onStartCommand(intent, flags, startId);} public IBinder onBind(Intent t){Log.e(TAG, "onBind");return mBinder;} public void onDestroy(){Log.e(TAG, "onDestroy");super.onDestroy();} public boolean onUnbind(Intent intent){Log.e(TAG, "onUnbind");return super.onUnbind(intent);} public void onRebind(Intent intent){Log.e(TAG, "onRebind");super.onRebind(intent);} private MyBinder mBinder = new MyBinder(); private class MyBinder extends Binder{@Overrideprotected boolean onTransact(int code, Parcel data, Parcel reply,int flags) throws RemoteException{switch (code){case 0x110:{Log.e(TAG, "0x110");data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();int _arg1;_arg1 = data.readInt();int _result = _arg0 * _arg1;reply.writeNoException();reply.writeInt(_result);return true;}case 0x111:{Log.e(TAG, "0x111");data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();int _arg1;_arg1 = data.readInt();int _result = _arg0 / _arg1;reply.writeNoException();reply.writeInt(_result);return true;}}return super.onTransact(code, data, reply, flags);} }; }自定义了一个Binder子类,然后复写了其onTransact方法
AndroidManifest.xml中注册服务
<service android:name="com.realize.lizijun.noaidl_binder_server.CalcService" > <intent-filter> <action android:name="com.realize.noaidl.calc" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </service>
4.2 客户端
创建工程,其主activity内容如下所示:
package com.realize.lizijun.noaidl_binder_client; import android.app.Activity;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import android.view.View;import android.widget.Toast; public class MainActivity extends Activity{private static final String TAG = "client";private IBinder mPlusBinder = null;private ServiceConnection mServiceConnPlus = new ServiceConnection(){// 只有当servie异常退出时,系统才会调用onServiceDisconnected()@Overridepublic void onServiceDisconnected(ComponentName name){Log.e(TAG, "mServiceConnPlus onServiceDisconnected");mPlusBinder = null;} @Overridepublic void onServiceConnected(ComponentName name, IBinder service){ Log.e(TAG, " mServiceConnPlus onServiceConnected");mPlusBinder = service;}}; @Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); } public void bindService(View view){Intent intentPlus = new Intent();intentPlus.setAction("com.realize.noaidl.calc");boolean result = bindService(intentPlus, mServiceConnPlus,Context.BIND_AUTO_CREATE);Log.e(TAG, result + "");} public void unbindService(View view){if (mServiceConnPlus != null){Log.e(TAG, "unbindService");unbindService(mServiceConnPlus);//mServiceConnPlus = null;}} public void mulInvoked(View view){ if (mPlusBinder == null){Toast.makeText(this, "未连接服务端或服务端被异常杀死", Toast.LENGTH_SHORT).show();} else{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result = 0;try{_data.writeInterfaceToken("CalcService");_data.writeInt(50);_data.writeInt(12);mPlusBinder.transact(0x110, _data, _reply, 0);_reply.readException();_result = _reply.readInt();Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show(); } catch (RemoteException e){e.printStackTrace();} finally{_reply.recycle();_data.recycle();}} } public void divInvoked(View view){ if (mPlusBinder == null){Toast.makeText(this, "未连接服务端或服务端被异常杀死", Toast.LENGTH_SHORT).show();} else{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result = 0;try{_data.writeInterfaceToken("CalcService");_data.writeInt(36);_data.writeInt(12);mPlusBinder.transact(0x111, _data, _reply, 0);_reply.readException();_result = _reply.readInt();Toast.makeText(this, _result + "", Toast.LENGTH_SHORT).show(); } catch (RemoteException e){e.printStackTrace();} finally{_reply.recycle();_data.recycle();}} }}
界面如下:
五、 示例代码下载
aidl示例代码
0 0
- 【Android】由浅到深理解AIDL
- android AIDL 自我理解
- Android-深入理解AIDL
- Android AIDL理解
- Android-深入理解AIDL
- Android AIDL理解
- Android AIDL的重新理解
- android aidl接口的理解
- android bind aidl 实例理解
- 初步理解android中的aidl
- Android AIDL 理解及开发要点
- Android AIDL 理解及开发要点
- android 进程间通信 aidl 简单理解
- Android AIDL的理解和使用
- Android 中AIDL的使用与理解
- 从android aidl理解Proxy/stub模式
- AIDL的android:process的理解
- [Android]AIDL中的in,out,inout理解
- 《C++》03 C++ 变量作用域
- [面试] 算法(八)—— 树
- 第一次用阿里云
- Module Thinking之路径依赖
- Windows修复:使用安装光盘修复损坏的Windows系统
- 【Android】由浅到深理解AIDL
- 分析system_call中断处理过程(Linux)
- [提权禁区] SQL语句利用xp_cmdshell获取权限
- 搞定了iSCSI
- Trie树小酌
- CRCK array 1.4
- web分页
- Unity 用简单工厂模式创建对象
- [提权禁区]1433端口入侵提权