Binder

本文详细解析了Android系统中Binder机制的工作原理,包括其作为进程间通信机制的基础作用,以及MediaServer作为示例的深入分析。文章探讨了Binder在Android C/S架构中的应用,如ServiceManager、BpBinder及IPCThreadState等核心组件的功能与交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

结合源码9、10、深入理解Android卷一

以MediaServer为例,一个可执行函数,入口函数是main

Main_MediaService.cpp

binder是Android系统提供的一种进程间通讯机制(IPC),Android系统可以看作是一个基于Binder通信的C/S框架

a、server进程要注册一些service到serviceManager中,所以server是serviceManager的客户端,        serviceManager就是服务端

b、某个client要使用service,必须先到serviceManager中获取该service的相关信息,所以client是        serviceManager的客户端

c、client根据得到的service信息与service所在的server进程建立通信的通路,然后就可以直接与          service交互,client是service的客户端

d、三者的交互都是基于binder通信的

Binder只是为C/S架构提供了一种通信的方式

  ProcessState

DefaultServiceManager

在defaultServiceManager中创建了BpBinder

 BpBinder

 

 最后还是回到interface_cast<IServiceManager>

在IServiceManager.h文件中,使用宏业务和通讯挂钩

宏定义在IInterface.h文件中

 宏替换后的实际代码

DECLEAR宏声明了一些函数和一个变量

IMPLEMENT宏的作用就是定义

IMPLEMENT宏替换如下

 interface_cast就是在IMPLEMTN宏中,将BpBinder指针转换成一个IServiceManager

intr = new BpServiceManager(obj)

    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
            const ::android::sp<::android::IBinder>& obj)               \
    {                                                                   \
        ::android::sp<I##INTERFACE> intr;                               \
        if (obj != nullptr) {                                           \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == nullptr) {                                      \
                intr = new Bp##INTERFACE(obj);  //在这里做的转换                        \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    } 

interface_cast不是指针的转换,而是利用BpBinder作为参数新建了一个BpServiceManager对象

回到IserviceManager

 a、IServiceManager、BpServiceManager和BnServiceManager都与业务逻辑相关

b、BnServiceManager同时从IServiceManager BBinder派生,表示它可以直接参与Binder通讯

c、BpServiceManager从BpInterface派生,支线上看与BpBinder没有联系

d、BnServiceManager是一个虚类,业务最终需要子类来实现

BeRefBase中的mRemote就是BpBinder

IserviceManager中包含有BpServiceManager,在BpServiceManager继承自BpInterface<IServiceManager>(impl),BpInterface又继承自BpRefBase

 跟踪到BpRefBase

在构造函数中,mRemote(o.get())就是new BpBinder(0)

 BpServiceManager的一个变量mRemote指向了BpBinder

 defaultServiceManager有两个关键对象:

有一个BpBinder对象,它的handle的值是0

有一个BpServiceManager对象,它的mRemote值是BpBinder

BpServiceManager对象实现了IserviceManager的业务函数,又有BpBinder作为通信代表

MediaPlayerService

MediaPlayerService注册,调用了defaultServiceManager的addService(),上面有分析到defaultServiceManager实际返回的对象是BpServiceManager 

addService中

 remote就是BpBinder

Parcel当作数据包

addService是一个业务层的函数,把请求数据打包成data后,传递给BpBinder的transact函数,就是把通信工作交给了BpBinder

在BpBinder的transact方法中,将数据直接交给了IPCThreadState的transact方法 

IPCThreadState

第一次进入的时候gHaveTLS一定是false

注:TLS是Thread Local Storage线程本地存储空间的简称,这种空间每个线程都有,线程间不会共享

会new一个IPCThreadState对象,构造函数中会调用pthread_setspecific

 pthread_setspecific把自己设置到线程本地存储中去

mIn和mOut是两个Parcel,发送和接收命令的缓冲区

每个线程都有一个IPCThreadState,每个IPCThreadState中都有一个mIn,mOut,mIn是用来接收来自Binder设备的数据,mOut是用来存储发往Binder设备的数据

 再到IPCThreadState的transact,这个函数实际完成了与Binder通信的工作

 先发数据,再等结果

先看发送方法writeTransactionData

 binder_transaction_data是和binder设备通信的数据结构

code是消息码

mOut将命令写入,但没有发送出去,到这里,将addService的请求信息已经写到mOut中

 等待回复waitForResponse

收到回复后的处理executeCommand(cmd)

   case BR_TRANSACTION:
        {
            binder_transaction_data_secctx tr_secctx;
            binder_transaction_data& tr = tr_secctx.transaction_data;

            if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
                result = mIn.read(&tr_secctx, sizeof(tr_secctx));
            } else {
                result = mIn.read(&tr, sizeof(tr));
                tr_secctx.secctx = 0;
            }

            ALOG_ASSERT(result == NO_ERROR,
                "Not enough command data for brTRANSACTION");
            if (result != NO_ERROR) break;

            //Record the fact that we're in a binder call.
            mIPCThreadStateBase->pushCurrentState(
                IPCThreadStateBase::CallState::BINDER);
            Parcel buffer;
            buffer.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);

            const pid_t origPid = mCallingPid;
            const char* origSid = mCallingSid;
            const uid_t origUid = mCallingUid;
            const int32_t origStrictModePolicy = mStrictModePolicy;
            const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
            const int32_t origWorkSource = mWorkSource;
            const bool origPropagateWorkSet = mPropagateWorkSource;
            // Calling work source will be set by Parcel#enforceInterface. Parcel#enforceInterface
            // is only guaranteed to be called for AIDL-generated stubs so we reset the work source
            // here to never propagate it.
            clearCallingWorkSource();
            clearPropagateWorkSource();

            mCallingPid = tr.sender_pid;
            mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
            mCallingUid = tr.sender_euid;
            mLastTransactionBinderFlags = tr.flags;

            // ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid,
            //    (mCallingSid ? mCallingSid : "<N/A>"), mCallingUid);

            Parcel reply;
            status_t error;
            IF_LOG_TRANSACTIONS() {
                TextOutput::Bundle _b(alog);
                alog << "BR_TRANSACTION thr " << (void*)pthread_self()
                    << " / obj " << tr.target.ptr << " / code "
                    << TypeCode(tr.code) << ": " << indent << buffer
                    << dedent << endl
                    << "Data addr = "
                    << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
                    << ", offsets addr="
                    << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
            }
            if (tr.target.ptr) {
                // We only have a weak reference on the target object, so we must first try to
                // safely acquire a strong reference before doing anything else with it.
                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);
            }

            mIPCThreadStateBase->popCurrentState();
            //ALOGI("<<<< TRANSACT from pid %d restore pid %d sid %s uid %d\n",
            //     mCallingPid, origPid, (origSid ? origSid : "<N/A>"), origUid);

            if ((tr.flags & TF_ONE_WAY) == 0) {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                if (error < NO_ERROR) reply.setError(error);
                sendReply(reply, 0);
            } else {
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
            }

            mCallingPid = origPid;
            mCallingSid = origSid;
            mCallingUid = origUid;
            mStrictModePolicy = origStrictModePolicy;
            mLastTransactionBinderFlags = origTransactionBinderFlags;
            mWorkSource = origWorkSource;
            mPropagateWorkSource = origPropagateWorkSet;

            IF_LOG_TRANSACTIONS() {
                TextOutput::Bundle _b(alog);
                alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
                    << tr.target.ptr << ": " << indent << reply << dedent << endl;
            }

        }
        break;

 the_context_object是IPCThreadState.cpp中定义的一个全局变量

可通过setTheContextObject函数设置

 收到binder驱动发来的service死掉的消息

 这里收到来自驱动的指示,创建一个新的线程,用于和binder通信

 

talkWithDriver()

ProcessState

startThreadPool()

如果已经mThreadPoolStarted,函数没有下一步 

调用spawnPooledThread(true)

 在PoolThread中创建一个IPCThreadState,每个线程都有一个,但线程不共享,调用joinThreadPool(true)

来到joinThreadPool(true)

 isMain为true,需要循环处理,把请求信息写到mOut中,后续会发送出去

getAndExecuteCommand处理消息

组装请求信息到mOut中,最后调用talkWithDriver(false)

 有两个线程在为service服务:

startThreadPool中新启动的线程通过joinThreadPool读取Binder设备,查看是否有请求

主线程也调用joinThreadPool读取binder设备,查看是否有请求

Binder设备是支持多线程操作的

Binder是通信机制,业务可以基于Binder通信,也可以使用别的IPC通信

defultServiceManager返回的是一个BpServiceManager,通过它可以把命令请求发送给handle值为0的目的端

 应该有一个类从BnServiceManager中派生出来,并处理来自远方的请求,源码中并没有,是ServiceManager完成了BnServiceManager的工作

篇幅有限,下篇继续
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值