在开发过程中,实现进程间通信用的最多的就是 AIDL。
AIDL(Android Interface Definition Language),也就是接口定义语言,提供接口给远程调用者。
当我们定义好 AIDL 文件,在编译时编译器会帮我们生成代码实现 IPC 通信。为了可以更好的理解Binder的过程,从AIDL入手。
服务端 先创建一个服务端,创建一个IStudentManager.aidl
文件,声明2个方法getStudentList()
以及addStudent()
IStudentManager.aidl 1 2 3 4 5 6 7 8 9 package com.golden.aidlserver;import com.golden.aidlserver.Student;interface IStudentManager { List<Student> getStudentList () ; void addStudent (in Student student) ; }
IStudentManager.java Build一下工程,android studio会自动为我们生成一个java类:IStudentManager.java,大体结构如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package com.golden.aidlserver;public interface IStudentManager extends android .os .IInterface { public static abstract class Stub extends android .os .Binder implements com .golden .aidlserver .IStudentManager { private static final java.lang.String DESCRIPTOR = "com.golden.aidlserver.IStudentManager" ; public Stub () { this .attachInterface(this , DESCRIPTOR); } public static com.golden.aidlserver.IStudentManager asInterface (android.os.IBinder 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 {...} private static class Proxy implements com .golden .aidlserver .IStudentManager { 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; } @Override public java.util.List<com.golden.aidlserver.Student> getStudentList() throws android.os.RemoteException {...} @Override public void addStudent (com.golden.aidlserver.Student student) throws android.os.RemoteException {...} static final int TRANSACTION_getStudentList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0 ); static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1 ); } public java.util.List<com.golden.aidlserver.Student> getStudentList() throws android.os.RemoteException; public void addStudent (com.golden.aidlserver.Student student) throws android.os.RemoteException ; }
该类首先包含了一个抽象内部类:Stub, 该类继承自Binder并实现了IStudentManager接口。在Stub的内部,又包含了一个静态内部类:Proxy,Proxy类同样实现了IStudentManager接口。
Sercvice 接下来创建一个StudentManagerService,需要实现刚刚我们定义的两个方法,并且在AndroidManifest注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class StudentManagerService extends Service { private CopyOnWriteArrayList<Student> mStudentList = new CopyOnWriteArrayList<>(); @Override public void onCreate () { super .onCreate(); mStudentList.add(1 ,"张三" ); } @Override public IBinder onBind (Intent intent) { return new MyBinder(); } class MyBinder extends IStudentManager .Stub { @Override public List<Student> getStudentList () throws RemoteException { return mStudentList; } @Override public void addStudent (Student student) throws RemoteException { mStudentList.add(student); } } }
1 2 3 4 5 6 7 <service android:name =".StudentManagerService" android:process =":remote" > <intent-filter > <action android:name ="com.golden.server.StudentManagerService" /> </intent-filter > </service >
客户端
为了逻辑上区分清晰,另外重新创建一个客户端的应用。需要将服务端的aidl以及Student.java拷贝到客户端注意与服务端的包名保持一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public class ClientMainActivity extends AppCompatActivity { private static final String TAG = "AIDL Client" ; private IStudentManager mRemoteStudentManager; private int size = 1 ; private Button mAddBtn; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_main); mAddBtn = findViewById(R.id.mButton); Intent intent = new Intent(); intent.setComponent(new ComponentName("com.golden.aidlserver" , "com.golden.aidlserver.StudentManagerService" )); bindService(intent, mConnection, BIND_AUTO_CREATE); initView(); } private void initView () { mAddBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick (View v) { try { if (mRemoteStudentManager != null ) { mRemoteStudentManager.addStudent(new Student(size+1 ,"李四" +String.valueOf(size+1 ))); List<Student> studentList = mRemoteStudentManager.getStudentList(); size = studentList.size(); Log.e(TAG,studentList.toString()); } } catch (RemoteException e) { e.printStackTrace(); } } }); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected (ComponentName name, IBinder service) { Log.e(TAG, "onServiceConnected" ); mRemoteStudentManager = IStudentManager.Stub.asInterface(service); } @Override public void onServiceDisconnected (ComponentName name) { Log.e(TAG, "onServiceDisconnected" ); mRemoteStudentManager = null ; } }; }
client中去bindservice
在onServiceConnected()
中得到服务端获得IStudentManager对象mRemoteStudentManager
,可以通过mRemoteStudentManager
来调用服务端service的方法。实现点击button之后服务端添加一个学生然后getStudentList()
打印出来。
Stub 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 public static abstract class Stub extends android .os .Binder implements com .golden .aidlserver .IStudentManager { private static final java.lang.String DESCRIPTOR = "com.golden.aidlserver.IStudentManager" ; public Stub () { this .attachInterface(this , DESCRIPTOR); } public static com.golden.aidlserver.IStudentManager asInterface (android.os.IBinder obj) { if ((obj == null )) { return null ; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null ) && (iin instanceof com.golden.aidlserver.IStudentManager))) { return ((com.golden.aidlserver.IStudentManager) iin); } return new com.golden.aidlserver.IStudentManager.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 { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true ; } case TRANSACTION_getStudentList: { data.enforceInterface(descriptor); java.util.List<com.golden.aidlserver.Student> _result = this .getStudentList(); reply.writeNoException(); reply.writeTypedList(_result); return true ; } case TRANSACTION_addStudent: { data.enforceInterface(descriptor); com.golden.aidlserver.Student _arg0; if ((0 != data.readInt())) { _arg0 = com.golden.aidlserver.Student.CREATOR.createFromParcel(data); } else { _arg0 = null ; } this .addStudent(_arg0); reply.writeNoException(); return true ; } default : { return super .onTransact(code, data, reply, flags); } } static final int TRANSACTION_getStudentList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0 ); static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1 ); }
其中有一个DESCRIPTOR,它在Stub初始化的时候会绑定这个标识符,就是前面曾经提到的安全性方面。
client与server拥有一样的IStudentManager.java文件,在client端我们可以看到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected (ComponentName name, IBinder service) { Log.e(TAG, "onServiceConnected" ); mRemoteStudentManager = IStudentManager.Stub.asInterface(service); } @Override public void onServiceDisconnected (ComponentName name) { Log.e(TAG, "onServiceDisconnected" ); mRemoteStudentManager = null ; } };
我们在 client端中bindservice中在onServiceConnected()会传给我们一个IBinder,这个 IBinder类型的参数是Binder驱动传给我们的,后面在framework的会说到。方法中会去调用 binder.queryLocalInterface() 去查找 Binder 本地对象,如果找到了就说明 Client 和 Server 在同一进程,那么这个 binder 本身就是 Binder 本地对象,可以直接使用。否则说明是 IBinder是个远程对象,也就是 BinderProxy。因此需要我们创建一个代理对象 Proxy,通过这个代理对象来是实现远程访问。
在server端中我们只是创建了stub的对象并且实现了其中定义的两个方法,等待调用onTransact()
方法。
1 2 3 4 5 6 7 8 9 10 11 12 class MyBinder extends IStudentManager .Stub { @Override public List<Student> getStudentList () throws RemoteException { return mStudentList; } @Override public void addStudent (Student student) throws RemoteException { mStudentList.add(student); } }
Proxy 在client中当client 和server处于不同的进程的情况下,client使用的是Proxy对象mRemote。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 private static class Proxy implements com .golden .aidlserver .IStudentManager { 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; } @Override public java.util.List<com.golden.aidlserver.Student> getStudentList() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.util.List<com.golden.aidlserver.Student> _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getStudentList, _data, _reply, 0 ); _reply.readException(); _result = _reply.createTypedArrayList(com.golden.aidlserver.Student.CREATOR); } finally { _reply.recycle(); _data.recycle(); } return _result; } @Override public void addStudent (com.golden.aidlserver.Student student) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((student != null )) { _data.writeInt(1 ); student.writeToParcel(_data, 0 ); } else { _data.writeInt(0 ); } mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0 ); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } }
单独看下 client调用getStudentList()
过程就是 proxy中调用。数据包_data需要将标识符DESCRIPTOR写入,远程调用mRemote.transact(Stub.TRANSACTION_getStudentList, _data, _reply, 0);
(因性能考虑需要将方法以int值来标识),然后server端会调用到stub中的ontranscat()
,最后client中的proxy得到结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Override public boolean onTransact (int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true ; } case TRANSACTION_getStudentList: { data.enforceInterface(descriptor); java.util.List<com.golden.aidlserver.Student> _result = this .getStudentList(); reply.writeNoException(); reply.writeTypedList(_result); return true ; } case TRANSACTION_addStudent: { data.enforceInterface(descriptor); com.golden.aidlserver.Student _arg0; if ((0 != data.readInt())) { _arg0 = com.golden.aidlserver.Student.CREATOR.createFromParcel(data); } else { _arg0 = null ; } this .addStudent(_arg0); reply.writeNoException(); return true ; } default : { return super .onTransact(code, data, reply, flags); } } }
将_result 写入 _replay中返回给客户端。如果是在同一个进程中,就将直接调用stub中的getStudent()
方法不会走transact()
和onTransact()
逻辑。
特别注意的是在mRemote.transact()之后会挂起等待服务端的reply,所以如果是在UI线程中调用并且是耗时操作需要特殊处理。
以上就是一个简单的进程通信的流程,在不同进程的前提下,在理解的时候可以把client的所有操作都是通过proxy来实现,server端就是stub的具体实现。
下一篇会讲framework层源码。
最后更新时间:2019-06-23 12:18:56