1.AIDL的简介
AIDL (Android Interface Definition Language) 是一种接口定义语言,用于生成可以在Android设备上两个进程之间进行进程间通信(Interprocess Communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数,来完成进程间通信。
AIDL能够实现进程间通信,其内部是通过Binder机制来实现的
AIDL支持的数据类型:
- Java 编程语言中的所有基本数据类型(如 int、long、char、boolean 等等)
- String和CharSequence
- Parcelable:实现了Parcelable接口的对象
- List:其中的元素需要被AIDL支持,另一端实际接收的具体类始终是
- ArrayList,但生成的方法使用的是 List 接口
- Map:其中的元素需要被AIDL支持,包括key和value,另一端实际接收的具体类始终 是 HashMap,但生成的方法使用的是 Map 接口
其他注意事项:
- 在AIDL中传递的对象,必须实现Parcelable序列化接口;
- 在AIDL中传递的对象,需要在类文件相同路径下,创建同名、但是后缀为.aidl的文件,并在文件中使用parcelable关键字声明这个类;
- 跟普通接口的区别:只能声明方法,不能声明变量;
- 所有非基础数据类型参数都需要标出数据走向的方向标记。可以是 in、out 或 inout,基础数据类型默认只能是 in,不能是其他方向。
2.AIDL的使用
下面是项目的目录结构
其中在aidl文件下创建相同的包结构,在bean目录下创建和实体类一样的aidl文件,并用 parcelable关键字声明这个类
package com.kx.studyview.aidl.bean;
parcelable MessageModel ;
MessageReceiver,用于实现服务端传递给客户端消息的监听,类似接口回调的方式。
package com.kx.studyview.aidl;
import com.kx.studyview.aidl.bean.MessageModel ;
interface MessageReceiver {
void onMessageReceived(in MessageModel receivedMessage);
}
MessageSender,主要用于实现客户端与服务端的交互
// MessageSender.aidl
package com.kx.studyview.aidl;
import com.kx.studyview.aidl.bean.MessageModel ;
import com.kx.studyview.aidl.MessageReceiver ;
interface MessageSender {
void sendMessage(in MessageModel messageModel);
void registerReceiveListener(MessageReceiver messageReceiver);
void unregisterReceiveListener(MessageReceiver messageReceiver);
}
在Build之后,系统会为我们生成MessageSender.java文件
public interface MessageSender extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.kx.studyview.aidl.MessageSender {
// 代表当前Binder的唯一标识,一般为完整路径
private static final java.lang.String DESCRIPTOR = "com.kx.studyview.aidl.MessageSender";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
将服务端的Binder对象转换为客户端所需要的的AIDL接口类型对象,如果客户端和服务端位于同一进
程,则返回服务端的Stub对象本身,当两者处于不同进程时,返回的是系统封装后的Stub.proxy对象
public static com.kx.studyview.aidl.MessageSender asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.kx.studyview.aidl.MessageSender))) {
return ((com.kx.studyview.aidl.MessageSender) iin);
}
return new com.kx.studyview.aidl.MessageSender.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_sendMessage: {
data.enforceInterface(DESCRIPTOR);
com.kx.studyview.aidl.bean.MessageModel _arg0;
if ((0 != data.readInt())) {
_arg0 = com.kx.studyview.aidl.bean.MessageModel.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.sendMessage(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_registerReceiveListener: {
data.enforceInterface(DESCRIPTOR);
com.kx.studyview.aidl.MessageReceiver _arg0;
_arg0 = com.kx.studyview.aidl.MessageReceiver.Stub.asInterface(data.readStrongBinder());
this.registerReceiveListener(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_unregisterReceiveListener: {
data.enforceInterface(DESCRIPTOR);
com.kx.studyview.aidl.MessageReceiver _arg0;
_arg0 = com.kx.studyview.aidl.MessageReceiver.Stub.asInterface(data.readStrongBinder());
this.unregisterReceiveListener(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
不在一个进程时返回的代理
private static class Proxy implements com.kx.studyview.aidl.MessageSender {
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 void sendMessage(com.kx.studyview.aidl.bean.MessageModel messageModel) 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 ((messageModel != null)) {
_data.writeInt(1);
messageModel.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_sendMessage, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void registerReceiveListener(com.kx.studyview.aidl.MessageReceiver messageReceiver) 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.writeStrongBinder((((messageReceiver != null)) ? (messageReceiver.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_registerReceiveListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void unregisterReceiveListener(com.kx.studyview.aidl.MessageReceiver messageReceiver) 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.writeStrongBinder((((messageReceiver != null)) ? (messageReceiver.asBinder()) : (null)));
mRemote.transact(Stub.TRANSACTION_unregisterReceiveListener, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
用于区分不同方法名的 code
static final int TRANSACTION_sendMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_registerReceiveListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_unregisterReceiveListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
}
public void sendMessage(com.kx.studyview.aidl.bean.MessageModel messageModel) throws android.os.RemoteException;
public void registerReceiveListener(com.kx.studyview.aidl.MessageReceiver messageReceiver) throws android.os.RemoteException;
public void unregisterReceiveListener(com.kx.studyview.aidl.MessageReceiver messageReceiver) throws android.os.RemoteException;
}
其中Stub 的 onTransact() 运行在服务端的Binder线程池中,当客户端发起请求时,服务端根据code可以确定客户端所请求的目标方法时什么。
Proxy#sendMessage
@Override
public void sendMessage(com.kx.studyview.aidl.bean.MessageModel messageModel) 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 ((messageModel != null)) {
_data.writeInt(1);
messageModel.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_sendMessage, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
首先创建此方法的所需的输入型对象_data 和输出型对象_reply,然后将messageModel信息序列化写入_data中(如果messageModel不为空), _data.writeInt(1)和_data.writeInt(0)用于在Stub 的 onTransact()方法中判断是否进行反序列化。接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起。
mRemote.transact(Stub.TRANSACTION_sendMessage, _data, _reply, 0);
然后服务端的onTransact方法会被调用。根据不同的code区分不同的方法,
case TRANSACTION_sendMessage: {
data.enforceInterface(DESCRIPTOR);
com.kx.studyview.aidl.bean.MessageModel _arg0;
if ((0 != data.readInt())) {
_arg0 = com.kx.studyview.aidl.bean.MessageModel.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.sendMessage(_arg0);
reply.writeNoException();
return true;
}
当 data.writeInt(1)时,进行反序列化操作,生成与客户端发送消息内容一样的对象(不同的对象,内容一样),data.writeInt(0)时,返回空,代表客户端发送的是null。
_arg0 = com.kx.studyview.aidl.bean.MessageModel.CREATOR.createFromParcel(data);
反序列化完成后,调用sendMessage方法,这个方法的实现是在服务端
this.sendMessage(_arg0);
在定义接口方法时,主要的执行过程都是一样的,只不过区别在于定义的方法是否有返回值,是否有参数之分。当有返回值的时候,就会向onTransact参数中的reply对象写入返回值。有参数的时候,就会从data中的取出目标所需的参数。
void sendMessage(in MessageModel messageModel);
void registerReceiveListener(MessageReceiver messageReceiver);
void unregisterReceiveListener(MessageReceiver messageReceiver);
如果onTransact方法返回false,则客户端的请求就会失败,我们可以利用这个特性来做权限验证,因为我们也不希望随便一个进程都能远程调用我们的服务。
包名验证
/**
* 包名验证方式
*/
String packageName = null;
String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
if (packages != null && packages.length > 0) {
packageName = packages[0];
}
if (packageName == null || !packageName.startsWith("com.kx.studyview.aidl")) {
LogUtils.e("MessageService 进程onTransact " + "拒绝调用:" + packageName);
return false;
}
权限验证
// 在AndroidManifest中自定义的权限
if(checkCallingOrSelfPermission("com.kx.studyview.aidl.permission.REMOTE_SERVICE_PERMISSION") == PackageManager.PERMISSION_DENIED) {
return false;
}