阅读 2241

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

前言

本篇是系列文章的第二篇

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

在上一篇中我们分别从Native层到内核层讲解了系统服务是如何注册,那这篇从Java层开始讲,系统服务是如何获取的。

Java层

小伙伴想想我们平常接触系统服务最多的时候是什么时候?

是不是就是获取系统服务呢?没错,那我们就从获取系统服务开始。

首先以我们最基础的使用方式getSystemService()这个方法开始

getSystemService()

var manager=getSystemService(Service.AUDIO_SERVICE) as AudioManager
复制代码

一般情况下我们是这样使用的。但是这个AudioManager到底是如何实现的呢?

其实它也是通过获取Service来实现的。我们来看看它的方法

AudioManager.getService

//android.media.AudioManager.java
private static IAudioService getService()
    {
        if (sService != null) {
            return sService;
        }
        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
        sService = IAudioService.Stub.asInterface(b);
        return sService;
}
复制代码

AudioManager是通过AIDL的方式获取的真正的系统服务。

大家要注意这里的ServiceManager和上一篇中native层的ServiceManager是不一样的,这个是Java层的。我们来看一下这个Java层ServiceManager是如何做的。

ServiceManager.getService

//frameworks/base/core/java/android/os/ServiceManager.java
public static IBinder getService(String name) {
        try {
            //先从缓存中查看
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return Binder.allowBlocking(rawGetService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
}
复制代码

可以看到首先从缓存中去取,如果没有的话就去创建一个,请求获取服务过程中,如果缓存中不存在的话,再通过binder交互来查询相应的服务。创建的方法是rawGetService方法。

rawGetService

//frameworks/base/core/java/android/os/ServiceManager.java
//省略部分代码
private static IBinder rawGetService(String name) throws RemoteException {
   
       final IBinder binder = getIServiceManager().getService(name);
	   /*
       *
       */
        return binder;
}
复制代码

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); 
}
复制代码

由于本小节是讲解Java的,这里就不做过多的讲解了。对于ProcessState::self()->getContextObject()这个方法,等价于new BpBinder(0)。即BinderInternal.getContextObject()方法最后是获取BpBinder对象。

那么回过头来看asInterface方法的具体实现:

ServiceManagerNative.asInterface

//frameworks/base/core/java/android/os/ServiceManagerNative.java
static public IServiceManager asInterface(IBinder obj)
    {
        if (obj == null) {
            return null;
        }
        IServiceManager in =
            (IServiceManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }

        return new ServiceManagerProxy(obj);
}
复制代码

采用了单例模式获取ServiceManagerasInterface()返回的是ServiceManagerProxy(简称SMP)对象。所以最后getIServiceManager() 方法等价于new ServiceManagerProxy(new BinderProxy())

既然getIServiceManager()获取到的是ServiceManagerProxyServiceManager.getService(name)方法就是调用的ServiceManagerProxy.getService(name)的方法。我们先看一下ServiceManagerProxy是怎么被初始化的:

ServiceManagerProxy初始化

//frameworks/base/core/java/android/os/ServiceManagerNative.java
class ServiceManagerProxy implements IServiceManager {
    public ServiceManagerProxy(IBinder remote) {
        mRemote = remote;
    }
}
复制代码

mRemoteBinderProxy对象,该BinderProxy对象对应于BpBinder(0),其作为binder代理端,指向native层大管家service Manager。还记得BpBinder对象吗?在上一节,我们讲到了这个BpBinder对象于BBinder对象是一对一的,客户端拿着BpBinder去找BBinder,然后服务端的BBinder去做真正的事情。

emmm

好像有点懵逼了

没关系,我们捋一捋

在Java层,我们首先通过Native方法获得BpBinder对象。BpBinder对象中的handler为0的的时候,就指向的是ServiceManager了。

接下来构造一个ServiceManagerProxy,ServiceManagerProxy持有BpBinder。内部的工作也全部都是BpBinder去做的。

简单说就是获取ServiceManager,相当于你找人办事,但是人家架子很大不会自己来,先派给你一个小弟(ServiceManagerProxy),你想做什么就吩咐小弟,小弟手里拿着手机(BpBinder),你吩咐小弟任务以后,小弟通过手机拨打对应号码(BBinder)告诉办事的人。

ServiceManagerProxy.getService(name)

//frameworks/base/core/java/android/os/ServiceManagerNative.java
class ServiceManagerProxy implements IServiceManager {
    public IBinder getService(String name) throws RemoteException {
        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);
        //从reply里面解析出获取的IBinder对象
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }
}
复制代码

由上可知,framework层的ServiceManager的调用实际的工作确实交给SMP的成员变量BinderProxy;而BinderProxy通过jni方式,最终会调用BpBinder对象;可见上层binder架构的核心功能依赖native架构的服务来完成的。mRemote.transact这行代码将调用BinderProxy.transact方法,最终获得到的数据将会被赋值到reply对象中。

BinderProxy.transact

//frameworks/base/core/java/android/os/Binder.java
final class BinderProxy implements IBinder {
    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
        return transactNative(code, data, reply, flags);
    }
}
复制代码

最终BinderProxy.transact方法调用了Native方法,从这里开始进入了Native层。Java层的工作到这里就结束了。

Native层

android_os_BinderProxy_transact

//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)
{
    ...
    //java Parcel转为native Parcel
    Parcel* data = parcelForJavaObject(env, dataObj);
    Parcel* reply = parcelForJavaObject(env, replyObj);
    ...

    //gBinderProxyOffsets.mObject中保存的是new BpBinder(0)对象
    IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);
    ...

    //此处便是BpBinder::transact(), 经过native层
    status_t err = target->transact(code, *data, reply, flags);
    ...
    return JNI_FALSE;
}
复制代码

最终调用BpBinder.transact的方法来进行

BpBinder.transact

//frameworks/native/libs/binder/BpBinder.cpp
status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    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。在上一篇文章中,也出现了这个IPCThreadState。这也是个单例模式,每个线程只有一个哦。

到这里接下来的事情基本上和上一篇中的如出一辙,我这里大概过一下把~

IPC.transact

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck(); //数据错误检查
    flags |= TF_ACCEPT_FDS;
    ....
    if (err == NO_ERROR) {
         // 传输数据 
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }

    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }

    // 默认情况下,都是采用非oneway的方式, 也就是需要等待服务端的返回结果
    if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            //reply对象不为空 
            err = waitForResponse(reply);
        }else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }
    return err;
}
复制代码

transact主要过程:

  • 先执行writeTransactionData()Parcel数据类型的mOut写入数据,此时mIn还没有数据;
  • 然后执行waitForResponse()方法,循环执行,直到收到应答消息. 在waitForResponse()方法中会调用talkWithDriver()跟驱动交互,收到应答消息,便会写入mIn, 则根据收到的不同响应吗,执行相应的操作。

上一篇文章中也将到过,这里再说一次~

  • mIn 用来接收来自Binder设备的数据,默认大小为256字节;
  • mOut用来存储发往Binder设备的数据,默认大小为256字节。

IPC.talkWithDriver

//frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;
    while (1) {
        //此处是真正的与内核交互的方法
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...
        cmd = mIn.readInt32();
        switch (cmd) {
          case BR_REPLY:
          {
            binder_transaction_data tr;
            err = mIn.read(&tr, sizeof(tr));
            if (reply) {
                if ((tr.flags & TF_STATUS_CODE) == 0) {
                    //当reply对象回收时,则会调用freeBuffer来回收内存
                    reply->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);
                } else {
                    ...
                }
            }
          }
          case :...
        }
    }
    ...
    return err;
}

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    //和Binder驱动通信的结构体    
    binder_write_read bwr;
    //mIn是否有可读的数据,接收的数据存储在mIn
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    bwr.write_size = outAvail;
    //将要发送给Binder设备的消息填充到与Binder通信的结构体中
    bwr.write_buffer = (uintptr_t)mOut.data();
	
    if (doReceive && needRead) {
        //接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了。
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } 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 {
        //通过ioctl不停的读写操作,跟Binder Driver进行通信
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        ...
    } while (err == -EINTR); //当被中断,则继续执行
    ...
    return err;
}
复制代码

接下来会通过ioctl方法于Binder驱动进行交互,这个交互的调用链是如下

进入驱动。binder_ioctl -> binder_ioctl_write_read -> binder_thread_write,最终会将命令和数据插入到ServiceManagertodo队列中。 这个的叙述可以参考上一篇的内容。

那么接下来ServiceManager在不断地从队列中取事务并处理,当service manager进程收到该命令后,会执行do_find_service() 查询服务所对应的handle,然后再binder_send_reply()应答 发起者,发送BC_REPLY协议,然后调用binder_transaction(),再向服务请求者的Todo队列 插入事务。接下来,请求服务的进程在执行talkWithDriver的过程执行到binder_thread_read(),处理Todo队列的事务.(这部分不明白的小伙伴一定要看我上一篇文章)。

waitForResponse方法中,收到消息以后这个reply就不为空,此时会进入reply的ipcSetDataReference方法中,由于这个reply是Parcel对象,其实就是调用了Parcel的ipcSetDataReference方法将ServiceManager返回过来的数据设置到parcel对象中。waitForResponse()执行完BR_REPLY之后,便返回到IPCThreadState::transact()中;然后层层返回,直到退回到Java层的ServiceManagerProxy.getService方法,然后调用reply的readStrongBinder方法,最终调用的Native的方法nativeReadStrongBinder()方法。

nativeReadStrongBinder

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

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val; 
    unflatten_binder(ProcessState::self(), *this, &val);
    return val; 
}
复制代码

readStrongBinder()会调用unflatten_binder()来解析Parcel中的数据。

Parcel.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:
                //进入该分支
                *out = proc->getStrongProxyForHandle(flat->handle);
                //创建BpBinder对象
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}
复制代码

ProcessState.getStrongProxyForHandle

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)) {
            ...
            //当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;
}
复制代码

经过该方法,最终创建了指向Binder服务端的BpBinder代理对象。经过javaObjectForIBinder方法将native层BpBinder对象转换为Java层BinderProxy对象。 也就是说通过getService()最终获取了指向目标Binder服务端的代理对象BinderProxy。

小结

getService的核心过程:

public static IBinder getService(String name) {
    ...
    Parcel reply = Parcel.obtain(); //此处还需要将java层的Parcel转为Native层的Parcel
    BpBinder::transact(GET_SERVICE_TRANSACTION, *data, reply, 0);  //与Binder驱动交互
    IBinder binder = javaObjectForIBinder(env, new BpBinder(handle));
    ...
}
复制代码

javaObjectForIBinder作用是创建BinderProxy对象,并将BpBinder对象的地址保存到BinderProxy对象的mObjects中。 获取服务过程就是通过BpBinder来发送GET_SERVICE_TRANSACTION命令,与实现与binder驱动进行数据交互。

请求服务getService()过程,就是向servicemanager进程查询指定服务,当执行binder_transaction()时,会区分请求服务所属进程情况。

  1. 当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;即创建了一个针对于请求服务进程的一个手机号,然后请求进程就可以通过得到一个小弟(BpBinder),让小弟记住这个手机号,就可以找到对应的服务人员(BBinder),然后就可以让服务人员办事了。
    • 最终readStrongBinder(),返回的是BpBinder对象;
  2. 当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDERBINDER_TYPE_WEAK_BINDER
    • 最终readStrongBinder(),返回的是BBinder对象的真实子类;

一张图来总结一下:

参考:gityuan