Android10.0 Binder通信原理(四)-Native-C\C++实例分析_第四节-android10.0 binder通信原理(四)-native- c\c++实例分析-程序员宅基地

技术标签: # 2.进程间通信  vndbinder  servicemanager  Android取经之路  Android10.0  binder  hwbinder  

摘要:本节主要来讲解Android10.0 Binder的Native层实例流程

阅读本文大约需要花费35分钟。

文章首发微信公众号:IngresGe

专注于Android系统级源码分析,Android的平台设计,欢迎关注我,谢谢!

欢迎关注我的公众号!

[Android取经之路] 的源码都基于Android-Q(10.0) 进行分析

[Android取经之路] 系列文章:

《系统启动篇》

  1. Android系统架构
  2. Android是怎么启动的
  3. Android 10.0系统启动之init进程
  4. Android10.0系统启动之Zygote进程
  5. Android 10.0 系统启动之SystemServer进程
  6. Android 10.0 系统服务之ActivityMnagerService
  7. Android10.0系统启动之Launcher(桌面)启动流程
  8. Android10.0应用进程创建过程以及Zygote的fork流程
  9. Android 10.0 PackageManagerService(一)工作原理及启动流程
  10. Android 10.0 PackageManagerService(二)权限扫描
  11. Android 10.0 PackageManagerService(三)APK扫描
  12. Android 10.0 PackageManagerService(四)APK安装流程

《日志系统篇》

  1. Android10.0 日志系统分析(一)-logd、logcat 指令说明、分类和属性
  2. Android10.0 日志系统分析(二)-logd、logcat架构分析及日志系统初始化
  3. Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析
  4. Android10.0 日志系统分析(四)-selinux、kernel日志在logd中的实现​

《Binder通信原理》

  1. Android10.0 Binder通信原理(一)Binder、HwBinder、VndBinder概要
  2. Android10.0 Binder通信原理(二)-Binder入门篇
  3. Android10.0 Binder通信原理(三)-ServiceManager篇
  4. Android10.0 Binder通信原理(四)-Native-C\C++实例分析
  5. Android10.0 Binder通信原理(五)-Binder驱动分析
  6. Android10.0 Binder通信原理(六)-Binder数据如何完成定向打击
  7. Android10.0 Binder通信原理(七)-Framework binder示例
  8. Android10.0 Binder通信原理(八)-Framework层分析
  9. Android10.0 Binder通信原理(九)-AIDL Binder示例
  10. Android10.0 Binder通信原理(十)-AIDL原理分析-Proxy-Stub设计模式
  11. Android10.0 Binder通信原理(十一)-Binder总结

  《HwBinder通信原理》

  1. HwBinder入门篇-Android10.0 HwBinder通信原理(一)
  2.  HIDL详解-Android10.0 HwBinder通信原理(二)
  3. HIDL示例-C++服务创建Client验证-Android10.0 HwBinder通信原理(三)
  4. HIDL示例-JAVA服务创建-Client验证-Android10.0 HwBinder通信原理(四)
  5. HwServiceManager篇-Android10.0 HwBinder通信原理(五)
  6. Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)
  7. Native层HIDL服务的获取原理-Android10.0 HwBinder通信原理(七)
  8. JAVA层HIDL服务的注册原理-Android10.0 HwBinder通信原理(八)
  9. JAVA层HIDL服务的获取原理-Android10.0 HwBinder通信原理(九)
  10. HwBinder驱动篇-Android10.0 HwBinder通信原理(十)
  11. HwBinder原理总结-Android10.0 HwBinder通信原理(十一)

《编译原理》

  1. 编译系统入门篇-Android10.0编译系统(一)
  2. 编译环境初始化-Android10.0编译系统(二)
  3. make编译过程-Android10.0编译系统(三)
  4. Image打包流程-Android10.0编译系统(四)
  5. Kati详解-Android10.0编译系统(五)

1.概述

在上一节中,我们知道了ServiceManager的启动过程,注册、获取服务的细节处理。服务的信息都存在于一个全局变量svclist的链表中。

svclist对应的结构为svcinfo,其中有两个成员很重要:handle 和name,handle代表了service的句柄,我们也可以理解为service的实体, name为service的名称。

那么这个service的Binder句柄-handle是怎么来的?在Native层,我们是如何进行注册、获取服务的,还不清楚。

这一节,我们用一个Native层的实例来进行分析。

遵循了不少网络大神的路线,也通过media的服务来进行分析。media的Binder服务注册,是一个很典型的Binder服务注册流程。

 

2. Native层的Binder架构

服务端存在一个Binder实体--BBinder,以及对应的实体接口--BnInterface;

客户端存在一个Binder代理--BpBinder,以及对应的代理接口--BpInterface

服务端通过Binder驱动向ServiceManager进行注册,把BBinder的实体对象存入ServiceManager,对应svcinfo的handle;

客户端通过Binder驱动向ServiceManager发起查询请求,获取到service的Binder句柄--handle,进行一层转换变成BpBinder;

客户端拿到了服务的代理后,就可以调用服务的代理接口来实现相应的功能。

 

3. 看源码前的思考?

假如是你,该如何来注册、获取一个服务?

 

按照我们正常的设计方法,服务注册该走下面几步
  1)定义一个服务的名字

2)生成一个服务本身的实体BBinder

4)通过ServiceManager的代理接口,调用addService()这种接口实现服务注册,传入“服务名称”和“服务对象实体”,用来和ServiceManager的name-handle进行对应

5)开启一个线程池,把当前的线程加入线程池,方便管理,防止主线程的阻塞

 

服务获取该走下面几步:

1)获取ServiceManager的代理对象,用于和ServiceManager进行通信

2)通过ServiceManager的代理接口,调用getService()这种接口来获取指向服务实体的代理接口

3)客户端通过调用已得到的service代理的成员函数,把自己的binder实体作为参数,传递到目标service进程

4)获得合法的服务代理对象

 

4.几个概念 的提前理解

在真正看代码前,需要先了解两个类-ProcessState和IPCThreadState 这两个很重要类的概念。

4.1 ProcessState

ProcessState从字面意思可以理解,表示是“进程状态”,代表了这个进程的行为,Android中,每个进程都是独立的,所以每个进程都要有一个“进程状态”--ProcessState.

在Binder通信机制中,ProcessState使用了单例模式,即一个进程只有个ProcessState对象,一个进程中有很多个线程,不能每个线程都来new一个新的ProcessState(),采用单例模式后,每个线程都可以使用同一个ProcessState来和Binder驱动通信。

ProcessState作为进程状态的记录器,主要用来打开Binder驱动获取句柄,mmap申请一块(1M-8K)的内存空间,设置Binder线程最大个数。

 

4.2 IPCThreadState

IPCThreadState从字面意思可以理解,表示是“进程间通信的线程状态”,有了进程状态后,自然需要有线程状态。

ProcessState代表了进程,IPCThreadState代表了线程。Android系统中有很多进程,进程间相互隔离,每个进程内部又有很多线程,线程之间也是相互独立的。所以说一个进程会存在很多个线程,每个线程都有自己的“线程状态”--IPCThreadState对象.这个对象存储在线程的本地存储区(TLS:Thread local storage)中,每个线程都拥有自己的TLS,并且是私有空间,线程之间不会共享。

IPCThreadState对象根据key:gTLS去进行存储。通过pthread_getspecific/pthread_setspecific函数可以获取/设置这些空间中的内容。

 IPCThreadState负责与Binder驱动进行数据交互。

 

4.3 BpBinder

BpBinder 展开后就是Binder Proxy,也就是Binder代理的含义。BpBinder是客户端用来与服务交互的代理类,负责实现跨进程传输的传输机制,不关心具体的传输内容。通信功能由其它类和函数实现,但由于这些类和函数被BpBinder代理,所以客户端需要通过BpBinder来发送Binder通信数据。       

 

4.4 BBinder

BBinder代表服务端,可以理解为服务的Binder实体,当服务端从Binder驱动中读取到数据后,由BBinder类进行处理。

 

5 Media的服务注册

5.1 main()

[/frameworks/av/media/mediaserver/main_mediaserver.cpp]
int main(int argc __unused, char **argv __unused)
{
    signal(SIGPIPE, SIG_IGN);

    sp<ProcessState> proc(ProcessState::self());     //获得ProcessState实例对象
    sp<IServiceManager> sm(defaultServiceManager()); //获取BpServiceManager对象
    ALOGI("ServiceManager: %p", sm.get());
    AIcu_initializeIcuOrDie();
    MediaPlayerService::instantiate();   //注册多媒体服务
    ResourceManagerService::instantiate();
    registerExtensions();
    ProcessState::self()->startThreadPool();    //启动Binder线程池
    IPCThreadState::self()->joinThreadPool();   //当前线程加入到线程池
}

media的服务注册流程分为以下几步:

  1. 获得ProcessState实例对象
  2. 获取ServiceManager的代理对象--BpServiceManager
  3. 注册media服务
  4. 启动Binder线程池
  5. 把当前线程加入到线程池

 

5.2 ProcessState::self()

前面我们已经知道了ProcessState代表了进程状态,一个进程只有一个ProcessState对象。ProcessState采用了单例的模式保存了一个ProcessState全局对象--gProcess,共每个线程使用。

从下面的文件可以猜到ProcessState.cpp 存在于一个so库中,即libbinder.so, service 进程调用libbinder.so进行Binder通信。


[/frameworks/native/libs/binder/ProcessState.cpp]
#ifdef __ANDROID_VNDK__
const char* kDefaultDriver = "/dev/vndbinder";
#else
const char* kDefaultDriver = "/dev/binder";
#endif
sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
        //ProcessState的实例存在,直接返回该实例对象--单例模式
    if (gProcess != nullptr) {
        return gProcess;
    }
        //实例化ProcessState,kDefaultDriver 根据VNDK的宏定义来决定当前进程使用"/dev/binder" 还是"/dev/vndbinder"
    gProcess = new ProcessState(kDefaultDriver);
    return gProcess;
}

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
    , mDriverFD(open_driver(driver))        //打开驱动,根据VNDK的宏定义来决定当前进程使用"/dev/binder" 还是"/dev/vndbinder",假设为"/dev/binder"
    , mVMStart(MAP_FAILED)
    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
    , mExecutingThreadsCount(0)
    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)        //Binder线程的最大个数16
    , mStarvationStartTimeMs(0)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(nullptr)
    , mBinderContextUserData(nullptr)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
    , mCallRestriction(CallRestriction::NONE)
{
    if (mDriverFD >= 0) {
        // 向Binder驱动申请一块(1M-8K)的虚拟地址空间来接收事务。
        mVMStart = mmap(nullptr, 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.");
}

ProcessState的对象创建也比较简单,根据VNDK的宏定义来决定当前进程使用"/dev/binder" 还是"/dev/vndbinder"来打开了binder驱动,这里假设为"/dev/binder"。向Binder驱动申请一块(1M-8K)的虚拟地址空间来接收事务。(1M-8K)在前面的入门篇已经讲解原因,这里不重复说明。

几个变量展示:
    mDriverFD:Binder驱动打开后,记录的句柄,用于访问Binder设备

mMaxThreads:最大Binder线程个数

BINDER_VM_SIZE: ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2),其中_SC_PAGE_SIZE为4K,即一个物理页的大小为4K,最终为(1M-8K)

 

 

5.3 获取ServiceManager代理对象

--defaultServiceManager()

当服务进程获取到了ProcessState对象后,接下来要拿到ServiceManager的代理对象--BpServiceManager。

[/frameworks/native/libs/binder/IServiceManager.cpp]
sp<IServiceManager> defaultServiceManager()
{
    if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;
    {
        AutoMutex _l(gDefaultServiceManagerLock);
            //当ServiceManager还未准备好,等待1秒后重新获取ServiceManager对象
        while (gDefaultServiceManager == nullptr) {
            gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(nullptr));
            if (gDefaultServiceManager == nullptr)
                sleep(1);
        }
    }
    return gDefaultServiceManager;
}

ServiceManager的对象获取也采用了一个单例模式,一个进程中只要获取一次即可,对象存储在gDefaultServiceManager中。

主要流程如下:

  1. 获取ProcessState对象---ProcessState::self(),在上面的流程中可知ProcessState已获取,存入了全局变量中
  2. 获取BpBinder对象 --ProcessState::getContextObject(nullptr)
  3. 获取BpServiceManager对象----interface_cast<IServiceManager>

 

5.3.1 ProcessState::getContextObject()

getContextObject()调用getStrongProxyForHandle()进行处理,传入handle=0,在前面ServiceManager那一节我们知道,系统中约定了ServiceManager的handle=0


sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    AutoMutex _l(mLock);
       //查找handle对应的资源项
    handle_entry* e = lookupHandleLocked(handle);

    if (e != nullptr) {
        IBinder* b = e->binder;
        if (b == nullptr || !e->refs->attemptIncWeak(this)) {
            if (handle == 0) {
                Parcel data;
                     //通过ping操作测试binder是否准备就绪
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, nullptr, 0);
                if (status == DEAD_OBJECT)
                   return nullptr;
            }
                 //当handle值所对应的IBinder不存在或弱引用无效时,创建一个BpBinder,handle=0
                 //create的实现其实就是  new BpBinder(0,trackedUid)
            b = BpBinder::create(handle);
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

getStrongProxyForHandle()的过程也很简单,当handle=0所对应的IBinder不存在或弱引用无效时,先看下Binder是否已经准备就绪,即ServiceManager是否已经就绪,准备好后,创建一个BpBinder(0,trackedUid),创建BpBinder对象中会将handle相对应Binder的弱引用增加1,最终返回一个BpBiner的对象。

即当Service向ServiceManager进行注册时,Service变成了Client,ServiceManager变成了Server,需要先把Service 转换成一个BpBinder对象,作为Binder代理进行通信。

所以 ProcessState::getContextObject() 就相当于 new BpBinder(0,trackedUid)

 

5.3.2 interface_cast<IServiceManager>

真正获取ServiceManager的代理对象的是 interface_cast<IServiceManager> 方法。

[/frameworks/native/libs/binder/include/binder/IInterface.h]
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

这里采用了C++的模板函数,interface_cast<IServiceManager>其实就是调用了IServiceManager::asInterface(obj);  这里的obj 就是new BpBinder(0)。

但是IServiceManager中没有看到 asInterface()的实现,我们就在IInterface.h 进行查找,找到了asInterface()实现,分别在申明--DECLARE_META_INTERFACE和实现--IMPLEMENT_META_INTERFACE中


#define DECLARE_META_INTERFACE(INTERFACE)                               \
public:                                                                 \
    static const ::android::String16 descriptor;                        \
    static ::android::sp<I##INTERFACE> asInterface(                     \
            const ::android::sp<::android::IBinder>& obj);              \
    virtual const ::android::String16& getInterfaceDescriptor() const;  \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \
    static bool setDefaultImpl(std::unique_ptr<I##INTERFACE> impl);     \
    static const std::unique_ptr<I##INTERFACE>& getDefaultImpl();       \
private:                                                                \
    static std::unique_ptr<I##INTERFACE> default_impl;                  \
public:                                                                 \

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
    const ::android::String16&                                          \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    ::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;                                                    \
    }                                                                   \
    std::unique_ptr<I##INTERFACE> I##INTERFACE::default_impl;           \
    bool I##INTERFACE::setDefaultImpl(std::unique_ptr<I##INTERFACE> impl)\
    {                                                                   \
        if (!I##INTERFACE::default_impl && impl) {                      \
            I##INTERFACE::default_impl = std::move(impl);               \
            return true;                                                \
        }                                                               \
        return false;                                                   \
    }                                                                   \
    const std::unique_ptr<I##INTERFACE>& I##INTERFACE::getDefaultImpl() \
    {                                                                   \
        return I##INTERFACE::default_impl;                              \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }                                   \


#define CHECK_INTERFACE(interface, data, reply)                         \
    do {                                                                \
      if (!(data).checkInterface(this)) { return PERMISSION_DENIED; }   \
    } while (false)

IServiceManager 中的使用方法:

DECLARE_META_INTERFACE(ServiceManager)

IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

我这里就不进行展开了,有兴趣的可以尝试一下,最终IServiceManager::asInterface() 等价于 new Bp##INTERFACE(obj),即 new BpServiceManager(obj)

所以gDefaultServiceManager = interface_cast<IServiceManager>(ProcessState::self()->getContextObject(nullptr));

转换后,变成 所以gDefaultServiceManager =new BpServiceManager(new BpBinder(0,trackedUid));

 

BpServiceManager()的继承有必要展开下,方便后面的分析:

1)class BpServiceManager : public BpInterface<IServiceManager>

2)class BpInterface : public INTERFACE, public BpRefBase

3)class BpRefBase : public virtual RefBase

 

下面的mRemote(o.get()) ,其实就是拿到传入的obj,即为 new BpBinder(0,trackedUid)

BpRefBase::BpRefBase(const sp<IBinder>& o)
    : mRemote(o.get()), mRefs(nullptr), mState(0)
{
    extendObjectLifetime(OBJECT_LIFETIME_WEAK);
    if (mRemote) {
        mRemote->incStrong(this);           // Removed on first IncStrong().
        mRefs = mRemote->createWeak(this);  // Held for our entire lifetime.
    }
}

5.4 MediaPlayerService::instantiate()

[/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp]
void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}

defaultServiceManager()->addService()等价调用 BpServiceManager::addService(),其中service的name是“media.player”,service的对象是“new MediaPlayerService()”

MediaPlayerService 继承自BnMediaPlayerService,BnMediaPlayerService继承自BnInterface,BnInterface继承自BBinder,最终转换为一个Binder实体 --BBinder对象。

类的继承关系如下

继续往下看BpServiceManager::addService()是如何工作的

[/frameworks/native/libs/binder/IServiceManager.cpp]
virtual status_t addService(const String16& name, const sp<IBinder>& service,
                            bool allowIsolated, int dumpsysPriority) {
    Parcel data, reply;        //定义一个data和reply的Parcel数据包
     //写入RPC头信息"android.os.IServiceManager"
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);        //服务名为 "media.player"
    data.writeStrongBinder(service);        //把一个binder实体“打扁”并写入parcel, 服务的实体对象:new MediaPlayerService()
    data.writeInt32(allowIsolated ? 1 : 0); //allowIsolated= false
    data.writeInt32(dumpsysPriority);        //dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT
    //remote()函数返回的是mRemote,就是BpRefBase中的mRemote,即BpBinder对象。这里调用了BpBinder的transact()方法
    status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    return err == NO_ERROR ? reply.readExceptionCode() : err;
}

主要流程:

  1. 准备两个Parcel结构--data,reply
  2. 组装Parcel数据
  3. 写入头信息"android.os.IServiceManager
  4. 写入服务名-- "media.player"
  5. 写入服务的实体对象--new MediaPlayerService()
  6. 调用remote的transact,发送ADD_SERVICE_TRANSACTION 的命令进行服务的注册
  7. 得到返回的reply数据

最核心的就是 remote()->transact(ADD_SERVICE_TRANSACTION,XXX), 这里的remote()函数返回的是mRemote,在上面我们理解到mRemote其实就是new BpBinder(0,trackedUid)最终转换为  BpBinder->transact(ADD_SERVICE_TRANSACTION,XXX)。

上面有一个要注意的地方data.writeStrongBinder(service); 最终调用的是flatten_binder(),目的是把一个Binder实体“压扁”并写入Parcel。这里"压扁"的含义,其实就是把Binder对象整理成flat_binder_object变量。如果压扁的是Binder实体,那么flat_binder_object用cookie域记录binder实体的指针,即BBinder指针,而如果打扁的是Binder代理,那么flat_binder_object用handle域记录的binder代理的句柄值。

[/frameworks/native/libs/binder/Parcel.cpp]
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;

    if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
        /* minimum priority for all nodes is nice 0 */
        obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
    } else {
        /* minimum priority for all nodes is MAX_NICE(19) */
        obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    }

    if (binder != nullptr) {
        BBinder *local = binder->localBinder(); //是否是Binder实体
        if (!local) {
            //是binder代理
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == nullptr) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;//记录Binder代理的句柄
            obj.hdr.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; 
            obj.handle = handle;
            obj.cookie = 0; 
        } else {
            //是binder实体
            if (local->isRequestingSid()) {
                obj.flags |= FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
            }
            obj.hdr.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);    //cookie记录Binder实体的指针
        }
    } else {
        obj.hdr.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
    }

    return finish_flatten_binder(binder, obj, out);
}

接着flatten_binder()调用了一个关键的finish_flatten_binder()函数。这个函数内部会记录下刚刚被扁平化的flat_binder_object在parcel中的位置。说得更详细点儿就是,parcel对象内部会有一个buffer,记录着parcel中所有扁平化的数据,有些扁平数据是普通数据,而另一些扁平数据则记录着binder对象。所以parcel中会构造另一个mObjects数组,专门记录那些binder扁平数据所在的位置,示意图如下:

接下来看看传输过程BpBinder->transact(ADD_SERVICE_TRANSACTION,XXX)。

 

5.4.1  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;
}

BpBinder::transact()就是调用IPCThreadState::self()->transact() 进行处理

 

5.4.2 IPCThreadState::transact()


status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err;

    flags |= TF_ACCEPT_FDS;
    ...
    // 传输数据
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);

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

    if ((flags & TF_ONE_WAY) == 0) {
        if (UNLIKELY(mCallRestriction != ProcessState::CallRestriction::NONE)) {
            if (mCallRestriction == ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY) {
                ALOGE("Process making non-oneway call but is restricted.");
                CallStack::logStack("non-oneway call", CallStack::getCurrent(10).get(),
                    ANDROID_LOG_ERROR);
            } else /* FATAL_IF_NOT_ONEWAY */ {
                LOG_ALWAYS_FATAL("Process may not make oneway calls.");
            }
        }
        //等待响应
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        ...
    } else {
        //oneway,则不需要等待reply的场景
        err = waitForResponse(nullptr, nullptr);
    }

    return err;
}

IPCThreadState::transact()主要做了下面几步:

  1. writeTransactionData() 组装一个binder_transaction_data 结构的数据,存入        mOut中,mOut是一个Parcel的数据结构,处理的时候,前4个字节存入BC_XX 请求码,这里是BC_TRANSACTION,后面存入sizeof(binder_transaction_data)长度的数据
  2. waitForResponse() 等待响应。

writeTransactionData 代码如下:


status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
    binder_transaction_data tr;  //申请一个binder_transaction_data的结构

    tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
    tr.target.handle = handle;
    tr.code = code;
    tr.flags = binderFlags;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    const status_t err = data.errorCheck();  //错误检查
    if (err == NO_ERROR) {
        //把Parcel的数据转换到binder_transaction_data中
        tr.data_size = data.ipcDataSize();
            // 这部分是待传递数据
        tr.data.ptr.buffer = data.ipcData(); 
            // 这部分是扁平化的binder对象在数据中的具体位置
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }

    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}

writeTransactionData() 主要就是把传入的Parcel数据,转换成binder_transaction_data,写入mOut,用来与Binder驱动交互。其中tr.data.ptr.buffer 记录了Parcel传输的数据,tr.data.ptr.offsets记录下“待传数据”中所有binder对象的具体位置,如下图所示:

当binder_transaction_data传递到binder驱动层后,驱动层可以准确地分析出数据中到底有多少binder对象,并分别进行处理,从而产生出合适的红黑树节点(Binder驱动层再分析,这里了解即可)。

此时,如果产生的红黑树节点是binder_node的话,binder_node的cookie域会被赋值成flat_binder_object所携带的cookie值,也就是用户态的BBinder地址值。

这个新生成的binder_node节点被插入红黑树后,会一直严阵以待,以后当它成为另外某次传输动作的目标节点时,它的cookie域就派上用场了,此时cookie值会被反映到用户态,于是用户态就拿到了BBinder对象。

waitForResponse() 先调用talkWithDriver() 把mOut的数据发给Binder驱动,Binder驱动再和ServiceManager进行交互,进行服务注册,然后ServiceManager解析完成后,调用binder_send_reply()把返回的数据发送出来,其中的cmd为BR_XXX 响应码,请求的数据存入到IPCThreadState mIn的Parcel结构中.

waitForResponse()根据 Binder驱动发来的BR_XXX请求码,进行相应的处理。

mOut里面的BC_XXX请求码为 BC_TRANSACTION, 根据Binder驱动中的交互流程,会先发一个 BR_TRANSACTION_COMPLETE响应码,目标进程收到事务后,处理BR_TRANSACTION事务,然后发送给当前进程,再执行BR_REPLY命令。

waitForResponse()里面是一个while(1)循环,可以处理多个命令,只有进入goto finish后,循环才推出。

协议码转换的流程,到下一节的Binder 驱动一节进行详细分析,这里只要了解一个大概即可,不要陷入死胡同。


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

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...

        cmd = (uint32_t)mIn.readInt32();

        switch (cmd) {
        case BR_TRANSACTION_COMPLETE: ...
            break;

        case BR_DEAD_REPLY: ...
            goto finish;

        case BR_FAILED_REPLY: ...
            goto finish;

        case BR_ACQUIRE_RESULT: ...
            goto finish;

        case BR_REPLY: ...
            goto finish;

        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }
finish:
    if (err != NO_ERROR) {
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }
    ...
    return err;
}

talkWithDriver()用来不停的和Binder驱动进行通信,ioctl()函数在传递BINDER_WRITE_READ语义时,既会使用“输入buffer”,也会使用“输出buffer”,所以IPCThreadState专门搞了两个Parcel类型的成员变量:mIn和mOut。mOut中的内容发出去,发送后的回复写进mIn。

BINDER_WRITE_READ的命令发给Binder驱动后,ServiceManager有个循环不停的解析Binder驱动的BINDER_WRITE_READ信息,调用binder_parse()进行解析,我们前面addService()时,传入的code为ADD_SERVICE_TRANSACTION,在ServiceManager中解析后,对应的值为SVC_MGR_ADD_SERVICE,最终把服务的name和handle(对象) 存入到svclist中,ServiceManager再通过binder_send_reply()把返回的数据发送出来,在talkWithDriver()中填入mIn中,waitForResponse()进行最终的语义处理,发送出去。


status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    if (mProcess->mDriverFD <= 0) {
        return -EBADF;
    }

    binder_write_read bwr;

    ...
    //如果仍在读取输入缓冲区中剩余的数据,并且调用方已请求读取下一个数据,则不希望写入任何内容。
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();  //把mOut的数据存入 write_buffer中,

    // This is what we'll read.
    if (doReceive && needRead) {
        //接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        //没有收到数据时,把read置空,binder只进行write处理
        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 {
    ...
#if defined(__ANDROID__)
        //通过ioctl不停的读写操作,跟Binder Driver进行通信
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
        if (mProcess->mDriverFD <= 0) {
            err = -EBADF;
        }
        ...
    } while (err == -EINTR);//当被中断,则继续执行


    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else {
                mOut.setDataSize(0);
                processPostWriteDerefs();
            }
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        ...
        return NO_ERROR;
    }

    return err;
}

 

mIn和mOut的data会先整理进一个binder_write_read结构,然后再传给ioctl()函数。此时使用的文件描述符就是前文我们说的ProcessState中记录的mDriverFD,说明是向binder驱动传递语义。BINDER_WRITE_READ表示我们希望读写一些数据。这样就完成了BpBinder向远端--ServiceManager发起的传输流程。

waitForResponse()收到BR_TRANSACTION响应码后,调用BBinder的transact()进行处理。

status_t IPCThreadState::executeCommand(int32_t cmd)
{
...
 case BR_TRANSACTION:
    if (tr.target.ptr) {
        if (reinterpret_cast<RefBase::weakref_type*>(
                tr.target.ptr)->attemptIncStrong(this)) {
                 //这里的cookie就是驱动层binder_node 节点的cookie发挥作用,拿到了一个合法的BBinder
            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);
    }
 ...
}

BBinder->transact() 中最重要的就是onTransact(),binder实体在本质上都是继承于BBinder的,而且我们一般都会重载onTransact()函数,所以上面这句onTransact()实际上调用的是具体binder实体的onTransact()成员函数。

uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);

    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            reply->writeInt32(pingBinder());
            break;
        default:
            err = onTransact(code, data, reply, flags);
            break;
    }

    if (reply != nullptr) {
        reply->setDataPosition(0);
    }

    return err;
}

MediaPlayerService 继承自BnMediaPlayerService,最终继承自BBinder,上面执行onTransact时,其实对应的BBinder实体,也会执行该函数,就进入了BnMediaPlayerService::onTransact。

status_t BnMediaPlayerService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
....
}

注册服务的流程简单的总结一下:

  1. 服务进程先获得一个 ProcessState()的对象
  2. 获取ServiceManager的代理对象BpServiceManager,主要通过new BpBinder(0,xxx)得到。
  3. 调用BpServiceManager的addService,组装一个Parce数据,传入服务名称、服务实体对象--BBinder、执行code-ADD_SERVICE_TRANSACTION
  4. 先通过IPCThreadThread的writeTransactionData()把上面的Parcel数据写入mOut,用来进行发送
  5. 通过IPCThreadThread的talkWithDriver()与Binder驱动通信,传递语义BINDER_WRITE_READ
  6. ServiceManager有个循环不停的解析Binder驱动的BINDER_WRITE_READ信息,调用binder_parse()进行解析
  7. ServiceManager中解析后,ADD_SERVICE_TRANSACTION对应的值为SVC_MGR_ADD_SERVICE,最终把服务的name和handle存入到svclist中,ServiceManager再通过binder_send_reply()把返回的数据发送出来,在talkWithDriver()中填入mIn中,waitForResponse()进行最终的语义处理
  8. waitForResponse()收到BR_TRANSACTION响应码后,最终后调用executeCommand()进行命令执行,根据逻辑处理,最终会调用到Binder实体的onTransact(),例如这里的BnMediaPlayerService::onTransact()
  9. 最终完成服务的注册流程

 

6 获取media的服务

在第5节中,我们了解了media服务的注册流程,接下来我们一起看看,其他进程是如何获取media的服务来进行通信。

在ServiceManager一节,我们知道了注册、获取服务我们都要通过ServiceManager进行处理,所以获取服务,大体还是分为下面几步

  1. 获取ServiceManager的代理对象BpServiceManager,用于和ServiceManager进行通信
  2. 通过ServiceManager的代理接口,调用getService()这种接口来获取指向服务实体的代理接口
  3. 客户端通过调用已得到的service代理的成员函数,把自己的binder实体作为参数,传递到目标service进程
  4. 获得合法的服务代理对象

获取media服务序列图

 

6.1 IMediaDeathNotifier::getMediaPlayerService()

[/frameworks/av/media/libmedia/IMediaDeathNotifier.cpp]
IMediaDeathNotifier::getMediaPlayerService()
{
    ALOGV("getMediaPlayerService");
    Mutex::Autolock _l(sServiceLock);
    if (sMediaPlayerService == 0) {
            //获取ServiceManager的代理对象BpServiceManager
        sp<IServiceManager> sm = defaultServiceManager();
        sp<IBinder> binder;
        do {
                 //调用BpServiceManager的getService接口,来获取服务名称为“media.player”的Binder 服务对象
            binder = sm->getService(String16("media.player"));
            if (binder != 0) {
                break;
            }
            ALOGW("Media player service not published, waiting...");
            usleep(500000); // 如果media的服务还没有准备好,休眠0.5秒进行等待
        } while (true);

        if (sDeathNotifier == NULL) {
            sDeathNotifier = new DeathNotifier();        //创建死亡通知对象
        }
        binder->linkToDeath(sDeathNotifier);//将死亡通知连接到binder
               //转换得到服务对象
        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
    }
    ALOGE_IF(sMediaPlayerService == 0, "no media player service!?");
    return sMediaPlayerService;
}

流程如下:

  1. 获取ServiceManager的代理对象BpServiceManager
  2. 调用BpServiceManager的getService接口,来获取服务名称为“media.player”的Binder 服务对象
  3. 创建死亡通知对象
  4. 将死亡通知连接到binder
  5. 得到服务对象

通过defaultServiceManager()来获取ServiceManager的对象,参考[6.1.3],我们接下来主要来看getService的流程

 

6.2 BpServiceManager::getService()

defaultServiceManager->getService()其实就是BpServiceManager->getService。
virtual sp<IBinder> getService(const String16& name) const
{
    //检索指定服务是否存在
    sp<IBinder> svc = checkService(name);
    if (svc != nullptr) return svc;

    //如果ProcessState和Binder驱动交互的是"/dev/vndbinder",那么isVendorService为True,表明Vendor进程之间可以进行Binder通信
    const bool isVendorService =
        strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
    const long timeout = uptimeMillis() + 5000;


    if (!gSystemBootCompleted && !isVendorService) {
        //vendor分区的代码不能访问system的属性
        char bootCompleted[PROPERTY_VALUE_MAX];
        property_get("sys.boot_completed", bootCompleted, "0");
        gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
    }

    //vendor分区的服务sleepTime 为100ms, system为1000ms
    const long sleepTime = gSystemBootCompleted ? 1000 : 100;

    int n = 0;
    while (uptimeMillis() < timeout) {
        n++;
        ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
            ProcessState::self()->getDriverName().c_str());
        usleep(1000*sleepTime);
        
        sp<IBinder> svc = checkService(name);
        if (svc != nullptr) return svc;
    }
    ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
    return nullptr;
}

getService()的核心就是调用checkService()来检查服务是否存在,如果不存在,继续等待查找。注意:vendor分区的服务等待时间为100ms,system分区的为1000ms.

 

6.3 BpServiceManager::checkService()

checkService()和前面的addService类似,都是组织一个Parcel结构,然后调用BpBinder的transact()方法,把服务信息和传输code--CHECK_SERVICE_TRANSACTION 发给Binder驱动.

virtual sp<IBinder> checkService( const String16& name) const
{
    Parcel data, reply;
        //写入RPC头信息"android.os.IServiceManager"
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name); //写入服务的名称
         //remote()函数返回的是mRemote,就是BpRefBase中的mRemote,即BpBinder对象。这里调用了BpBinder的transact()方法
    remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
    return reply.readStrongBinder();
}

BpBinder的transact()的流程这里就不展开,上面addService()已经有了详细的说明。CHECK_SERVICE_TRANSACTION 在ServiceManager中对应的是SVC_MGR_CHECK_SERVICE(),从svclist中,根据服务的name查到对应的handle,最终得到服务的对象。

和addService类似,ServiceManager查到对应的handle后,把handle存入reply,addService的reply没有数据getService的reply有数据,返回BR_REPLY相应码。

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    ...
    case BR_REPLY:
        {
            binder_transaction_data tr;
            err = mIn.read(&tr, sizeof(tr));
            ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
            if (err != NO_ERROR) goto finish;

            if (reply) {
                if ((tr.flags & TF_STATUS_CODE) == 0) {
                    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 {
                    err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
                    freeBuffer(nullptr,
                        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), this);
                }
            } else {
                freeBuffer(nullptr,
                    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), this);
                continue;
            }
        }
        goto finish;
    ...
}

6.4 Parcel::readStrongBinder()

checkservice()收到ServiceManager发来的reply后,调用readStrongBinder()来获取服务的对象。主要在unflatten_binder 中,根据flat的type是handle还是实体,从而返回BpBinder对象 或者BBinder实体。


sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    readNullableStrongBinder(&val);
    return val;
}

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

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->hdr.type) {
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(nullptr, *flat, in); //返回BBinder实体
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in); //返回BpBinder代理对象
        }
    }
    return BAD_TYPE;
}

获取服务的流程简单的总结一下:

  1. 客户端进程获取ServiceManager的代理对象BpServiceManager,主要通过new BpBinder(0,xxx)得到。
  2. 调用BpServiceManager的getService,再到checkService(),然后组装一个Parce数据,传入服务名称、传输code-CHECK_SERVICE_TRANSACTION
  3. 先通过IPCThreadThread的writeTransactionData()把上面的Parcel数据写入mOut,用来进行发送
  4. 通过IPCThreadThread的talkWithDriver()与Binder驱动通信,传递语义BINDER_WRITE_READ
  5. ServiceManager有个循环不停的解析Binder驱动的BINDER_WRITE_READ信息,调用binder_parse()进行解析
  6. ServiceManager中解析后,CHECK_SERVICE_TRANSACTION对应的值为SVC_MGR_CHECK_SERVICE,从svclist中,根据服务的name查到对应的handle,ServiceManager再通过binder_send_reply()把返回的数据发送出来,在talkWithDriver()中填入mIn中,waitForResponse()进行最终的语义处理,发送出去。

 

注意:

  1. 当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;最终readStrongBinder()时,返回的是BpBinder对象;
  2. 当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。最终readStrongBinder()时,返回的是BBinder对象的真实子类;

 

7 协议码的转换流程 及不同Android版本的变化 

Binder通信协议是基于Command-Reply的方式的。

Android9.0之前的协议码流程:

Android9.0及之后的协议码流程:

上面第5步的 BR_TRANSACTION_COMPLETE 被延迟到 第 10步 ,Android做了deferred_thread_work,延迟 TRANSACTION_COMPLETE,因此不会立即返回到用户空间;这允许目标进程立即开始处理此事务,从而减少延迟。然后,当目标回复(或出现错误)时,我们将返回TRANSACTION_COMPLETE。

注册服务的详细代码流程,kernel细节的代码这里就不贴了,后面在内核章节进行详细解析:

  1. BpServiceManager::addService()时,调用writeStrongBinder(service),把服务对象写入BBinder,作为Binder实体,调用remote()->transact()处理,code:ADD_SERVICE_TRANSACTION, 最终到IPCThreadState::transact()
  2. IPCThreadState::transact() 调用writeTransactionData(),组装CMD:BC_TRANSACTION 进入 binder_transaction_data tr, tr写入mOut
  3. IPCThreadState::transact() 再调用waitForRespose和Binder驱动进行交互,第一次mOut里面存的是BC_TRANSACTION及binder_transaction_data的值,mIn没有值
  4. talkWithDriver()中此时,bwr.write_size >0 ; bwr.read_size = 0,调用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) 和binder驱动进行交互
  5. binder_ioctl()->binder_ioctl_write_read() 先从用户空间读到上面的bwr的内容,根据此时的 bwr.write_size >0 ; bwr.read_size = 0, 只进入binder_thread_write()
  6. binder_thread_write() 根据前面的 CMD:BC_TRANSACTION 从而进入binder_transaction()
  7. binder_transaction() 是个重要的流程,主要用来进行事务处理;首先创建一个binder_transaction 结构的对象 t,并插入到自己的binder_transaction堆栈中
  8. 分配一块buffer:t->buffer, 用于保存 上面mOut中的data和mObjects 中的offset数据
  9. 从data中解析出所有的binder实体并为其创建binder_node和binder_ref  ,data解析的数据存在结构 flat_binder_object中
  10. transaction事务处理完成后,tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE, t->work.type = BINDER_WORK_TRANSACTION
  11. 接下来,延迟 TRANSACTION_COMPLETE,因此我们不会立即返回到用户空间,这允许目标进程立即开始处理此事务,从而减少延迟。然后,当目标(ServiceManager)回复reply(或出现错误)时,我们将返回TRANSACTION_COMPLETE。主要通过thread->process_todo = false;来促成
  12. binder_transaction()调用binder_proc_transaction() 将transaction发送到进程(ServiceManager)并将其唤醒,调用wake_up_interruptible()进行唤醒
  13. 唤醒ServiceManager后,回到binder_ioctl_write_read(),调用copy_to_user(),把binder_write_read的数据传到用户空间
  14. ServiceManager的binder_loop()中,不同循环通过 ioctl(,BINDER_WRITE_READ,XXX)从用户空间获取数据, 此时bwr.write_size = 0,bwr.read_size> 0
  15. 又进入进入到了Binder驱动,binder_ioctl()->binder_ioctl_write_read()  ->binder_thread_read()
  16. binder_thread_read()中,前面的 type=BINDER_WORK_TRANSACTION,且tr有数据,将会发送cmd:BR_TRANSACTION 到ServiceManager, 调用copy_to_user()把数据发给用户空间ServiceManager
  17. ServiceManager的 binder_parse()解析内核传来的binder_write_read数据,根据cmd:BR_TRANSACTION, 调用svcmgr_handler处理,code=SVC_MGR_ADD_SERVICE, 然后调用binder_send_reply() cmd_reply=BC_REPLY,cmd_free=BC_FREE_BUFFER, 发给Binder驱动,其中write_size > 0
  18. Binder驱动,binder_ioctl()->binder_ioctl_write_read()->binder_thread_write(), 读取ServiceManager传来的数据,进入binder_transaction(),cmd=BC_REPLY,唤醒Client进程,把BR_TRANSACTION_COMPLETE分别发给ServiceManager 和Client进程
  19. IPCThreadState 收到BR_TRANSACTION_COMPLETE后,把数据写入mIn,mOut移除内容,继续调用talkWithDriver(),向Binder驱动发起BINDER_WRITE_READ请求,此时mOut无值,mIn有内容
  20. Binder驱动进入binder_thread_read(),根据ServiceManager发来的reply数据,发送BR_REPLY给client
  21. IPCThreadState waitForResponse()收到BR_REPLY后,释放内存空间

 

8.Media Client\Server交互流程

 

9.代码路径

/frameworks/av/media/mediaserver/main_mediaserver.cpp

/frameworks/native/libs/binder/IServiceManager.cpp

/frameworks/native/libs/binder/ProcessState.cpp

/frameworks/native/libs/binder/Parcel.cpp

/frameworks/native/libs/binder/include/binder/IInterface.h

/frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

 

 

10.总结

服务的注册和获取,主要还是 进程和Binder驱动,和ServiceManager交互的流程,这一节只是介绍了流程,但是BC_XXX 传输码和BR_XXX 响应码的转换流程还没有细讲,下一节会单独进行讲解。

另外服务注册后,启动的Binder线程池,本节也没有细讲,后面单独开一节来进行分析。

 

我的微信公众号:IngresGe

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yiranfeng/article/details/105210611

智能推荐

Hexo 博客加入豆瓣读书界面(综合教程)_hexo-douban-程序员宅基地

文章浏览阅读1.3k次,点赞16次,收藏5次。在自己的博客中添加豆瓣界面_hexo-douban

[JAVA]语言程序设计入门 第1-2章-程序员宅基地

文章浏览阅读677次,点赞19次,收藏24次。Java 是目前最具影响力的、卓越的编程语言之一。Java 凭借其“编写一次,到处运行”的特性很好地支持互联网应用所要求的跨平台能力,成为服务器端开发的主流语言。现在人类已进人移动互联网时代,而Java 依然是当之无愧的主角。随着人工智能和大数据技术的蓬勃发展,Java 也不断发展,使其在数据处理方面大有用武之地。本文以JAVA17版本作为学习对象。

Ubuntu下无法安装sun-java6-jdk的解决办法_java6不能安装策略-程序员宅基地

文章浏览阅读548次。Ubuntu下无法安装sun-java6-jdk的解决办法安装jdk,按照全志文档,如下步骤$ sudo add-apt-repository “deb http://archive.canonical.com/ lucid partner”$ sudo apt-get update提示如下错误:root@stu-system:/home# sudo apt-get install su..._java6不能安装策略

Codeforces #708 Div2_C1. k-LCM (easy version)-程序员宅基地

文章浏览阅读370次。C1. k-LCM (easy version)题目链接在此!题面:中文题意:实际上就是说,给你n,k两个正整数,要求构造出一个元素个数为k,且数组元素和为n的数组,要求所有元素最小公倍数<=N/2。此处降低难度,k==3。思路:范围在此,有事没事先开个ll。思路是这样的,首先剪枝情况。n偶数且为4倍数的时候,n/4,n/4,n/2。n偶数但非4倍数,2,n/2-1,n/2-1。n为奇数,1,(n-1)/2,(n-1)/2。代码:#include<bits/s

php 解析 ini文件,php解析.ini文件-程序员宅基地

文章浏览阅读327次。1.myphp.ini文件autostart = false font_size = 12font_color = red$string['access'] = '进入';$string['accesshelp'] = '进入帮助';$string['accesskey'] = '进入验证 {$a}';$string['accessstatement'] = '进入声明';$string['act..._php 解析ini

PHP汉字转话为拼音_51141cc-程序员宅基地

文章浏览阅读3.4k次。public $enableCsrfValidation = false ; static private function pinyin(){ return array( "A" => array(59371, 41648, 50400, 33157, 41392, 18661, 47599), "Ai" =&..._51141cc

随便推点

阿里云redis 密钥登录_如何使Redis中的密钥失效-程序员宅基地

文章浏览阅读235次。阿里云redis 密钥登录 介绍 (Introduction)Redis is an open-source, in-memory key-value data store. Redis keys are persistent by default, meaning that the Redis server will continue to store them unless they are..._阿里云 redis 登录

腾讯云服务器挂载云硬盘_腾讯云硬盘如何挂载到服务器上-程序员宅基地

文章浏览阅读2k次。背景:在服务器下挂载3块云硬盘操作过程:在云服务器上购买云硬盘购买好硬盘后,在云控制台挂载硬盘挂载云硬盘Xshell进入到需要挂载的云服务器中,进行硬盘的分区,格式化,挂载等操作查看系统内的磁盘对磁盘进行分区格式化磁盘新建目录作为挂载点..._腾讯云硬盘如何挂载到服务器上

Android Studio Chipmunk | 2021.2.1 Patch 2(2022 年 8 月)-程序员宅基地

文章浏览阅读2.3w次,点赞4次,收藏3次。Android Studio Chipmunk | 2021.2.1 Patch 2(2022 年 8 月)_android studio chipmunk

iOS 单独设置某个控制器横屏 —— HERO博客_ios 横屏当前控制器-程序员宅基地

文章浏览阅读4.1k次。iOS 单独设置某个控制器横屏,其他竖屏。_ios 横屏当前控制器

关于SAP程序版本问题_sap 回滚版本-程序员宅基地

文章浏览阅读1.7k次。1.一般情况下,report程序每一个版本都会对应到相应的请求号下面. 可以通过e070, e071来找到请求号下面对应的程序名称. 或者直接找到存放版本的表VRSD(OBJTYPE='REPS',OBJNAME='程序名',KORRNUM='请求号') 上面可以得到某个请求号对应的版本.2.根据程序名,版本号 可以找到相对应的程序源代码. 调用程序RSVRSRS1_sap 回滚版本

linux cp目录_Linux cp目录和内容-程序员宅基地

文章浏览阅读7.4k次。linux cp目录Linux provides cp command in order to copy files, folders, and directories. But sometimes we may have some issues if we want to copy a folder or directory. In this tutorial, we will learn h..._linux cp 目录