概述
引言
IPC,全称Inter-Process Communication,含义为进程间通信或者跨进程通信,是指两个进程之间进行数据交换的过程。
实现IPC的方法有Socket,Binder,管道等,这篇文章主要介绍Binder,通过AIDL的使用来展开分析。
有关Binder的技术文章,推荐看看下面这篇:
Android中Binder学习
AIDL
定义一个简单的AIDL接口:
interface IBinderListener {
void update(in String str);
}
编译后,会在app/build/generated/source/aidl下生成一个IBinderListener.java的类
/**
* {@hide}
*/
public interface IBinderListener extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.test.bindercserver.IBinderListener
{
private static final java.lang.String DESCRIPTOR = "com.test.bindercserver.IBinderListener";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.test.bindercserver.IBinderListener interface,
* generating a proxy if needed.
*/
public static com.test.bindercserver.IBinderListener asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.test.bindercserver.IBinderListener))) {
return ((com.test.bindercserver.IBinderListener)iin);
}
return new com.test.bindercserver.IBinderListener.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_update:
{
data.enforceInterface(descriptor);
java.lang.String _arg0;
_arg0 = data.readString();
this.update(_arg0);
reply.writeNoException();
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.test.bindercserver.IBinderListener
{
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 update(java.lang.String str) 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.writeString(str);
mRemote.transact(Stub.TRANSACTION_update, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_update = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void update(java.lang.String str) throws android.os.RemoteException;
}
Android studio会帮我们生成这个文件,使用的时候只需要继承IBinderListener.Stub这个抽象类,在Service的onBinder()方法里面返回它,就实现了AIDL。
AIDL过程分析
主要分析一下aidl的实现过程,不依赖Android studio的编译自动生成,而是自己手动敲出接口的java文件。
首先定义接口文件
import android.os.IBinder;
import android.os.IInterface;
public interface IJustKidding extends IInterface{
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
public int add(int a, int b) throws android.os.RemoteException;
public int sub(int a, int b) throws android.os.RemoteException;
static final int TRANSACTION_add = IBinder.FIRST_CALL_TRANSACTION;
static final int TRANSACTION_sub = IBinder.FIRST_CALL_TRANSACTION + 1;
static final String DESCRIPTOR = "com.test.BinderTest.IJustKidding";
}
add(int a, int b)和sub(int a, int b)是IJustKidding接口里面的两个方法,TRANSACTION_add 和TRANSACTION_sub 分别代表两个方法在接口文件中的排列顺序,DESCRIPTOR 作为接口的描述符。
接下来敲aidl的实现过程
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
public abstract class JustKiddingNative extends Binder implements IJustKidding {
//JustKiddingNative相当于IJustKidding.Stub
public JustKiddingNative(){
this.attachInterface(this, IJustKidding.DESCRIPTOR);
}
public static IJustKidding asInterface(IBinder obj){
if (obj == null){
return null;
}
//通过接口标识符DESCRIPTOR到本地查找
IInterface iInterface = obj.queryLocalInterface(IJustKidding.DESCRIPTOR);
if (iInterface != null && iInterface instanceof IJustKidding){
Log.d("***", "same process");
//相同进程,直接返回
return (IJustKidding) iInterface;
}
Log.d("***", "different process");
//不同进程,返回代理类IJustKiddingProxy
return new IJustKiddingProxy(obj);
}
//来自接口IJustKidding类的父类IInterface
@Override
public IBinder asBinder(){
return this;
}
//onTransact()方法运行在服务端
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Log.d("***", "Stub --> onTransact()");
int arg0;
int arg1;
int result;
switch (code){
case INTERFACE_TRANSACTION:
reply.writeString(IJustKidding.DESCRIPTOR);
return true;
case TRANSACTION_add:
Log.d("***", "Stub --> onTransact() TRANSACTION_add");
data.enforceInterface(IJustKidding.DESCRIPTOR);
arg0 = data.readInt();
arg1 = data.readInt();
result = this.add(arg0, arg1);
Log.d("***", "Stub --> onTransact() TRANSACTION_add result = " + result);
reply.writeNoException();
reply.writeInt(result);
return true;
case TRANSACTION_sub:
Log.d("***", "Stub --> onTransact() TRANSACTION_sub");
data.enforceInterface(IJustKidding.DESCRIPTOR);
arg0 = data.readInt();
arg1 = data.readInt();
result = this.sub(arg0, arg1);
Log.d("***", "Stub --> onTransact() TRANSACTION_sub result = " + result);
reply.writeNoException();
reply.writeInt(result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
//IJustKidding的代理类,实现了IJustKidding接口
class IJustKiddingProxy implements IJustKidding{
private IBinder mRemote;
IJustKiddingProxy(IBinder iBinder){
mRemote = iBinder;
}
//来自接口IJustKidding类的父类IInterface
@Override
public IBinder asBinder() {
return mRemote;
}
//接口描述符
public String getInterfaceDescriptor() {
return IJustKidding.DESCRIPTOR;
}
@Override
public int add(int a, int b) throws RemoteException {
Log.d("***", "Proxy --> add()");
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(IJustKidding.DESCRIPTOR);
Log.d("***", "Proxy --> add() --> writeInt()");
_data.writeInt(a);
_data.writeInt(b);
Log.d("***", "Proxy --> add() --> mRemote.transact()");
mRemote.transact(TRANSACTION_add, _data, _reply, 0);
Log.d("***", "Proxy --> add() --> _reply.readException()");
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
Log.d("***", "Proxy --> add() --> _result = " + _result);
return _result;
}
@Override
public int sub(int a, int b) throws RemoteException {
Log.d("***", "Proxy --> sub()");
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(IJustKidding.DESCRIPTOR);
Log.d("***", "Proxy --> sub() --> writeInt()");
_data.writeInt(a);
_data.writeInt(b);
Log.d("***", "Proxy --> sub() --> mRemote.transact()");
mRemote.transact(TRANSACTION_sub, _data, _reply, 0);
Log.d("***", "Proxy --> sub() --> _reply.readException()");
_reply.readException();
_result = _reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
Log.d("***", "Proxy --> sub() --> _result = " + _result);
return _result;
}
}
服务端口的代码就更简单了:
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class JustKiddingService extends Service {
public JustKiddingService() {}
//JustKiddingNative相当于IJustKidding.Stub
private final JustKiddingNative mBinder = new JustKiddingNative() {
@Override
public int add(int a, int b) throws RemoteException {
Log.d("***", "JustKiddingService IJustKiddingInterface.Stub --> add()");
return a + b;
}
@Override
public int sub(int a, int b) throws RemoteException {
Log.d("***", "JustKiddingService IJustKiddingInterface.Stub --> sub()");
return a - b;
}
};
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.d("***", "JustKiddingService --> onBind()");
return mBinder;
}
}
客户端重点部分的代码:
private IBinder mPlusBinder;
private IJustKidding iJustKidding;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.d("***", "onServiceConnected() componentName = " + componentName
+ " iBinder = " + iBinder);
mPlusBinder = iBinder;
try {
iBinder.linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.d("***", "onServiceDisconnected() componentName = " + componentName);
mPlusBinder = null;
iJustKidding = null;
}
};
IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (iJustKidding == null){
return;
}
iJustKidding.asBinder().unlinkToDeath(deathRecipient, 0);
iJustKidding = null;
bindService();
}
};
public void bindService(){
Intent intent = new Intent(this, JustKiddingService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}
//客户端调用add()和sub()方法
if (mPlusBinder != null){
try {
iJustKidding = JustKiddingNative.asInterface(mPlusBinder);
if (iJustKidding != null) {
int add = iJustKidding.add(2, 1);
int sub = iJustKidding.sub(2, 1);
Log.d("***", "add = " + add + " sub = " + sub);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
调用bindService()后,会在ServiceConnection对象的onServiceConnected()方法中回调,返回IBInder对象,可以理解为IJustKidding接口的句柄,是由驱动返回的。
然后调用JustKiddingNative.asInterface(mPlusBinder)方法(这里的JustKiddingNative相当于IJustKidding.Stub),将IBInder句柄转换为本地对象或代理对象。
public static IJustKidding asInterface(IBinder obj){
if (obj == null){
return null;
}
IInterface iInterface = obj.queryLocalInterface(IJustKidding.DESCRIPTOR);
if (iInterface != null && iInterface instanceof IJustKidding){
Log.d("***", "same process");
return (IJustKidding) iInterface;
}
Log.d("***", "different process");
return new IJustKiddingProxy(obj);
}
根据IBinder的obj对象,现在本地查找,如果能找到,就强制转换为IJustKidding对象,然后返回;如果不能找到,就返回接口的代理对象IJustKiddingProxy,传参obj。
分别设置JustKiddingService服务为相同进程和不同进程,抓取日志,分析流程。
设置不同进程,只需要在标签中增加android:process=":remote"属性值,进程名remote可以自己取。
不同进程:
2021-07-12 09:38:04.846 31620-31620/com.Test D/djw: BinderTestActivity --> bindService()
2021-07-12 09:38:05.162 31724-31724/? D/djw: JustKiddingService --> onBind()
2021-07-12 09:38:05.165 31620-31620/com.Test D/djw: onServiceConnected() componentName = ComponentInfo{com.Test/com.test.BinderTest.JustKiddingService} iBinder = android.os.BinderProxy@a208bfb
2021-07-12 09:39:10.403 31620-31620/com.Test D/djw: different process
2021-07-12 09:39:10.404 31620-31620/com.Test D/djw: Proxy --> add()
2021-07-12 09:39:10.404 31620-31620/com.Test D/djw: Proxy --> add() --> writeInt()
2021-07-12 09:39:10.404 31620-31620/com.Test D/djw: Proxy --> add() --> mRemote.transact()
2021-07-12 09:39:10.405 31724-31737/com.Test:remote D/djw: Stub --> onTransact()
2021-07-12 09:39:10.405 31724-31737/com.Test:remote D/djw: Stub --> onTransact() TRANSACTION_add
2021-07-12 09:39:10.405 31724-31737/com.Test:remote D/djw: JustKiddingService IJustKiddingInterface.Stub --> add()
2021-07-12 09:39:10.405 31724-31737/com.Test:remote D/djw: Stub --> onTransact() TRANSACTION_add result = 3
2021-07-12 09:39:10.406 31620-31620/com.Test D/djw: Proxy --> add() --> _reply.readException()
2021-07-12 09:39:10.406 31620-31620/com.Test D/djw: Proxy --> add() --> _result = 3
2021-07-12 09:39:10.406 31620-31620/com.Test D/djw: Proxy --> sub()
2021-07-12 09:39:10.406 31620-31620/com.Test D/djw: Proxy --> sub() --> writeInt()
2021-07-12 09:39:10.406 31620-31620/com.Test D/djw: Proxy --> sub() --> mRemote.transact()
2021-07-12 09:39:10.406 31724-31737/com.Test:remote D/djw: Stub --> onTransact()
2021-07-12 09:39:10.406 31724-31737/com.Test:remote D/djw: Stub --> onTransact() TRANSACTION_sub
2021-07-12 09:39:10.407 31724-31737/com.Test:remote D/djw: JustKiddingService IJustKiddingInterface.Stub --> sub()
2021-07-12 09:39:10.407 31724-31737/com.Test:remote D/djw: Stub --> onTransact() TRANSACTION_sub result = 1
2021-07-12 09:39:10.407 31620-31620/com.Test D/djw: Proxy --> sub() --> _reply.readException()
2021-07-12 09:39:10.408 31620-31620/com.Test D/djw: Proxy --> sub() --> _result = 1
2021-07-12 09:39:10.408 31620-31620/com.Test D/djw: add = 3 sub = 1
日志第一行和第二行,可以知道调用方和JustKiddingService不在同一进程,第五行的日志different process也能说明它们不在同一进程;
调用binderServer()之后,JustKiddingService服务的onBind()会被调用,返回接口的IBinder对象。
调用JustKiddingNative.asInterface(mPlusBinder)时,返回的是IJustKiddingProxy代理对象,add()里面_data写入接口描述符和参数数据,再调用mRemote.transact(TRANSACTION_add, _data, _reply, 0)方法,mRemote是驱动返回的IBInder句柄。
_data数据被Parcel序列化之后,经过Native、驱动,进入内核态,挂起等待返回。驱动完成一系列操作之后,唤醒Server进程,调用Server进程本地对象的onTransact方法(onTransact()方法运行在Server端),然后根据方法在接口中的顺序标识符识别到相应的方法,鉴别接口描述符,取出对应参数进行计算,调用到JustKiddingService里面JustKiddingNative实例对象的add()方法,计算完成返回结果,由replyParcel序列化后,返回结果到调用端,这样就完成了一次跨进程调用。
这里涉及到Binder驱动的流程,没有展开来讲解,有兴趣的可以看看文章开头提到的技术文章。
同一进程
2021-07-12 11:52:29.256 3615-3615/com.Test D/djw: BinderTestActivity --> bindService()
2021-07-12 11:52:29.279 3615-3615/com.Test D/djw: JustKiddingService --> onBind()
2021-07-12 11:52:29.359 3615-3615/com.Test D/djw: onServiceConnected() componentName = ComponentInfo{com.Test/com.test.BinderTest.JustKiddingService} iBinder = com.szzt.test.BinderTest.JustKiddingService$1@6b50a0b
2021-07-12 11:52:32.437 3615-3615/com.Test D/djw: same process
2021-07-12 11:52:32.438 3615-3615/com.Test D/djw: JustKiddingService IJustKiddingInterface.Stub --> add()
2021-07-12 11:52:32.438 3615-3615/com.Test D/djw: JustKiddingService IJustKiddingInterface.Stub --> sub()
2021-07-12 11:52:32.438 3615-3615/com.Test D/djw: add = 3 sub = 1
相同进程的情况下,直接调用到JustKiddingService里面JustKiddingNative实例对象的add()方法。
至此,aidl调用流程分析完成。
最后
以上就是唠叨狗为你收集整理的Android binder学习笔记(一)AIDL流程分析的全部内容,希望文章能够帮你解决Android binder学习笔记(一)AIDL流程分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复