AIDL是一种接口定义语言,用于生成可在Android设备上两个进程之间进行进程间通信(IPC)的代码。
AIDL的使用
- 新建一个aidl文件,定义进程间通信的接口
// IStudentManager.aidl package com.tellh.androidart; // Declare any non-default types here with import statements import com.tellh.androidart.Student; interface IStudentManager { List<Student> getStudent(); void addStudent(in Student student); }
注意点:
- aidl中支持的参数类型为:基本类型(int,long,char,boolean等),String,CharSequence,List,Map,其他类型必须使用import导入,即使它们可能在同一个包里。
- 接口中的参数除了aidl支持的类型,其他类型必须标识其方向:到底是输入还是输出抑或两者兼之,用in,out或者inout来表示。
- 如果有自定义的数据类型,需要把自定义类实现Parcelable接口并新建aidl声明文件。
// Student.aidl package tellh.com.androidart; parcelable Student; public class Student implements Parcelable {...}
点击sycn project,对应的接口java类就被自动生成在gen目录中。
- 创建服务端的Service,运行在服务端进程
public class AidlTestService extends Service { private final static String TAG = "AidlTestService"; private static final String PACKAGE_CLIENT = "com.example.test.aidlclient&&com.tellh.androidart"; private final List<Student> mStudents = new ArrayList<>(); private IBinder mBinder = new IStudentManager.Stub() { @Override public List<Student> getStudent() throws RemoteException { synchronized (mStudents) { return mStudents; } } @Override public void addStudent(Student student) throws RemoteException { synchronized (mStudents) { if (!mStudents.contains(student)) mStudents.add(student); } } @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { //权限控制 String packageName = null; String[] packages = AidlTestService.this.getPackageManager(). getPackagesForUid(getCallingUid()); if (packages != null && packages.length > 0) { packageName = packages[0]; } Log.d(TAG, "onTransact: " + packageName); String[] clients = PACKAGE_CLIENT.split("&&"); for (String client : clients) { if (client.equals(packageName)) { return super.onTransact(code, data, reply, flags); } } return false; } }; @Override public void onCreate() { super.onCreate(); synchronized (mStudents) { for (int i = 1; i < 6; i++) { Student student = new Student(); student.sno = i; student.name = "student#" + i; student.age = i * 5; mStudents.add(student); } } } public AidlTestService() { } @Override public IBinder onBind(Intent intent) { return mBinder; } }
注册Service
<service android:name=".AidlTestService" android:enabled="true" android:exported="true"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="com.tellh.androidart.AidlTestService" /> </intent-filter></service>
新建一个进程作为客户端,隐式启动服务端的Service,在绑定的回调函数中通过IStudentManager.Stub.asInterface(binder)
获得通信接口的代理对象。
public class AidlClientActivity extends ActionBarActivity { private String tag = "AidlClient"; private static final String ACTION_BIND_SERVICE = "com.tellh.androidart.AidlTestService"; private IStudentManager mStudentManager; // Binder连接断裂(死亡)代理 private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { if (mStudentManager == null) return; mStudentManager.asBinder().unlinkToDeath(mDeathRecipient, 0); mStudentManager = null; bindService(); } }; private ServiceConnection mServiceConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { mStudentManager = IStudentManager.Stub.asInterface(service); try { service.linkToDeath(mDeathRecipient, 0); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mStudentManager = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_aidl_client); bindService(); } private void bindService() { Intent intent = new Intent(ACTION_BIND_SERVICE); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setPackage("com.tellh.androidart"); bindService(intent, mServiceConn, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); if (mStudentManager != null) unbindService(mServiceConn); } public void onClickGetStudent(View view) { if (mStudentManager == null) return; try { Log.d(tag, mStudentManager.getStudent().toString()); } catch (RemoteException e) { e.printStackTrace(); } } public void onClickAddStudent(View view) { if (mStudentManager == null) return; try { Student student = new Student(); student.sno = 7; student.age = 10; student.name = "TellH"; student.sex = Student.SEX_MALE; mStudentManager.addStudent(student); Log.d(tag, mStudentManager.getStudent().toString()); } catch (RemoteException e) { e.printStackTrace(); } } }
注册Activity,在新的进程中运行
<activity android:name=".AidlClientActivity" android:process=":client" />
如果在应用之间通信,客户端应用需要把服务端的aidl文件全部copy过来,并且保证包名相同,
AIDL的工作原理
分析自动生成的java接口代码:
pubblic interface IStudentManager extends android.os.IInterface { public static abstract class Stub extends android.os.Binder implements tellh.com.androidart.IStudentManager {...} public java.util.List<tellh.com.androidart.Student> getStudent() throws android.os.RemoteException; public void addStudent(tellh.com.androidart.Student student) throws android.os.RemoteException;
这个接口类继承IInterface,所有在Binder中传输的接口都必须继承IInterface。它除了保留了我们定义在aidl文件中的两个方法外,还自动生成一个名为Stub的静态类。这个Stub是抽象类,实现了这个接口类并继承自Binder,将会在服务端的Service中被实例化,作为onBind的返回指返回给客户端,客户端通过IStudentManager.Stub.asInterface(binder)转化为这个接口类的代理对象。
抽象类Stub的成员和属性:
DESRIPTOR
Binder的唯一标识,一般用当前Binder的全类名表示。
public static IStudentManager asInterface(IBinder obj)
如果客户端和服务端位于同一个进程,那么直接返回服务端的Stub对象本身,否则返回Stub.Proxy代理对象。
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
该方法运行在服务端中的Binder线程池中,服务端通过code确定客户端所请求的目标方法是什么,从data中取出目标方法所需的参数,然后执行目标方法,并将目标方法的返回值写入reply。如果该方法的返回false,那么客户端的请求回失败。因此,我们可以利用这个特性来做权限验证。
Proxy#addStudent
Proxy是一个代理类,或者说是装饰者类。
@Override public java.util.List<tellh.com.androidart.Student> getStudent() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<tellh.com.androidart.Student> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getStudent, _data, _reply, 0); _reply.readException(); _result = _reply.createTypedArrayList(tellh.com.androidart.Student.CREATOR); }finally { _reply.recycle(); _data.recycle(); } return _result; }
每一个代理方法都是相同的套路,将方法的标识,参数和返回值对象传入方法mRemote.transact中,发起远程调用请求,同时挂起当前线程,然后服务端的Stub#onTransact被调用。当onTransact返回true,调用成功,从reply对象中取出返回值,返回给客户端调用方。
总结
高度概括AIDL的用法,就是服务端里有一个Service,给与之绑定(bindService)的特定客户端进程提供Binder对象。客户端通过AIDL接口的静态方法asInterface 将Binder对象转化成AIDL接口的代理对象,通过这个代理对象就可以发起远程调用请求了。
至于更深入地,远程调用的过程可以概括如下图
————————————————
版权声明:本文为CSDN博主「TellH」的原创文章,遵循undefined版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/tellh/article/details/55100167
来源:https://www.cnblogs.com/yz123/p/12011108.html