欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android的进程间通信(六)之 Binder的客户端发送数据到服务端的流程

程序员文章站 2022-03-12 21:33:39
上一篇文章,介绍了Binder 内核层的注册代码以及ServiceManager初始化的过程。而我们平时在使用进程间通信时,只需要关注的“客户端”,“服务端”等概念。今天,就让我们来看一下,我们平时在使用AIDL的背后,是如何涉及到Binder内核和ServiceManager的。AIDL的使用过程:第一:我们定义一个AIDL文件interface IAIDLService { void basicTypes(int anInt, long aLong, boolean aBoolean,...

上一篇文章,介绍了Binder 内核层的注册代码以及ServiceManager初始化的过程。
而我们平时在使用进程间通信时,只需要关注的“客户端”,“服务端”等概念。今天,就让我们来看一下,我们平时在使用AIDL的背后,是如何涉及到Binder内核和ServiceManager的。

AIDL的使用过程:
第一:我们定义一个AIDL文件

interface IAIDLService {
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);
}

第二:在我们的页面上,通过 bindService 的方式启动服务,并且在onServiceConnected方法中,把IBinder接口通过IAIDLService.Stub.asInterface(service)转化成IAIDLService接口,然后就可以通过IAIDLService接口调用对应的接口即可。

bindService(intent, new ServiceConnection() {
  @Override
   public void onServiceConnected(ComponentName name, IBinder service) {
       IAIDLService iaidlService = IAIDLService.Stub.asInterface(service);
       try {
           iaidlService.basicTypes(1,2,true,4,5,"6");
       } catch (RemoteException e) {
           e.printStackTrace();
       }
   }

   @Override
   public void onServiceDisconnected(ComponentName name) {
   }
}, Context.BIND_AUTO_CREATE);

第三:在我们的服务端,需要实现 IBinder onBind(Intent intent) 方法,然后实例化new IAIDLService.Stub() 并且再onBind中返回回去。注意:Service要配置运行在另外一个进程。

private IAIDLService.Stub binder = new IAIDLService.Stub() {
    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
        Log.e("TAG","basicTypes:anInt:" + anInt + " aLong:" + aLong + " aBoolean:" + aBoolean + " aFloat:" + aFloat
            + " aDouble:" + aDouble + " aString:" + aString);
    }
};

这样,我们就实现了从客户端进程发送数据到服务端进程了。
平时,我们使用的AIDL是经过层层封装,那么背后它的原理是什么样子的呢?

我们首先看到 IAIDLService iaidlService = IAIDLService.Stub.asInterface(service);这一行代码。IAIDLService是一个接口,所以我们先要知道,IAIDLService的具体实现是谁。所以,我们看一下asInterface方法。

public static com.bzl.a929demo.service.aidl.IAIDLService asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.bzl.a929demo.service.aidl.IAIDLService))) {
        return ((com.bzl.a929demo.service.aidl.IAIDLService) iin);
    }
    return new com.bzl.a929demo.service.aidl.IAIDLService.Stub.Proxy(obj);
}

这里主要做了客户端和服务端是否在同一个进程的判断,如果不是,就创建IAIDLService.Stub.Proxy(obj)类。也就是说 IAIDLService 的具体实现是 IAIDLService.Stub.Proxy。

我们在客户端发送数据的时候,是调用了 iaidlService.basicTypes 这个方法,看一下 Proxy.basicTypes这个方法的具体实现。

@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);
        boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
        if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
            return;
        }
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}

这里的最要操作,就是把数据装载到Parcel中,然后通过 mRemote.transact 方法发送出去。那么,mRemote又是谁呢?我们来到Proxy的构造方法。

Proxy(android.os.IBinder remote) {
    mRemote = remote;
}

可以看到,mRemote 就是在bindService的onServiceConnected回调方法中IBinder service接口。到这里,我们便遇到第一个难题:IBinder接口是在启动服务时系统回调的。我们如果要从代码里分析出来IBinder的具体实现是谁,还需要去走一遍启动服务的流程。

我们这里采用debug的方式来看出IBinder的具体实现。
Android的进程间通信(六)之 Binder的客户端发送数据到服务端的流程
从debug的结果上来看,mRemote的具体是BinderProxy,所以,我们来到BinderProxy.transact()这个方法。

public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
	省略代码。。。。
    try {
        return transactNative(code, data, reply, flags);
    } finally {
        if (transactListener != null) {
            transactListener.onTransactEnded(session);
        }

        if (tracingEnabled) {
            Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
        }
    }
}

transact 调用了 transactNative方法,transactNative是一个本地方法,我们看一下对应的JNI实现。
我们在 android_util_Binder 中,找到了 transactNative的实现。

static const JNINativeMethod gBinderProxyMethods[] = {
     /* name, signature, funcPtr */
    {"pingBinder",          "()Z", (void*)android_os_BinderProxy_pingBinder},
    {"isBinderAlive",       "()Z", (void*)android_os_BinderProxy_isBinderAlive},
    {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
    {"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
    {"linkToDeath",         "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
    {"unlinkToDeath",       "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
    {"getNativeFinalizer",  "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
};

从这个结构体中,可以看到 transactNative 对应 android_os_BinderProxy_transact方法。看一下 android_os_BinderProxy_transact的实现。

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    省略代码 ...
    IBinder* target = getBPNativeData(env, obj)->mObject.get();
    省略代码 ...
    //printf("Transact from Java code to %p sending: ", target); data->print();
    status_t err = target->transact(code, *data, reply, flags);
    省略代码 ...
    return JNI_FALSE;
}

这个方法,主要有两行我们需要看的代码。
第一行是:
IBinder* target = getBPNativeData(env, obj)->mObject.get();
我们需要确定,IBinder的具体实现。所以,看一下getBPNativeData的代码。

BinderProxyNativeData* getBPNativeData(JNIEnv* env, jobject obj) {
    return (BinderProxyNativeData *) env->GetLongField(obj, gBinderProxyOffsets.mNativeData);
}

getBPNativeData 返回一个 BinderProxyNativeData 的结构体,这个结构体已经提前初始化并且存在JNIEnv里,在JNI层会缓存在gNativeDataCache 上。我们先看一下 BinderProxyNativeData 结构体的定义。

struct BinderProxyNativeData {
	// Both fields are constant and not null once javaObjectForIBinder returns this as
	// part of a BinderProxy.

	// The native IBinder proxied by this BinderProxy.
	sp<IBinder> mObject;

	// Death recipients for mObject. Reference counted only because DeathRecipients
	// hold a weak reference that can be temporarily promoted.
	sp<DeathRecipientList> mOrgue;  // Death recipients for mObject.
};

所以,我们需要知道,mObject是在哪里初始化的,就首先需要知道 gNativeDataCache 在哪里被初始化。

gNativeDataCache 在 javaObjectForIBinder 中被初始化,javaObjectForIBinder 在 android_os_BinderInternal_getContextObject中被调用,而 android_os_BinderInternal_getContextObject 是一个JNI方法,由Java层调用。
看一下 android_os_BinderInternal_getContextObject 的实现。

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    return javaObjectForIBinder(env, b);
}

mObject 就是这个 ProcessState::self()->getContextObject(NULL); 。重点看一下这个方法。

我们来到了 ProcessState.cpp 文件,找到getContextObject这个方法的实现。

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

可以看到这里获得一个 handle = 0 的IBinder 接口。

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
	...... 
			if (handle == 0) {
				Parcel data;
				status_t status = IPCThreadState::self()->transact(
						0, IBinder::PING_TRANSACTION, data, NULL, 0);
				if (status == DEAD_OBJECT)
				   return NULL;
			}
			b = BpBinder::create(handle);
			e->binder = b;
			if (b) e->refs = b->getWeakRefs();
			result = b;
			
	.... 

	return result;
}

所以 ProcessState::self()->getContextObject(NULL) 返回的是一个 BpBinder
所以,在从java层到JNI的 android_os_BinderProxy_transact,本质上是 BpBinder->transact()。

看一下 BpBinder->transact这个方法的实现。

status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
	// Once a binder has died, it will never come back to life.
	if (mAlive) {
		status_t status = IPCThreadState::self()->transact(
			mHandle, code, data, reply, flags);
		if (status == DEAD_OBJECT) mAlive = 0;
		return status;
	}
	return DEAD_OBJECT;
}

继续看一下 IPCThreadState的transact的实现。

status_t IPCThreadState::transact(int32_t handle,uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
	..... 
	err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
	.....
	if ((flags & TF_ONE_WAY) == 0) {
		.....
		if (reply) {
			err = waitForResponse(reply);
		} else {
			Parcel fakeReply;
			err = waitForResponse(&fakeReply);
		}
		.....
	} else {
		err = waitForResponse(NULL, NULL);
	}
	return err;
}

writeTransactionData 进行数据的封装,要记得 BC_TRANSACTION 这个type
waitForResponse 把数据发送出去,继续看一下这个方法的实现。

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){
	..... 省略代码
	while (1) {
		..... 省略代码
		if ((err=talkWithDriver()) < NO_ERROR) break;
		..... 省略代码
	}
	..... 省略代码
}

waitForResponse 最主要调用了 talkWithDriver 方法,继续看 talkWithDriver 的实现。

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ..... 省略
    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)
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
        if (mProcess->mDriverFD <= 0) {
            err = -EBADF;
        }
        IF_LOG_COMMANDS() {
            alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
        }
    } while (err == -EINTR);

    .... 省略
    return err;
}

到了这里,终于看到 ioctl 了。到了这里,就把数据发到了Binder内核。
Binder内核会把数据转发给对应的服务端,就不继续往下走了。

这一篇代码分析,里面可能存在一些错误,但是我的目的就是从代码层面去验证前面几篇的理论分析。但是好累啊,哈哈哈。

Binder的学习就告一段落。

本文地址:https://blog.csdn.net/s2311307/article/details/111868681