千里马android binder深入分析-承上启下的native层(客户端部分)

92 篇文章 66 订阅
92 篇文章 73 订阅

csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论

android跨进程通信实战视频课程(加群获取优惠)
image.png
相信大家对上面这一副binder跨进程通信的图都应该比较熟悉,图中的主要有4个角色:
1、客户端(A进程)
2、SerivceManager
3、服务端(B进程)
4、binder驱动
平时一问到binder是怎么跨进程通信的?那么同学们肯定大部分回答:binder最后调到底层还是通过binder驱动来实现跨进程通信的。那么这里就要问一下:请问android中app的java层binder调用,是怎么一步步调用到了底层binder驱动呢?
image.png
这个中间问号部分也就本节要给大家重点分享的部分。
##1.ServiceManager方法调用也是binder跨进程通信
跨进程通信那么必然会出现有两端,即客户端和服务端这样的C/S模型,那么问题是C端怎么知道的S端?那么这就会引出一个重要的角色ServiceManager,ServiceManager本身工作相对简单,其功能:查询和注册服务。客户端通过ServiceManager查询到了注册服务后,才可以进行跨进程通信,这里就是常说的ServiceManager像个DNS服务器。但问题来了,ServiceManager本身自己就是一个独立进程,那么客户端去SerivceManager中查询服务也肯定是跨进程通信,所以本节分析跨进程通信时就拿ServiceManager.getService这个跨进程调用来展开分析。

##2.ServiceManager接口获取分析
平时系统中获取某一个服务,一般都是最后都是ServiceManager.getService这种方式,来看看它的源码:

//ServiceManager.java中
    public static IBinder getService(String name) {
        try {
        	//缓存中获取,第一次缓存没有
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
            	//Binder.allowBlocking仅仅是为了提示是否为阻塞行接口,没有实际干活
                return Binder.allowBlocking(getIServiceManager().getService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

这里大家可以看到实际真正干活的是getIServiceManager().getService(name),这里首先来看getIServiceManager()方法:

//ServiceManager.java中
   private static IServiceManager getIServiceManager() {
      //这里有一个sServiceManager来缓存,但是第一次肯定还为null
        if (sServiceManager != null) {
            return sServiceManager;
        }
        // 这里用调用了ServiceManagerNative类的asInterface方法和BinderInternal.getContextObject()方法
        sServiceManager = ServiceManagerNative
                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
        return sServiceManager;
    }

这里又调用到了ServiceManagerNative类的asInterface方法这方法本身应该在应用写aidl生成的java文件中也经常见到:

//ServiceManagerNative.java
  static public IServiceManager asInterface(IBinder obj)
    {
        if (obj == null) {
            return null;
        }
        IServiceManager in =
            (IServiceManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        //其实就是 new ServiceManagerProxy代理对象,参数是IBinder 类型的对象
        return new ServiceManagerProxy(obj);
    }

它的核心就是new ServiceManagerProxy,但是真正干活的还是IBinder参数,参数getIServiceManager方法中可以看出获取其实是核心是BinderInternal.getContextObject()方法,但getContextObject是个native的方法,所以就得看对应的jni方法:

//android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
   //调用getContextObject构造出一个IBinder类型对象
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    //把C++层面的IBinder类型对象转成java成的IBinder对象
    return javaObjectForIBinder(env, b);
}

这里一共才2行代码,那就一行行深入分析,首先来看ProcessState::self()->getContextObject:

//ProcessState.cpp
//这里直接就没有使用传递来的参数,本身传递来的也是个NULL
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

ProcessState这里又调用了getStrongProxyForHandle方法,而且传递了一个参数0:

//ProcessState.cpp
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);
   //根据handle查询handle_entry对象,handle没有初始化过则构造一个handle_entry空壳出来
    handle_entry* e = lookupHandleLocked(handle);
  //因为handle_entry已经有了,只不过是一个空壳里面内容都为空
    if (e != NULL) {
        IBinder* b = e->binder;
      //这里e->binder第一次肯定为空
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
          //如果传入handle为0
            if (handle == 0) {
                Parcel data;
               //这里会调用 IPCThreadState::self()->transact方法来传递一个PING_TRANSACTION,主要目的
               //是为了试探ServiceManager是否还存活
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            //利用handle值构造出一个BpBinder对象,最后返回也是这个BpBinder对象
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

到这里我们就看到了最后其实就是new BpBinder(handle);,这里handle就是我们经常说 “引用”,即对远程对象的引用,这里因为ServiceManager的的特殊性,所以android系统中默认把任何进程对ServiceManager的引用handle值都设置为固定的0。那么到这里就分析完了ProcessState::self()->getContextObject(NULL)了,返回的其实就是个new BpBinder(0),但是这里还是C++层的BpBinder对象,而我们是要获取Java层的IBinder类型的对象,那接下来就要分析上面剩下的 javaObjectForIBinder(env, b):

//android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
        //省略部分
	//这里构造出了gBinderProxyOffsets的java对象
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        // The proxy holds a reference to the native object.
      //这里吧val这个c++的对象指针设置到gBinderProxyOffsets.mObject这个java属性中
        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
        val->incStrong((void*)javaObjectForIBinder);

        // The native object needs to hold a weak reference back to the
        // proxy, so we can retrieve the same proxy if it is still active.
        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        //前面只是基于val建立对应的java对象,及java对象可以直接拿到val指针
       //但是我们进程也需要val指针可以获取到java对象
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);

     //省略部分
    }

    return object;
}

这里面gBinderProxyOffsets相关的是什么呢?这里再来看它的对应初始化代码:

//android_util_Binder.cpp
const char* const kBinderProxyPathName = "android/os/BinderProxy";

static int int_register_android_os_BinderProxy(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, "java/lang/Error");
    gErrorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
  //通过jni找出android/os/BinderProxy这个java类
    clazz = FindClassOrDie(env, kBinderProxyPathName);
    gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
  //通过jni找出android/os/BinderProxy这个java类的构造方法
    gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "()V");
    gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice",
            "(Landroid/os/IBinder$DeathRecipient;)V");
///通过jni找出android/os/BinderProxy这个java类的mObject 属性
    gBinderProxyOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
//省略部分
}

这里面可以看出其实都是通过jni相关方法,让native的相关变量与java层的BinderProxy相绑定一起,到这里就可以看出在BinderProxy是在native层面被构造出来的,设置了它的mObject值就是c++层的BpBinder指针,那么到这里就已经分析完了开始的getIServiceManager方法,这个时候就有了ServiceManager的Proxy代理,总结以下几点核心部分:
1、ServiceManager特殊,它的handle固定为0,native层直接进行new BpBinder(0)
2、native层面的BpBinder需要转换成Java层的BinderProxy,这个需要native通过jni构造出java层对应的BinderProxy,且BinderProxy的mObject值就是BpBinder(0)的指针,mObject也是Java层面与native层面进行互通的最关键纽带

image.png

##3.getService获取远程服务代理的源码分析
首先来看ServiceManagerNative.java中的ServiceManagerProxy类中的getService

//ServiceManagerNative.java
    public IBinder getService(String name) throws RemoteException {
         //准备输入和返回Parcel对象
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
      //这里已经知道mRemote其实就是前面分析构造出来的BinderProxy对象
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
      //读取返回的IBinder数据
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }

这里其实核心就是 mRemote.transact和 reply.readStrongBinder两个部分,这里先来分析transact部分,
这个mRemote对象是BinderProxy对象,所以来看BinderProxy类的transact方法,注意这里BinderProxy没有单独java文件,它在Binder.java文件中:

//Binder.java
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//省略
        try {
            return transactNative(code, data, reply, flags);
        } finally {
           //省略
        }
    }

这里其实又是调用了一个native方法transactNative,注意这里transactNative到android_os_BinderProxy_transact是有一个转换关系的,这个在分析android系统源码时候很常见:
image.png

//android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
   //省略部分
//这里从BinderProxy类型的java对象中获取mObject属性,前面分析过它的值就是BpBinder对象指针
    IBinder* target = (IBinder*)env->GetLongField(obj, gBinderProxyOffsets.mObject);
   //省略部分
//调用BpBinder对象的transact方法
    status_t err = target->transact(code, *data, reply, flags);
//省略部分
}

这里就可以看出前面讲的mObject为啥是“重要纽带”,那么接下来看看BpBinder的transact方法:

//BpBinder.cpp
status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    if (mAlive) {
       //本质是调用了IPCThreadState的transact方法
        status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }
    return DEAD_OBJECT;
}

那么接下来看看IPCThreadState的transact方法:

//IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
 //省略部分
    if (err == NO_ERROR) {
      //准备好与驱动通信的数据格式结构体
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
//如果不是TF_ONE_WAY即oneway类型的调用
    if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
          //这里需要等待答复
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
    } else {
//即oneway类型的调用
        err = waitForResponse(NULL, NULL);
    }
    return err;
}

这里面分为两个大块writeTransactionData和waitForResponse,writeTransactionData主要目的就是把数据组装成和驱动一致的binder_transaction_data结构体,然后在是waitForResponse:

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;

    while (1) {
        //与驱动进行通信,这里主要通过相关ioctl相关方法
        if ((err=talkWithDriver()) < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
        //得到驱动返回cmd
        cmd = (uint32_t)mIn.readInt32();
        switch (cmd) {
        case BR_REPLY:
            {
                binder_transaction_data tr;
              //得到驱动返回数据
                err = mIn.read(&tr, sizeof(tr));
                //省略部分
         }
//省略部分
}

可以看出主要就是talkWithDriver与驱动进行通信并且一直等待返回驱动相应结果,这里涉及驱动部分就不给大家在这里讲解,大家把驱动暂时当作黑盒既可以。
这个地方简单看看ServiceManager这个服务端,面对客户端的getService做了什么呢?
在servicemanager代码中如果接受到客户端请求,最后都会调用到svcmgr_handler来负责处理:

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;
//..省略部分
    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
     //根据获取到service的name
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
      //根据name从已经存在集合中找出对应的handle即索引
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
      //把handle获取到了后写入reply
        bio_put_ref(reply, handle);
        return 0;
//..省略部分
    default:
        ALOGE("unknown code %d\n", txn->code);
        return -1;
    }

    bio_put_uint32(reply, 0);
    return 0;
}

这里面根据name从集合中寻找出了服务的handle,注意这里只是找出了一个int类型的handle,然后在调用bio_put_ref进行写入reply,再通过binder驱动传递给客户端,这里看看bio_put_ref方法:

void bio_put_ref(struct binder_io *bio, uint32_t handle)
{
//构造出一个binder结构体
    struct flat_binder_object *obj;

    if (handle)
        obj = bio_alloc_obj(bio);
    else
        obj = bio_alloc(bio, sizeof(*obj));

    if (!obj)
        return;
//给flat_binder_object 结构体对应属性赋值
    obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
 //设置类型为BINDER_TYPE_HANDLE
    obj->type = BINDER_TYPE_HANDLE;
   //把handle赋值给flat_binder_object 的handle属性
    obj->handle = handle;
    obj->cookie = 0;
}

这里大概我们就清除了原来servicemanager这一边做的事情就是根据name查找到这个name对应的handle,再把这个handle值包装到flat_binder_object 结构体中,再把结构体传递到驱动,驱动再传递到客户端,具体传递过程就不在这一节详细讲述,分析这里相当于客户端调用transact方法后,服务端servicemanager的数据经过binder驱动进行了返回。但是返回后的数据是怎么一步步又变成IBinder对象的呢?这里我们接下来看 IBinder getService(String name)的 IBinder binder = reply.readStrongBinder()方法了,这里看着就是从Parcel类型的reply中调用了readStrongBinder方法就返回了IBinder对象。注意啦Parcel这里是java层的,但是最后调用它又会调用到Parcel.cpp中,先看Parcel.java:

//Parcel.java
  public final IBinder readStrongBinder() {
        return nativeReadStrongBinder(mNativePtr);
    }

这里其实就只调用了nativeReadStrongBinder方法,它又是一个jni方法,所以这个方法后就会调用到native层,具体看一下这个方法在native层映射成了哪个方法:

//android_os_Parcel.cpp
    {"nativeReadStrongBinder",    "(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},

这里被映射成了android_os_Parcel_readStrongBinder方法:

//android_os_Parcel.cpp
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

这里又会先调用parcel->readStrongBinder()获取native层的BpBinder对象作为参数,然后再调用javaObjectForIBinder转为java对象,这个前面已经讲过了哦。

//Parcel.cpp
sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
//这里又调用了readNullableStrongBinder
    readNullableStrongBinder(&val);
    return val;
}

接下来看看readNullableStrongBinder:

status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
    return unflatten_binder(ProcessState::self(), *this, val);
}

这里又调用到了unflatten_binder:

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);

    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
              //这里核心又是获取了handle后调用getStrongProxyForHandle
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}

这里我们前面分析servicemanager时候就知道type类型为BINDER_TYPE_HANDLE,所以根据flat->handle的handle值调用getStrongProxyForHandle,这个getStrongProxyForHandle方法前面已经分析过他就是new BpBinder(handle),所以这里就明白了这个getService方法最后也是根据servicemanager返回的handle(这里大家要注意这个客户端的handle值和servicemanager中写入的handle值不一定相等,而是各种进程独立,但是在binder驱动可以关联上,具体区别会binder驱动中进行剖析)。
image.png
getService部分的总结:
1、获取远端Serivce整体依然是new BpBinder(handle) --> javaObjectForIBinder变成BinderProxy的过程
2、但这里的handle不再像ServiceManager那么简单的直接写死为0,而是需要把name传递到SeriveManager查询对应的服务,ServiceManager把对应服务flat_binder_object对象通过binder驱动传递到客户端,客户端再从flat_binder_object获取handle

至此我们就分析完了客户端发起一个调用到获取驱动数据返回的整个过程,那么接下要分析的是作为一个服务端即Binder实现端。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值