阅读 1123

不懂砍我之看完这篇还不明白Binder你砍我(三)

前言

本篇是系列文章的第三篇

看完这篇还不明白Binder你砍我(一)

看完这篇还不明白Binder你砍我(二)

在上一篇中我们从Java层开始出发,一路直指Binder驱动,详细的讲解了是如何获取系统服务的。出于连贯性,有个很重要的东西在上一篇中没有讲解,那就是在Java层到Native层是如何获取的ServiceManager。因为所有的业务和逻辑全都是依靠ServiceManager来实现的,所以本篇将会讲解如何获取ServiceManager

Java层获取ServiceManager

在上一篇中走到这个getIServiceManager()方法中获取ServiceManager对象。

getIServiceManager()

//frameworks/base/core/java/android/os/ServiceManager.java
private static IServiceManager getIServiceManager() {
    if (sServiceManager != null) {
        return sServiceManager;
    }
    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
    return sServiceManager;
}
复制代码

是通过ServiceManagerNative.asInterface()方法来获取ServiceManager对象,asInterface方法的参数中是调用了BinderInternal.getContextObject()方法。这是一个native方法。

getContextObject()

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

我们看一下ProcessState::self()这个方法:

//frameworks/native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState("/dev/binder");//1
    return gProcess;
}
复制代码

这是一个单例模式用于获取ProcessState,每个进程只有一个。眼尖的小伙伴应该发现了一个熟悉的字符串,没错就是这个/dev/binder,这就是没有物理介质的Binder驱动。那么ProcessState的构造方法又做了哪些事情呢?

初始化ProcessState

//frameworks/native/libs/binder/ProcessState.cpp
ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))//1 这一行很重要,打开了Binder驱动
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
    , mStarvationStartTimeMs(0)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {
        //2 mmap内存映射
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
            close(mDriverFD);
            mDriverFD = -1;
            mDriverName.clear();
        }
    }
    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}
复制代码

注释1处,ProcessState的构造方法首先调用了open_driver()方法,这个方法一看名字就知道,是打开驱动嘛,它的参数不就是我们刚才看到的传进去的/dev/binder,也就是说ProcessState在构造方法处打开了Binder驱动。看看它是怎么打开驱动的吧

open_driver
//frameworks/native/libs/binder/ProcessState.cpp
static int open_driver(const char *driver)
{
    int fd = open(driver, O_RDWR | O_CLOEXEC);//1
    if (fd >= 0) {
        ...
        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);//2
        if (result == -1) {
            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
    } else {
        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
    }
    return fd;
}
复制代码

注释1处用于打开/dev/binder设备并返回文件操作符fd,这样就可以操作内核的Binder驱动了。

Linux 系统中,把一切都看做是文件,当进程打开现有文件或创建新文件时,内核向进程返回一个文件描述符,文件描述符就是内核为了高效管理已被打开的文件所创建的索引,用来指向被打开的文件,所有执行I/O操作的系统调用都会通过文件描述符。

注释2处的ioctl函数的作用就是和Binder设备进行参数的传递,这里的ioctl函数用于设定binder支持的最大线程数为15(maxThreads的值为15)。

在用户空间,使用ioctl方法系统调用来控制设备。这是方法原型:

/*
fd:文件描述符
cmd:控制命令
...:可选参数:插入*argp,具体内容依赖于cmd*/
int ioctl(int fd,unsigned long cmd,...);
复制代码

用户程序所作的只是通过命令码告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。所以在用户空间我们想做什么事情都是通过这个方法以命令的形式告诉Binder驱动,Binder驱动收到命令执行相应的操作。

mmap

在刚才的注释2处就是大名鼎鼎的内存映射。内存映射函数mmap,给binder分配一块虚拟地址空间。它会在内核虚拟地址空间中申请一块与用户虚拟内存相同大小的内存,然后再申请物理内存,将同一块物理内存分别映射到内核虚拟地址空间和用户虚拟内存空间,实现了内核虚拟地址空间和用户虚拟内存空间的数据同步操作。

这是函数原型:

//原型
/*
addr: 代表映射到进程地址空间的起始地址,当值等于0则由内核选择合适地址,此处为0;
size: 代表需要映射的内存地址空间的大小,此处为1M-8K;
prot: 代表内存映射区的读写等属性值,此处为PROT_READ(可读取);
flags: 标志位,此处为MAP_PRIVATE(私有映射,多进程间不共享内容的改变)和 MAP_NORESERVE(不保留交换空间)
fd: 代表mmap所关联的文件描述符,此处为mDriverFD;
offset:偏移量,此处为0。

此处 mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
*/
void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) 
复制代码

总的来说,ProcessState做了两件事情,一是打开Binder驱动并返回文件操作符fd,二是通过mmap为Binder分配了一块虚拟内存空间,以达到内存映射的目的。

得到ProcessState对象后,调用它的getContextObject方法得到BpBinder对象。

ProcessState.getContextObject

//frameworks/native/libs/binder/ProcessState.cpp
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);  //
}
复制代码

在之前的篇幅中讲了,当请求服务的进程的handler是0的时候就是获取ServiceManager的BpBinder对象。这里的话就是获取获取handle=0的IBinder。

ProcessState.getStrongProxyForHandle

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

    AutoMutex _l(mLock);
    //查找handle对应的资源项
    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                Parcel data;
                //通过ping操作测试binder是否准备就绪
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            //当handle值所对应的IBinder不存在或弱引用无效时,则创建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;
}
复制代码

首先查找handler所对应的资源,当handle值所对应的IBinder不存在或弱引用无效时会创建BpBinder,否则直接获取。handle==0的特殊情况,即获取的是ServiceManager,需要通过PING_TRANSACTION来判断是否准备就绪。

创建BpBinder

//frameworks/native/libs/binder/BpBinder.cpp
BpBinder::BpBinder(int32_t handle)
    : mHandle(handle)
    , mAlive(1)
    , mObitsSent(0)
    , mObituaries(NULL)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK); //延长对象的生命时间
    IPCThreadState::self()->incWeakHandle(handle); //handle所对应的bindle弱引用 + 1
}
复制代码

创建BpBinder对象中会将handle相对应Binder的弱引用增加1.

创建完成以后我们就重新回到了getContextObject()方法中

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

可以看到,使用了javaObjectForIBinder方法将本地IBinder指针转为javaobject。然后返回给了Java层。

javaObjectForIBinder

//frameworks/base/core/jni/android_util_Binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) {
    if (val == NULL) return NULL;

    if (val->checkSubclass(&gBinderOffsets)) { //返回false
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        return object;
    }

    AutoMutex _l(mProxyLock);

    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) { //第一次object为null
        jobject res = jniGetReferent(env, object);
        if (res != NULL) {
            return res;
        }
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }

    //创建BinderProxy对象
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        //BinderProxy.mObject成员变量记录BpBinder对象
        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
        val->incStrong((void*)javaObjectForIBinder);

        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        //将BinderProxy对象信息附加到BpBinder的成员变量mObjects中
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);

        sp<DeathRecipientList> drl = new DeathRecipientList;
        drl->incStrong((void*)javaObjectForIBinder);
        //BinderProxy.mOrgue成员变量记录死亡通知对象
        env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));

        android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }
    return object;
}
复制代码

根据BpBinder(C++)生成BinderProxy(Java)对象. 主要工作是创建BinderProxy对象,并把BpBinder对象地址保存到BinderProxy.mObject成员变量. ,实现了proxy拥有了native对象的引用。通过BpBinder的成员变量mObjects记录BinderProxy对象信息, 实现了native对象需要保存proxy对象的弱引用,当proxy还存在的时候,可以检索到同一个proxy。到此,可知ServiceManagerNative.asInterface(BinderInternal.getContextObject()) 等价于

ServiceManagerNative.asInterface(new BinderProxy())
复制代码

ServiceManagerNative.asInterface方法中:

 static public IServiceManager asInterface(IBinder obj)
{
    if (obj == null) { //obj为BpBinder
        return null;
    }
    //由于obj为BpBinder,该方法默认返回null
    IServiceManager in = (IServiceManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }
    return new ServiceManagerProxy(obj); //
}
复制代码

由此,可知ServiceManagerNative.asInterface(new BinderProxy()) 等价于new ServiceManagerProxy(new BinderProxy()).

ServiceManagerProxy初始化

class ServiceManagerProxy implements IServiceManager {
    public ServiceManagerProxy(IBinder remote) {
        mRemote = remote;
    }
}
复制代码

mRemoteBinderProxy对象,该BinderProxy对象对应于BpBinder(0),其作为binder代理端,指向native层大管家service Manager。

ServiceManager.getIServiceManager最终等价于new ServiceManagerProxy(new BinderProxy())

framework层的ServiceManager的调用实际的工作确实交给ServiceManagerProxy的成员变量BinderProxy;而BinderProxy通过jni方式,最终会调用BpBinder对象;可见上层binder架构的核心功能依赖native架构的服务来完成的。

参考:gityuan