在 Framework 源码解析知识梳理(1) - 应用进程与 AMS 的通讯实现 和 Framework 源码解析知识梳理(2) - 应用进程与 WMS 的通讯实现 这两篇文章中,咱们介绍了应用进程与AMS
以及WMS
之间的通讯实现,可是逻辑仍是比较绕的,为了方便你们更好地理解,咱们介绍一下你们见得比较多的应用进程间通讯的实现。java
提及应用进程之间的通讯,相信你们都不陌生,应用进程之间通讯最经常使用的方式就是AIDL
,下面,咱们先演示一个AIDL
的简单例子,接下来,咱们再分析它的内部实现。android
第一件事,就是服务端须要声明本身能够为客户端提供什么功能,而这一声明则须要经过一个.aidl
文件来实现,咱们先简要介绍介绍一下AIDL
文件:bash
AIDL
文件的后缀为*.aidl
AIDL
默认支持的数据类型,是不须要导入包的,这些默认的数据类型包括:byte/short/int/long/float/double/boolean/char
String/CharSequence
List<T>
:其中T
必须是AIDL
支持的类型,或者是其它AIDL
生成的接口,或者是实现了Parcelable
接口的对象,List
支持泛型Map
:它的要求和List
相似,可是不支持泛型Tag
标签:对于接口方法中的形参,咱们须要用in/out/inout
三种关键词去修饰:in
:表示服务端会收到客户端的完整对象,可是在服务端对这个对象的修改不会同步给客户端out
:表示服务端会收到客户端的空对象,它对这个对象的修改会同步到客户端inout
:表示服务端会收到客户端的完整对象,它对这个对象的修改会同步到客户端说了这么多,咱们最多见的需求无非就是两个:让复杂对象实现Parcelable
接口实现传输以及定义接口方法。app
(1) Parcelable 的实现ide
咱们能够很方便地经过AS
插件来让某个对象实现Parcelable
接口,并自动补全要实现的方法: 函数
public class InObject {
private int inData;
public int getInData() {
return inData;
}
public void setInData(int inData) {
this.inData = inData;
}
}
复制代码
在文件的空白处,点击右键Generate -> Parcelable
: ui
Parcelable
中的接口:
public class InObject implements Parcelable {
private int inData;
public int getInData() {
return inData;
}
public void setInData(int inData) {
this.inData = inData;
}
public InObject() {}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.inData);
}
protected InObject(Parcel in) {
this.inData = in.readInt();
}
public static final Parcelable.Creator<InObject> CREATOR = new Parcelable.Creator<InObject>() {
@Override
public InObject createFromParcel(Parcel source) {
return new InObject(source);
}
@Override
public InObject[] newArray(int size) {
return new InObject[size];
}
};
}
复制代码
(2) 编写 AIDL 文件this
点击File -> New -> AIDL -> AIDL File
以后,会多出一个名叫aidl
的文件夹,以后咱们全部须要用到的aidl
文件都被存放在这里: spa
AS
为咱们生成的
AIDL
文件为:
// AIDLInterface.aidl
package com.demo.lizejun.binderdemoclient;
// Declare any non-default types here with import statements
interface AIDLInterface {
/**
* 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);
}
复制代码
当咱们编译以后,就会在下面这个路径中生成一个Java
文件:插件
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: /home/lizejun/Repository/RepoGithub/BinderDemo/app/src/main/aidl/com/demo/lizejun/binderdemoclient/AIDLInterface.aidl
*/
package com.demo.lizejun.binderdemoclient;
// Declare any non-default types here with import statements
public interface AIDLInterface extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.demo.lizejun.binderdemoclient.AIDLInterface {
private static final java.lang.String DESCRIPTOR = "com.demo.lizejun.binderdemoclient.AIDLInterface";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.demo.lizejun.binderdemoclient.AIDLInterface interface,
* generating a proxy if needed.
*/
public static com.demo.lizejun.binderdemoclient.AIDLInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.demo.lizejun.binderdemoclient.AIDLInterface))) {
return ((com.demo.lizejun.binderdemoclient.AIDLInterface) iin);
}
return new com.demo.lizejun.binderdemoclient.AIDLInterface.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;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.demo.lizejun.binderdemoclient.AIDLInterface {
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();
}
}
}
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
/**
* 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;
}
复制代码
整个结构图为:
asInterface/asBinder/transact/onTransact/Stub/Proxy...
,这个咱们以后再来解释,下面咱们介绍服务端的第二步操做。
既然服务端已经定义好了接口,那么接下来就服务端就须要实现这些接口:
public class AIDLService extends Service {
private final AIDLInterface.Stub mBinder = new AIDLInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
Log.d("basicTypes", "basicTypes");
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
复制代码
在这个Service
中,咱们只须要实现AIDLInterface.Stub
接口中的basicTypes
接口就能够了,它就是咱们在AIDL
文件中定义的接口,再把这个对象经过onBinde
方法返回。
最后一步,在AndroidManifest.xml
文件中声明这个Service
:
<service
android:name=".server.AIDLService"
android:enabled="true"
android:exported="true">
</service>
复制代码
和服务端相似,客户端也须要和服务端同样,生成一个相同的AIDL
文件,这里就很少说了:
// AIDLInterface.aidl
package com.demo.lizejun.binderdemoclient;
// Declare any non-default types here with import statements
interface AIDLInterface {
/**
* 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);
}
复制代码
和服务端相似,咱们也会获得一个由aidl
生成的Java
接口文件。
(1) 绑定服务
private void bind() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.demo.lizejun.binderdemo", "com.demo.lizejun.binderdemo.server.AIDLService"));
boolean result = bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
Log.d("bind", "result=" + result);
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = AIDLInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBinder = null;
}
};
复制代码
(2) 调用接口
public void sayHello(View view) {
try {
if (mBinder != null) {
mBinder.basicTypes(0, 0, false, 0, 0, "aaa");
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
复制代码
以后咱们打印出响应的log
:
下面,咱们就一块儿来分析一下经过AIDL
实现的进程间通讯的原理。
**(1) 客户端得到服务端的远程代理对象 IBinder **
咱们从客户端提及,当咱们在客户端调用了bindService
方法以后,就会启动服务端实现的AIDLService
,而在该AIDLService
的onBind()
方法中返回了AIDLInterface.Stub
的实现类,绑定成功以后,客户端就经过onServiceConnected
的回调,获得了它在客户端进程的远程代理对象IBinder
。
(2) AIDLInterface.Stub.asInterface(IBinder)
在拿到这个IBinder
对象以后,咱们经过AIDLInterface.Stub.asInterface(IBinder)
方法,对这个IBinder
进行了一层包装,转换成为AIDLInterface
接口类,那么这个AIDLInterface
是怎么来的呢,它就是经过咱们在客户端定义的aidl
文件在编译时生成的,能够看到,最终asInterface
方法会返回给咱们一个AIDLInterface
的实现类Proxy
,IBinder
则被保存为它内部的一个成员变量mRemote
。
mBinder
其实是一个由
AIDL
文件所生成的
Proxy
对象。
(3) 调用 AIDLInterface 的接口方法
Proxy
实现了AIDLInterface
中定义的接口方法,当咱们调用它的接口方法时:
mRemote
对象的
transact
方法发送消息:
(4) 服务端接收消息
那么客户端发送的这一消息去哪里了呢,回想一下在服务端中经过onBind()
放回的IBinder
,它实际上是由AIDL
文件生成的AIDLInterface.java
中的内部类Stub
的实现,而在Stub
中有一个回调函数onTransact
,当咱们经过客户端发送消息以后,那么服务端的Stub
对象就会经过onTransact
收到这一发送的消息:
(5) 调用子类的处理逻辑
在onTransact
方法中,又会去调用AIDLInterface
定义的接口:
而咱们在服务端AIDLService
中实现了该接口,所以,最终就打印出了咱们在上面所看到的文字:
如今,咱们经过这一进程间的通讯过程来复习一下前面两篇文章中讨论的应用进程与AMS
和WMS
之间的通讯实现。
在 Framework 源码解析知识梳理(1) - 应用进程与 AMS 的通讯实现 中,AMS
所在进程在收到消息以后,进行了下面的处理逻辑:
onServiceConnected
中作的工做同样,
IApplicationThread
其实是一个
ApplicaionThreadProxy
对象,和咱们上面
AIDLInterface
其实是一个
AIDLInterface.Stub.Proxy
的原理是同样的。当咱们调用了它的接口方法时,就是经过内部的
mRemote
发送了消息。
在AMS
通讯中,接收消息的是应用进程中的ApplicationThread
,而咱们上面例子中接收消息的是服务端进程的AIDLInterface.Stub
的实现类mBinder
,一样是在onTransact()
方法中接收消息,再由子类去实现处理的逻辑。
Framework 源码解析知识梳理(2) - 应用进程与 WMS 的通讯实现 中的原理就更好解释了,由于它就是经过AIDL
来实现的,咱们从客户端向WMS
所在进程创建会话时,是经过IWindowSession
来实现的,会话过程当中IWindowSession
就对应于AIDLInterface
,而WMS
中的IWindowSession.Stub
的实现类Session
,就对应于上面咱们在AIDLService
中定义的AIDLInterface.Stub
的实现类mBinder
。
其实AIDL
并无什么神秘的东西,它的本质就是Binder
通讯,咱们定义aidl
文件的目的,主要有两个:
transact/onTransact
里面的代码,由于这些东西和业务逻辑是无关的,只不过是简单的发送消息、接收消息。若是咱们明白了AIDL
的原理,那么咱们彻底能够不用定义AIDL
文件,本身去参考由AIDL
文件所生成的Java
文件的逻辑,进行消息的发送和处理。