Android: Binder

Binder概述

Binder是一种Android实现的IPC,用于进程间通信。

通常Linux系统提供好几种进程间通信的方式,比如
1) Message Queue :把进程之间通信用的message保存到内核中或者从内核中读取的方式。

2) Shared Memory:进程间指定共享的内存,把需要传输的内容保存到相应的内存的方式

3) Socket:

Android中选择Binder为主要的IPC方式,因为Binder比其他的IPC方式有更加简洁快速,消耗内存更小等优点。

下面来看一下Framework层Java空间都是怎么用Binder实现进程间通信的。

Framework层Binder

Binder实际是一种C/S模式的工作方式,客户端通过Binde向服务端发出请求,服务端再通过Binder返回相应的内容给服务端。Binder的工作流程如下:
1)客户首先获得服务端的代理对象。所谓代理对象就是客户端建立一个服务端的”引用”,该代理对象具有服务端的功能,使其在客户端访问服务端的方法就像访问本地方法一样。
2)客户端通过调用服务器代理对象的方法,向服务器端发送请求
3)代理对象通过Binder驱动将用户请求发送给服务器端
4)服务器端处理客户端请求,并通过Binder驱动将处理结果返回给客户端
5)客户端收到服务器端的返回结果

这里说的服务端为:BBinder 服务端代理对象为:BpBinder
还需要说一下IBinder接口。这个接口是对跨进程对象的抽象,在C/C++和Java都有定义。IBinder定义了一套使用Binder机制来实现客户程序与服务器的通信协议。
一个对象只能在当前进程中被访问,如果希望它能被其他进程访问,就必须实现IBinder接口。IBinder接口可以指向本地对象,也可以指向远程对象。关键在与IBinder接口中的transact函数。如果IBinder指向服务端代理,那transact负责把请求发送给服务器;如果IBinder指向的是一个服务端,那么transact只负责提供服务。因此不管是服务端还是服务端代理对象,都必须实现该接口,这样才能进行Binder通信。
C/C++中BBinder和BpBinder都是继承了IBinder接口的类。

所以实现Binder就很简单,服务器端继承BBinder并实现onTransact函数,客户端继承BpBinder实现transact函数即可。
以MediaPlayerService为例,在Stagefright.cpp文件的main函数中有如下代码

        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder = sm->getService(String16("media.player"));
        sp<IMediaPlayerService> service =
            interface_cast<IMediaPlayerService>(binder);

        sp<IOMX> omx = service->getOMX();

这里getOMX函数是BpMediaPlayerService类中的函数,这个很容易看的出来。
定义如下:

    virtual sp<IOMX> getOMX() {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        remote()->transact(GET_OMX, data, &reply); //调用tranact函数发送Binder请求
        return interface_cast<IOMX>(reply.readStrongBinder());
    }

上述的Binder请求会最终发给服务器端,也就是BnMediaPlayerService类的onTransact函数中

status_t BnMediaPlayerService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
        ...
        case GET_OMX: {
            CHECK_INTERFACE(IMediaPlayerService, data, reply);
            sp<IOMX> omx = getOMX();
            reply->writeStrongBinder(omx->asBinder());
            return NO_ERROR;
        } break;
        ...
    }
}

最终getOMX函数就是调用继承了BnMediaPlayerService类的MediaPlayerService类中的getOMX函数

sp<IOMX> MediaPlayerService::getOMX() {
    Mutex::Autolock autoLock(mLock);

    if (mOMX.get() == NULL) {
        mOMX = new OMX;
    }

    return mOMX;
}

下面来看一下上述的过程是怎么通过Binder驱动来传递的,因为上面说的内容都没有涉及到打开,读写Binder驱动(/dev/binder)的内容。

要看service是怎么打开Binder驱动并实现,必须要从其初始化过程以及service的注册过程看起。
在系统开机的时候,init.rc里边有如下配置,负责启动mediaserver。

service media /system/bin/mediaserver
    class main
    user media
    group system audio camera inet net_bt net_bt_admin net_bw_acct drmrpc sdcard_r shell mediadrm media_rw qcom_diag radio
    ioprio rt 4

可以从Android.mk配置中找到,上面的service启动,入口函数是main_mediaserver.cpp文件中的main函数。

int main(int argc __unused, char** argv)
{
    signal(SIGPIPE, SIG_IGN);
    char value[PROPERTY_VALUE_MAX];
    bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
    pid_t childPid;

    if (doLog && (childPid = fork()) != 0) {
        //如果doLog为true,其父进程就会跑到这里,处理几个子进程的消息。这个不是重点,跳过!!
    } else {
        ...
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ...
        waitBeforeAdding(String16("media.player"));
        MediaPlayerService::instantiate();
        ALOGI("Add MediaPlayerService on mediaserver");  // SEC_PRODUCT_FEATURE_AUDIO_COMMON
        ...
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }
}

来看一下上面几行代码的说明

1.  sp<ProcessState> proc(ProcessState::self()) 
    ProcessState没有初始化就初始化,已经初始化的话就把ProcessState的对象加一个sp。这里加sp的作用,
    可以看Android中sp/wp的说明,这里就不再赘述。那ProcessState初始化都在干什么呢?
    ProcessState::ProcessState()
        : mDriverFD(open_driver()) //这里打开Binder驱动设备
        , mVMStart(MAP_FAILED)
        , mManagesContexts(false)
        , mBinderContextCheckFunc(NULL)
        , mBinderContextUserData(NULL)
        , mThreadPoolStarted(false)
        , mThreadPoolSeq(1)
    {
        if (mDriverFD >= 0) {
            //驱动设备的mmap!!!
            mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

        }

        LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
    }

2.  sp<IServiceManager> sm = defaultServiceManager()

    sp<IServiceManager> defaultServiceManager()
    {
        if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
        {
            AutoMutex _l(gDefaultServiceManagerLock);
            while (gDefaultServiceManager == NULL) {
                gDefaultServiceManager = interface_cast<IServiceManager>(
                    ProcessState::self()->getContextObject(NULL));
                if (gDefaultServiceManager == NULL)
                    sleep(1);
            }
        }

        return gDefaultServiceManager;
    }

    sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
    {
        ...
        b = new BpBinder(handle); 
        //BpBinder为一个服务器代理客户端,handle(也就是mHandle)标识一个service。
        //一个客户端在通过transact发送Binder消息给ServiceManager的时候会发送自己的handle。
        //ServiceManager会根据这个handle来分发Binder消息给相应的服务端。
        //handle为0是ServiceManager本身

        //当然getService()找到相应的service不是通过handle,而是通过service名字
        ...
        result = b;
    }

    BpBinder强制转换成IServiceManager??

3.  MediaPlayerService::instantiate()
    void MediaPlayerService::instantiate() {
        defaultServiceManager()->addService( //
                String16("media.player"), new MediaPlayerService());
    }

    BpServiceManager::addService(){
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeStrongBinder(service);
        data.writeInt32(allowIsolated ? 1 : 0);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        //按理说应该是BnServiceManager::onTransact()函数接收!!!但其实是
        //service_manager.c文件的函数接收处理
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }
    这里的remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply)按理说应该是传到
    BnServiceManager::onTransact()函数来处理。但ServiceManager比较特殊。其实这个是传到
    service_manager.c文件中去实现了
    添加service的操作!!BnServiceManager为什么没有用呢??

4.ProcessState::self()->startThreadPool(), IPCThreadState::self()->joinThreadPool()

把相关的Server加到ServiceManger之后,Service会使用ProcessState::self()->startThreadPool()
启动一个线程(使用IPCThreadState::self()->joinThreadPool()),负责打开Binder驱动等待客户端发来消
息。下面的IPCThreadState::self()->joinThreadPool()本身也会打开一个Binder设备等待客户端消息。

看一下客户端发送Binder消息给对应的Service的流程以及Service接收到Binder消息之后的处理

1.在需要使用到Service完成功能的时候,需要按如下流程发送Binder消息

    1) 需要从ServiceManager根据Service的名字,获取相应的Service(当然如果Service没有注册的话是获取不到
    的)。

    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("media.player"));
    mOMX = service->getOMX();

    2)打包数据只会通过remote()->transact发送数据
    virtual sp<IOMX> getOMX() {
        Parcel data, reply;
        data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
        remote()->transact(GET_OMX, data, &reply);
        return interface_cast<IOMX>(reply.readStrongBinder());
    }

2.具体看一下用来发送的am->transact()函数都在干什么

    //am->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() {
        IPCThreadState::writeTransactionData();
        //负责数据的打包 
        /*   //这里的cookie和handle负责找到指定的Service并调用相应的onTransact函数
             //怎么通过cookie或者handle找到相应的onTranact函数呢????
        tr.target.ptr = 0; 
        tr.target.handle = handle;
        tr.code = code;
        tr.flags = binderFlags;
        tr.cookie = 0;
        tr.sender_pid = 0;
        tr.sender_euid = 0;
        */
        IPCThreadState::waitForResponse();//talkWithDriver()发送Binder消息
    }

3.以main_mediaserver.cpp文件为例,main函数最后会通过ProcessState::self()->startThreadPool(), IPCThreadState::self()->joinThreadPool()函数开启线程和打开Binder设备等待客户端发来消息

//来看一下调用流程
IPCThreadState::joinThreadPool()->IPCThreadState::getAndExecuteCommand() {
     talkWithDriver();
     executeCommand(cmd);
}

executeCommand()//这个函数如果发现是有Binder Transact会跑到下面部分
{
    if (tr.target.ptr) {
        sp<BBinder> b((BBinder*)tr.cookie);
        error = b->transact(tr.code, buffer, &reply, tr.flags);
    }
}
//这里tr.target.pr其实就是tr.target.handle。这里b->transact()会调用到
//BBinder::transact()->onTransact()然后怎么调用到子类的onTransact()函数的?????
/*if(tr.target.ptr)为真的分支部分是最重要的。它从binder内核驱动中获取到一个地址并转换为BBinder类型的指针(该指针在执行IServiceManager::addService()函数时放入binder内核驱动)。记住,MediaPlayerService继承自BnMediaPlayerService,BnMediaPlayerService又继承自BBinder。该指针实际上与BnMediaPlayerService实例是同一个指针。于是接下来的transact()函数将调用到BnMediaPlayerService::onTransact()/

Service的注册以及获取Servcie,然后客户端发送请求给服务端的流程如下:
1) Service启动的时候通过IServiceManager的addService()把自己加到ServiceManager中
2) addService的service参数会在Binder Driver中变成handle变量
3) Binder Driver会根据名字来管理所有的service
4) IServiceManager可以通过getService()找到已经注册的Service的Interface handle
5) android.os.IBinder.INTERFACE_TRANSACTION code来找到Interface handle的实际名字

这里写图片描述

到此上面解释完了Framework层是怎么通过Binder实现IPC了!!

http://egloos.zum.com/windom/v/1865390

Java Binder

Binder in java layer

Java层的binder机制主要涉及到以下类:
 服务层:IFooService;FooService; FooManager
其中,IFooService 接口定义服务所提供的方法,由.aidl文件实现;
FooService具体实现各个功能函数,提供具体服务;
FooManager用于注册和查找该服务;


中间层:IFooService.Stub;IFooService.Stub.Proxy
中间代码,用于实现框架封装,实际工作中由.aidl接口文件自动生成;

IPC层:Binder;BinderProxy;Parcel
BinderProxy为Binder对象在本地的代理,接收客户端传过来的数据,对其进行封装,调用JNI函数将数据发送至底层框架;
Binder接收从底层框架传过来的数据,解包,并传送至远程服务。
Parcel类对数据进行包封装。

Java 层 Binder 框架数据传递的实现

int register_android_os_Binder(JNIEnv* env)
{
    if (int_register_android_os_Binder(env) < 0)
        return -1;
    if (int_register_android_os_BinderInternal(env) < 0)
        return -1;
    if (int_register_android_os_BinderProxy(env) < 0)
        return -1;
    if (int_register_android_os_Parcel(env) < 0)
        return -1;
    return 0;
}

http://www.oss.kr/index.php?mid=oss_repository14&listStyle=list&page=5&document_srl=70352&sort_index=regdate&order_type=desc

Linux Binder驱动

#binder驱动
http://blog.csdn.net/woaieillen/article/details/8455797

待续。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值