之前讲过Android Parcel数据传输源码解析,也讲过Android的bindService,但是Binder才是跨进程的核心内容,今天我就详细的说一下Binder到底是如何跨进程的。如果对bindService不是很了解的同学,建议先看看看上面的文章进行了解。
目录
3.Binder对象的传输
在跨进程通信之前,客服端client首先会执行bindService,和服务端进行连接,链接成功之后,会通过回调函数ServiceConnection的回调方法onServiceConnected将远程的IBinder对象进行返回,在我们自己写的通信接口类的Proxy中,赋值给mRemote。之后进行数据传输的时候,直接使用mRemote的transact方法进行跨进程通信。我相信小伙伴对上面的流程都比较熟悉了,但是不知道小伙伴思考过没,mRemote的具体实现类是谁?因为我们所能看见是mRemote是android.os.IBinder,它只是一个接口类,肯定有具体实现类的。
mRemote的具体实现类其实是BinderProxy,这个类在android.os.Binder.java类中。为什么是BinderProxy?我们在分析bindService的时候,没有找到BinderProxy的任何蛛丝马迹,怎么突然就变成了BinderProxy了呢?我们从头来说。
1.Binder对象的创建
AIDL生成了相关的接口类,而接口类中有一个Stub类,服务端Service中的onBind方法,返回的就是这个Stub对象,举例如下:
public static abstract class Stub extends android.os.Binder implements IBookManager {
private static final String DESCRIPTOR = "com.example.bindertest.IBookManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
....
}
继承了android.os.Binder类,我们看一下Binder类:
public Binder() {
init();
....
}
private native final void init();
init()是native方法,所以我们查看jni层的init方法,具体类为frameworks/base/core/jni/android_util_Binder.cpp
static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
JavaBBinderHolder* jbh = new JavaBBinderHolder();//注释1
if (jbh == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
}
ALOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh);
jbh->incStrong((void*)android_os_Binder_init);
env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh);//注释2
}
我们先看注释2:这是一个赋值操作,我们知道obj是Binder对象,那gBinderOffsets.mObject是什么呢?其实就是Binder中的mObject,注释2就是将JavaBBinderHolder赋值给了Binder的mObject,两者成为了一一对应的关系。
注释1的JavaBBinderHolder,创建JavaBBinderHolder的时候,会调用它的get方法:
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);//注释1
mBinder = b;//注释2
ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
}
return b;
}
注释1创建了JavaBBinder,并且在注释2中将JavaBBinder赋值给了mBinder,所以JavaBBinderHolder的mBinder指向了JavaBBinder。
我们再看一下JavaBBinder的构造方法:
JavaBBinder(JNIEnv* env, jobject object)
: mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))//注释1
{
ALOGV("Creating JavaBBinder %p\n", this);
android_atomic_inc(&gNumLocalRefs);
incRefsCreated(env);
}
注释1这里将object赋值给了JavaBBinder的mObject,而object是Binder对象,所以mObject指向了Binder对象。
总结上述的关系如下:
Binder.mObject(Java层)----->JavaBBinderHolder(Native层)
JavaBBinderHolder.mBinder(Native层)----->JavaBBinder(Native层)
JavaBBinder.mObject(Native层)----->Binder(Java层)
2.BinderProxy的创建
对应关系是找到了,但是依然没有看见BinderProxy。我们都知道Binder对象是依靠ServiceConnection在两端传递的,但是它本身也仅仅是传递的作用,没有其他的发现。在看代码的时候,我发现AMS也是通过Binder进行跨进程通信的,那原理应该是一样的才对,所以我打算从AMS中进行线索的查找
我们看一下AMS对象的获取,在ActivityManager中:
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);//注释1
final IActivityManager am = IActivityManager.Stub.asInterface(b);//注释2
return am;
}
};
我们先看注释2,这里和我们自己在使用AIDL通信的操作是一样的,都调用了Stub的asInterface方法,参数为远端的代理对象;我们再看注释1,这个远端的代理对象,是通过ServiceManager的getService获取到的,看一下ServiceManager的getService方法:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return Binder.allowBlocking(getIServiceManager().getService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
先调用了getIserviceManager方法拿到了IServiceManager对象,然后调用IServiceManager的getService方法拿到了Binder对象。我们先看一下getIServiceManager方法:
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
我们可以看到,同样是调用了asInterface方法拿到了远端代理对象,而这个远端的代理对象时通过BinderInternal.getContextObject获取到的,看一下getContextObject方法:
public static final native IBinder getContextObject();
是native方法,具体的实现在frameworks/base/core/jni/android_util_Binder.cpp中,如下:
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);//注释1
return javaObjectForIBinder(env, b);//注释2
}
我们先看注释1的getContextObject方法,在frameworks/native/libs/binder/ProcessState.cpp中:
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
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 = new BpBinder(handle); //注释1
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;//注释2
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
注释1创建了BpBinder对象,赋值给了注释2的result,然后进行了返回。
我们回到frameworks/base/core/jni/android_util_Binder.cpp中,看一下getContextObject方法中注释2的代码,第二个参数就是刚刚创建的BpBinder,我们看一下javaObjectForIBinder方法:
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
if (val == NULL) return NULL;
....
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);//注释1
if (object != NULL) {
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
val->incStrong((void*)javaObjectForIBinder);
jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
// Also remember the death recipients registered on this proxy
sp<DeathRecipientList> drl = new DeathRecipientList;
drl->incStrong((void*)javaObjectForIBinder);
env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
// Note that a new object reference has been created.
android_atomic_inc(&gNumProxyRefs);
incRefsCreated(env);
}
return object;
}
我们在注释1这里可以看到,通过反射的方式创建了gBinderProxyOffsets.mClass所代表的类对象,并且进行了返回,返回到了Java层,所以这类就是远端的代理对象。这个类估计大家也能猜到,就是BindProxy,为什么呢?其实这里设计到了Android系统的启动流程,这篇博客不涉及,所以我就不带着去找了,我总结了几个步骤作为参考:
第一步:app_main.cpp的main方法
第二步:AndroidRuntime的start方法
第三步:AndroidRuntime的startReg方法
第四步:AndroidRuntime的register_jni_procs方法
第五步:遍历gRegJNI数组,而android_util_Binder.cpp的register_android_os_Binder方法就在其中
第六步:执行android_util_Binder.cpp的int_register_android_os_Binder方法
第七步:对gBinderOffsets的成员变量赋值,其中:
(1)mClass为 android/os/Binder.java
(2)mExecTransact为 android/os/Binder.java这个类的execTransact方法
(3)mObject为 android/os/Binder.java这个类的mObject对象
第八步:对gBinderProxyOffsets的成员变量赋值,其中
(1)mClass为 android/os/BinderProxy,这个类在android/os/Binder.java中
(2)mConstructor为 android/os/BinderProxy的构造器
(3)mObject为 android/os/BinderProxy的mObject
3.Binder对象的传输
从bindService这篇文章我们可以知道,Binder对象是通过IServiceConnection进行传输的,如下:
ActiveServices的publishServiceLocked方法
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
...
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +" to connection " + c.conn.asBinder() +" (in " + c.binding.client.processName + ")", e);
}
...
}
IServiceConnection具体代码我们看不见,但是我们大致可以猜到,IServiceConnection的原理是Binder跨进程通信机制,只有这样,才能实现跨进程的数据传输。很明显,c.conn.connected方法就是客户端client调用的方法,而真正进行跨进程通信的其实是服务端的代理类。也就是说,IServiceConnection中也有一个远端代理mRemote,而这个mRemote就是BinderProxy,我们的Binder对象,也是通过我们要验证的BinderProxy类进行传输的。我们查看BinderProxy的transact方法:
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); }
return transactNative(code, data, reply, flags);
}
public native boolean transactNative(int code, Parcel data, Parcel reply,int flags) throws RemoteException;
transactNative方法是native方法,所以我们查看jni层的代码:
frameworks/base/core/jni/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);
if (data == NULL) {
return JNI_FALSE;
}
Parcel* reply = parcelForJavaObject(env, replyObj);
if (reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
IBinder* target = (IBinder*)env->GetLongField(obj, gBinderProxyOffsets.mObject);
...
//printf("Transact from Java code to %p sending: ", target); data->print();
status_t err = target->transact(code, *data, reply, flags);
....
}
第5行,第9行:拿到请求和响应的Parcel对象
第14行:obj就是BinderProxy对象,而gBinderProxyOffsets.mObject就是BinderProxy类中的mObject。所以这句代码就是拿到BinderProxy中的mObject对象。而mObject对象其实就是BpBinder(frameworks/native/libs/binder/BpBinder.cpp),而BpBinder与Java层的BinderProxy是一一对应的,这个我们稍后再证明
第17行:调用BpBinder的transact方法
我们查看BpBinder(frameworks/native/libs/binder/BpBinder.cpp)的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(frameworks/native/libs/binder/IPCThreadState.cpp)的transact方法
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
...
if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
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和waitForResponse,我们先看一下writeTransactionData方法
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr;
tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = 0;
tr.data.ptr.offsets = 0;
} else {
return (mLastError = err);
}
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
这个方法的作用,总结来说就是将binder_transaction_data结构体写入到Parcel对象mOut中。binder_transaction_data是用来描述Binder事务交互的数据结构体。它也属于内核空间和用户空间的通信结构体。个人理解,binder_transaction_data就是一个包裹类,用于通信的。
我们再看一下上面说的writeTransactionData:
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
cmd = (uint32_t)mIn.readInt32();
...
}
...
return err;
}
我们可以看到,这里是一个死循环,等到talkWithDriver方法有结果返回,我们看一下talkWithDriver方法
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
...
binder_write_read bwr;
// Is the read buffer empty?
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();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
...
// Return immediately if there is nothing to do.
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 (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
...
} while (err == -EINTR);
...
return err;
}
binder_write_read是内核空间和用户空间的通信结构体,它记录了Binder读写内容的相关信息。当用户空间的应用程序和Binder驱动通信时,它会将数据打包到binder_write_read中。write开头的是记录应用程序要发送给Binder驱动的内容,而read开头的是记录Binder驱动要反馈给应用程序的内容。参考博客
第30行代码:ioctl这个方法的具体实现是在内核层,需要看内核代码(官网地址,需要翻墙),我们看一下ioctl的具体代码:
在看内核代码之前,我们先了解几个概念:
binder_proc:是描述进程上下文信息的,每个用户的进程都对应binder_proc结构体。每当一个程序打开该文件节点时,Binder驱动中会新建一个binder_proc对象来保存改进程的上下文信息。
binder_thread:是描述Binder线程相关的结构体
在/dirvers/android/binder.c中,从framework层传过来的cmd是BINDER_WRITE_READ,所以我们只看BINDER_WRITE_READ相关的代码
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
.....
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
....
}
default:
ret = -EINVAL;
goto err;
}
....
return ret;
}
第4行代码:获取binder_proc对象
第7行代码:获取binder_thread对象,也就是binder_proc所在的线程
看看binder_ioctl_write_read方法
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
...
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
...
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
....
}
...
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
这里面有两个关键的方法
copy_from_user:将数据从用户空间拷贝到内核空间
copy_to_user:将数据从内核空间拷贝到用户空间
这两个方法完成了数据的跨进程操作
而binder_thread_read方法我没有去深研究,所以我就不展开了,不过这个方法中有两处关键代码:
(1)cmd = BR_TRANSACTION:存储这个指令,之后再framework层会取出来
(2)tr.cookie = target_node->cookie:cookie跨进程通信中服务端的Stub对象,在Service中onBind方法返回的对象,那这个cookie是在哪里存储的呢?由于篇幅有限,这个我们以后再去验证
内核中代码执行完成之后,会去唤醒Framework中IPCThreadState的talkWithDriver方法,继续向下执行,而talkWIthDriver方法在waitForResponse方法中,我们继续看waitForResponse方法:
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
...
cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
....
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
...
return err;
}
cmd就是上面说的BR_TRANSACTION,所以执行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;
result = mIn.read(&tr, sizeof(tr));
...
if (tr.target.ptr) {
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,&reply, tr.flags);
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
}
...
}
break;
...
return result;
}
第17行代码:上面说了,tr.cookie是我们的Stub对象,而它是BBinder(frameworks/native/libs/binder/BBinder.cpp)类型,所以我们先看BBinder中的transact方法
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);
break;
}
if (reply != NULL) {
reply->setDataPosition(0);
}
return err;
}
code是我们自己的code,每个通信方法的标识符,所以执行onTransact方法,而onTransact在具体的实现类中被复写了(这个地方涉及到了addService的相关原理,以后的博客我们来学习),所以可以理解为直接执行了我们自己Stub类中的onTransact方法。至此,数据完成了传输,从客户端传输到了服务端。
感谢技术大牛的博客作为参考!
参考文章:
Android Binder机制(二) Binder中的数据结构 | skywang