在開發(fā)過程中冗懦,實現(xiàn)進程間通信用的最多的就是 AIDL情臭。
AIDL(Android Interface Definition Language)妖枚,也就是接口定義語言运提,提供接口給遠程調用者鳍寂。
當我們定義好 AIDL 文件改含,在編譯時編譯器會幫我們生成代碼實現(xiàn) IPC 通信。為了可以更好的理解Binder的過程迄汛,從AIDL入手捍壤。
服務端
先創(chuàng)建一個服務端骤视,創(chuàng)建一個IStudentManager.aidl
文件,聲明2個方法getStudentList()
以及addStudent()
IStudentManager.aidl
// IStudentManager.aidl
package com.golden.aidlserver;
import com.golden.aidlserver.Student;
// Declare any non-default types here with import statements
interface IStudentManager {
List<Student> getStudentList();
void addStudent(in Student student);
}
IStudentManager.java
Build一下工程,android studio會自動為我們生成一個java類:IStudentManager.java,大體結構如下鹃觉。
package com.golden.aidlserver;
// Declare any non-default types here with import statements
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并實現(xiàn)了IStudentManager接口专酗。在Stub的內部,又包含了一個靜態(tài)內部類:Proxy盗扇,Proxy類同樣實現(xiàn)了IStudentManager接口祷肯。
Sercvice
接下來創(chuàng)建一個StudentManagerService,需要實現(xiàn)剛剛我們定義的兩個方法,并且在AndroidManifest注冊。
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);
}
}
}
<service android:name=".StudentManagerService"
android:process=":remote">
<intent-filter>
<!--是客戶端用于訪問AIDL服務的ID -->
<action android:name="com.golden.server.StudentManagerService" />
</intent-filter>
</service>
客戶端
為了邏輯上區(qū)分清晰疗隶,另外重新創(chuàng)建一個客戶端的應用佑笋。需要將服務端的aidl以及Student.java拷貝到客戶端注意與服務端的包名保持一致
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");
//獲得IStudentManager對象
mRemoteStudentManager = IStudentManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "onServiceDisconnected");
mRemoteStudentManager = null;
}
};
}
client中去bindservice
在onServiceConnected()
中得到服務端獲得IStudentManager對象mRemoteStudentManager
,可以通過mRemoteStudentManager
來調用服務端service的方法。實現(xiàn)點擊button之后服務端添加一個學生然后getStudentList()
打印出來抽减。
Stub
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";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.golden.aidlserver.IStudentManager interface,
* generating a proxy if needed.
*/
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端我們可以看到
//client端
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "onServiceConnected");
//獲得IStudentManager對象
mRemoteStudentManager = IStudentManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "onServiceDisconnected");
mRemoteStudentManager = null;
}
};
我們在 client端中bindservice中在onServiceConnected()會傳給我們一個IBinder颠锉,這個 IBinder類型的參數(shù)是Binder驅動傳給我們的,后面在framework的會說到史汗。方法中會去調用 binder.queryLocalInterface() 去查找 Binder 本地對象琼掠,如果找到了就說明 Client 和 Server 在同一進程,那么這個 binder 本身就是 Binder 本地對象停撞,可以直接使用瓷蛙。否則說明是 IBinder是個遠程對象,也就是 BinderProxy戈毒。因此需要我們創(chuàng)建一個代理對象 Proxy艰猬,通過這個代理對象來是實現(xiàn)遠程訪問。
server端中我們只是創(chuàng)建了stub的對象并且實現(xiàn)了其中定義的兩個方法埋市,等待調用onTransact()
方法冠桃。
//server端
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道宅。
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中調用食听。數(shù)據(jù)包_data需要將標識符DESCRIPTOR寫入,遠程調用mRemote.transact(Stub.TRANSACTION_getStudentList, _data, _reply, 0);
(因性能考慮需要將方法以int值來標識)污茵,然后server端會調用到stub中的ontranscat()
樱报,最后client中的proxy得到結果。
@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()
邏輯。
以上就是一個簡單的進程通信的流程,在不同進程的前提下笤受,在理解的時候可以把client的所有操作都是通過proxy來實現(xiàn)穷缤,server端就是stub的具體實現(xiàn)。
下一篇會講framework層源碼箩兽。