从AIDL来看Binder的通信原理(基于Andorid8(1)

}

return new com.rikkatheworld.aidl_demo.IUserManager.Stub.Proxy(obj);

}

可以看出调用了 queryLocalInterface()获得一个 IInterface类型的对象iin,如果iin不为空,则返回iin,如果为空,则 new一个 Proxy类并返回。

我们知道AMS给我们返回的一定是Binder的对象,所以我们去 Binder中看看queryLocalInterface()

// Binder.java

public class Binder implements IBinder {

// 1

public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {

if (mDescriptor != null && mDescriptor.equals(descriptor)) {

return mOwner;

}

return null;

}

}

// 2

final class BinderProxy implements IBinder {

// 3

public IInterface queryLocalInterface(String descriptor) {

return null;

}

}

可以发现Binder文件中,有两处实现了这个方法,在Binder类中。

注释1中 通过 descriptor标识来返回,mOwner是Bidner本身。

注释2、3是 BinderProxy实现的,直接返回一个空。

在Stub类的构造方法里我们就看到了只要Stub被构建就会调用:

public Stub() {

this.attachInterface(this, DESCRIPTOR);

}

按理来说,queryLocalInterface不可能返回为空,我们应该都是得到一个正宗的 Stub类才对,但是实际上这里出现了偏出。

在跨进程服务中,我们通过 asInterface() 返回的是一个 IUserManager.Stub.Proxy的对象。这就说明 queryLocalInterface()返回了空,只有一种情况会导致这种结果, 那就是 ServiceConnection返回来的值是一个 BinderProxy类型的对象。

这就是我最开始的疑问点,为什么 onServiceConnection()中远端进程和同进程下返回的是Binder,而不同进程下返回的是BinderProxy

2.2 BindService 客户端进程传出流程


Binder机制是C/S架构,任意两个进程,请求方是C端,接收方是S端

C端通过 BpBinder来访问S端,S端通过 BBinder来访问C端,而BpProxy就是BpBinder的封装类。他们的具体知识这里就不再赘述了。详情请看皇叔的文章。下面以框架层角度画个图来看下 客户端进程的数据传出经过了什么方法:

在这里插入图片描述

万物的开端在于BindService,在 Service的startService和bindService源码流程中,我们知道主进程的最终代码是到 ContextImpl.bindServiceCommon()

// ContextImpl.java

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler

handler, UserHandle user) {

IServiceConnection sd;

if (mPackageInfo != null) {

sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);

} else {

throw new RuntimeException(“Not supported in system context”);

}

try {

IBinder token = getActivityToken();

int res = ActivityManager.getService().bindService(

mMainThread.getApplicationThread(), getActivityToken(), service,

service.resolveTypeIfNeeded(getContentResolver()),

sd, flags, getOpPackageName(), user.getIdentifier());

} …

}

// ActivityManager

public static IActivityManager getService() {

return IActivityManagerSingleton.get();

}

private static final Singleton IActivityManagerSingleton =

new Singleton() {

@Override

protected IActivityManager create() {

final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);

final IActivityManager am = IActivityManager.Stub.asInterface(b);

return am;

}

};

ActivityManager.getService()是 IActivityManager.Stub.asInterface(b),这个肯定是Proxy类(套娃了,不过问题不大),我们要来看看bindService做了什么,由于IActivityManager是编译产生的,所以我暂时还没有找到IActivityManager,但是我们知道 它的实现肯定和我们自己所编译出来的如出一辙,甚至我们自己都可以写出来:

// 这个地方是照着 IUserManger.Stub.Proxy 仿写的,也看了开篇Blog的内容

// IActivityManager.Stub.Proxy

@Override

public int bindService(IApplicationThread caller, IBinder token,

Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) throws android.os.RemoteException {

android.os.Parcel _data = android.os.Parcel.obtain(); // 1

android.os.Parcel _reply = android.os.Parcel.obtain(); // 2

int _result;

try {

_data.writeInterfaceToken(DESCRIPTOR);

_data.writeStrongBinder(caller != null ? caller.asBinder() : null); // 3

_data.writeStrongBinder(token); // 4

service.writeToParcel(data, 0);

_data.writeString(resolvedType);

_data.writeStrongBinder(connection.asBinder()); // 5

_data.writeInt(flags);

_data.writeInt(userId);

mRemote.transact(TRANSACTION_bindService, data, reply, 0); // 6

reply.readException();

_result = reply.readInt(); // 7

} finally {

_reply.recycle();

_data.recycle();

}

return _result;

}

注释1:获得一个传出去的序列化数据 data

注释2:获得一个用于接收的序列化数据 reply

注释3、4、5: 通过 writeStrongBinder()把 Binder数据写入到 data中

注释6:调用原生层的 transact(),传入数据

注释7:在返回结果reply读出数据result

其中,注释3、4、5、6是这个方法的关键。就是参数是这么从客户端进程传出去的。

我们来看看 writeStrongBinder(),它是一个native方法:

// frameworks/base/core/jni/android_os_Parcel.cpp

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)

{

Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);

if (parcel != NULL) {

const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));

if (err != NO_ERROR) {

signalExceptionForError(env, clazz, err);

}

}

}

这里调用了两个函数, 一个是调用了 ibindForJavaObject得到一个IBinder,在传入到 Parcel->writeStrongBinder()中:

先来看看前者

// frameworks/base/core/jni/android_os_Parcel.cpp

sp ibinderForJavaObject(JNIEnv* env, jobject obj)

{

if (obj == NULL) return NULL;

if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {

JavaBBinderHolder* jbh = (JavaBBinderHolder*)

env->GetLongField(obj, gBinderOffsets.mObject);

return jbh != NULL ? jbh->get(env, obj) : NULL; // 1

}

if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {

return (IBinder*)

env->GetLongField(obj, gBinderProxyOffsets.mObject); // 2

}

return NULL;

}

注释1:如果传进来的binder是 gBinderOffsets,则 new一个 JavaBBinder并返回。

注释2:如果传进来的bind是 gBinderProxyOffsets(代理类),类中的 代理对象。(也就是封装在里面了,取出来用)

由于我们是客户端进程,所以进来的并不是代理类,所以 ibinderForJavaObject()会返回一个 JavaBBinder返回给我们。

再来看看 Parcel.writeStrongBinder():

// frameworks\native\libs\binder\Parcel.cpp

status_t Parcel::writeStrongBinder(const sp& val)

{

return flatten_binder(ProcessState::self(), val, this);

}

status_t flatten_binder(const sp& /proc/,

const sp& binder, Parcel* out)

{

if (binder != NULL) {

IBinder *local = binder->localBinder(); // 1

if (!local) {

BpBinder *proxy = binder->remoteBinder();

if (proxy == NULL) {

ALOGE(“null proxy”);

}

const int32_t handle = proxy ? proxy->handle() : 0;

obj.type = BINDER_TYPE_HANDLE;

obj.binder = 0; /* Don’t pass uninitialized stack data to a remote process */

obj.handle = handle;

obj.cookie = 0;

} else {

obj.type = BINDER_TYPE_BINDER; // 2

obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());

obj.cookie = reinterpret_cast<uintptr_t>(local);

}

} else {

obj.type = BINDER_TYPE_BINDER;

obj.binder = 0;

obj.cookie = 0;

}

return finish_flatten_binder(binder, obj, out);

}

inline static status_t finish_flatten_binder(

const sp& /binder/, const flat_binder_object& flat, Parcel* out)

{

return out->writeObject(flat, false);

}

在writeStrongBinder中调用了 flatten_binder()

注释1:localBinder()是取出Binder中的数据,用来标识传入Binder的进程是否是当前进程,所以local不为null,会走到else中去

注释2:设置 type为 BIND_TYPE_BINDER

最后把这些数据写到输出数据中。也就是一开始我们的 _data。

接下来看下 mRemote.transact()这个方法,mRemote是 ServiceManager返回给我们的,它是一个 BinderProxy对象,所以会调用 BinderProxy.transact()

// Binder.java

// BinderProxy ->

public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {

try {

return transactNative(code, data, reply, flags);

} …

}

调用了 native层的 transactNative()

// android_util_Binder.cpp

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,

jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException

{

Parcel* data = parcelForJavaObject(env, dataObj); // 1

Parcel* reply = parcelForJavaObject(env, replyObj); // 2

IBinder* target = (IBinder*)

env->GetLongField(obj, gBinderProxyOffsets.mObject); // 3

status_t err = target->transact(code, *data, reply, flags); // 4

}

注释1、2:通过 parcelForJavaObject() 把 Java层的Parce -> Natve层的Parcel,data是参数数据,reply是结果数据

注释3:把 java层的 ActivityManagerService的 BinderProxy 转换成 Native层的 BpBinder

注释4:调用 BpBinder.transact()

到这里我就不往下说了,BpBinder会调用 IPCThreadState.transact()writeData()talkWithDriver()waitForResponse()等方法去深入到 Kernel层的Binder,具体请看: Android Binder原理(三)系统服务的注册过程,里面写了一个系统服务注册到ServiceManager的过程,其中就有上述接下来的过程。

这样我们的Binder数据就从客户端进程传出去了。

2.3 ActivityManagerService接收数据


如果一个支持Binder通信的进程被创建后,它会开启一条线程加入到Binder线程池中,并通过 joinThreadPool()开启死循环,读 Binder驱动中的 BR_TRANSACTION(因为客户端进程传入的是 BC_TRANSACTION)命令,具体可以看 《Android进阶解密》第三章 应用程序进程的创建。

// IPCThreadState.cpp

void IPCThreadState::joinThreadPool(bool isMain)

{

do {

result = getAndExecuteCommand();

} while (result != -ECONNREFUSED && result != -EBADF);

talkWithDriver(false);

}

可以看到在死循环中不断调用 getAndExecuteCommand()

status_t IPCThreadState::getAndExecuteCommand()

{

result = talkWithDriver();

if (result >= NO_ERROR) {

size_t IN = mIn.dataAvail();

if (IN < sizeof(int32_t)) return result;

cmd = mIn.readInt32();

result = executeCommand(cmd);

}

return result;

}

// IPCThreadState.cpp

status_t IPCThreadState::talkWithDriver(bool doReceive)

{

if (mProcess->mDriverFD <= 0) {

return -EBADF;

}

//和Binder驱动通信的结构体

binder_write_read bwr; //1

//mIn是否有可读的数据,接收的数据存储在mIn

const bool needRead = mIn.dataPosition() >= mIn.dataSize();

const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

bwr.write_size = outAvail;

bwr.write_buffer = (uintptr_t)mOut.data();//2

//这时doReceive的值为true

if (doReceive && needRead) {

bwr.read_size = mIn.dataCapacity();

bwr.read_buffer = (uintptr_t)mIn.data();//3

} else {

bwr.read_size = 0;

bwr.read_buffer = 0;

}

if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

bwr.write_consumed = 0;

bwr.read_consumed = 0;

status_t err;

do {

IF_LOG_COMMANDS() {

alog << "About to read/write, write size = " << mOut.dataSize() << endl;

}

#if defined(ANDROID)

if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)//4

err = NO_ERROR;

else

err = -errno;

#else

err = INVALID_OPERATION;

#endif

} while (err == -EINTR);

return err;

}

talkWithDriver() 就是通过 ioctl读取有没有想要的BR数据,有就响应,调用 executeCommand()

status_t IPCThreadState::executeCommand(int32_t cmd)

{

BBinder* obj;

RefBase::weakref_type* refs;

status_t result = NO_ERROR;

switch ((uint32_t)cmd) {

case BR_TRANSACTION:

{

binder_transaction_data tr; // 1

result = mIn.read(&tr, sizeof(tr)); // 2

Parcel buffer;

buffer.ipcSetDataReference(

reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),

tr.data_size,

reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),

tr.offsets_size/sizeof(binder_size_t), freeBuffer, this); // 3

Parcel reply;

status_t error;

if (tr.target.ptr) {

if (…) {

error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,

&reply, tr.flags); // 4

}

} …

}

break;

return result;

}

这里只要截取 BR_TRANSACTION,因为客户端进程发的是 BC_TRANSATION

注释1:创建 binder_transaction_data 结构体的对象tr,它是IPCThread专用的 Parcel包, 在客户端进程的IPCThreadState调用transact时也是用这个类型

注释2:mIn是Binder驱动的读到的Parcel数据,通过 read()方法把这些数据写入到 tr中

注释3:通过写好的数据重新构造一个 Parcel包。(把它修改成AMS用的包)

注释4:调用 BBinder.transact(),这里的 BBinder是指 ActivityManagerService在Service端的对象,也就是自己。最后会调用自己的 onTransact(),会调用父类也就是 IActivityManager.onTransact()

IActivityManager对 onTransact应该是对 TRANSACTION_bindService()case处理,虽然我们没有 IActivityManager这个类,但是我们通过 IUserManager文件,可以仿写一份 IActivityManager的代码:

// 跟IActivityManager.Stub.Proxy类一样, 根据 IUserManager 仿写 IActivityManager.Stub.onTransact(),

// 代码参照开篇Blog,即Android7.0 的Binder返回的处理

@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 TRANSACTION_bindService: {

data.enforceInterface(descriptor);

IBinder b = data.readStrongBinder(); // 1

IApplicationThread app = ApplicationThreadNative.asInterface(b);

IBinder token = data.readStrongBinder();

Intent service = Intent.CREATOR.createFromParcel(data);

String resolvedType = data.readString();

b = data.readStrongBinder();

IServiceConnection conn = IServiceConnection.Stub.asInterface(b);

int fl = data.readInt();

int userId = data.readInt();

int res = bindService(app, token, service, resolvedType, conn, fl, userId); // 5

reply.writeNoException();

reply.writeInt(res);

return true;

}

default: {

return super.onTransact(code, data, reply, flags);

}

}

}

在拿到 natvie层的Pacel包后,进行拆包。

注释1-2前:通过readString() 、readInt()、 readStrongBinder()拆包,怎么装包的就怎么拆包

注释2:执行 ActivityManagerService.bindService(),正式开启 AMS之旅。

我们来看看解包的一个方法 readStrongBinder(),它和装包的 writeStrongBinder()对应:

// Parcel.cpp

status_t Parcel::readStrongBinder(sp* val) const

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
readStrongBinder()拆包,怎么装包的就怎么拆包

注释2:执行 ActivityManagerService.bindService(),正式开启 AMS之旅。

我们来看看解包的一个方法 readStrongBinder(),它和装包的 writeStrongBinder()对应:

// Parcel.cpp

status_t Parcel::readStrongBinder(sp* val) const

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-OqkeG3ch-1715840233117)]

[外链图片转存中…(img-YQ7IMtVa-1715840233118)]

[外链图片转存中…(img-vxfDF9HA-1715840233118)]

[外链图片转存中…(img-ZTEP7Y31-1715840233119)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值