• Binder


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

    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.h文件中,使用宏业务和通讯挂钩

    宏定义在IInterface.h文件中

     宏替换后的实际代码

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

    IMPLEMENT宏的作用就是定义

    IMPLEMENT宏替换如下

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

    intr = new BpServiceManager(obj)

    1. ::android::sp##INTERFACE> I##INTERFACE::asInterface( \
    2. const ::android::sp<::android::IBinder>& obj) \
    3. { \
    4. ::android::sp##INTERFACE> intr; \
    5. if (obj != nullptr) { \
    6. intr = static_cast##INTERFACE*>( \
    7. obj->queryLocalInterface( \
    8. I##INTERFACE::descriptor).get()); \
    9. if (intr == nullptr) { \
    10. intr = new Bp##INTERFACE(obj); //在这里做的转换 \
    11. } \
    12. } \
    13. return intr; \
    14. }

    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(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)

    1. case BR_TRANSACTION:
    2. {
    3. binder_transaction_data_secctx tr_secctx;
    4. binder_transaction_data& tr = tr_secctx.transaction_data;
    5. if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
    6. result = mIn.read(&tr_secctx, sizeof(tr_secctx));
    7. } else {
    8. result = mIn.read(&tr, sizeof(tr));
    9. tr_secctx.secctx = 0;
    10. }
    11. ALOG_ASSERT(result == NO_ERROR,
    12. "Not enough command data for brTRANSACTION");
    13. if (result != NO_ERROR) break;
    14. //Record the fact that we're in a binder call.
    15. mIPCThreadStateBase->pushCurrentState(
    16. IPCThreadStateBase::CallState::BINDER);
    17. Parcel buffer;
    18. buffer.ipcSetDataReference(
    19. reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
    20. tr.data_size,
    21. reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
    22. tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
    23. const pid_t origPid = mCallingPid;
    24. const char* origSid = mCallingSid;
    25. const uid_t origUid = mCallingUid;
    26. const int32_t origStrictModePolicy = mStrictModePolicy;
    27. const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
    28. const int32_t origWorkSource = mWorkSource;
    29. const bool origPropagateWorkSet = mPropagateWorkSource;
    30. // Calling work source will be set by Parcel#enforceInterface. Parcel#enforceInterface
    31. // is only guaranteed to be called for AIDL-generated stubs so we reset the work source
    32. // here to never propagate it.
    33. clearCallingWorkSource();
    34. clearPropagateWorkSource();
    35. mCallingPid = tr.sender_pid;
    36. mCallingSid = reinterpret_cast<const char*>(tr_secctx.secctx);
    37. mCallingUid = tr.sender_euid;
    38. mLastTransactionBinderFlags = tr.flags;
    39. // ALOGI(">>>> TRANSACT from pid %d sid %s uid %d\n", mCallingPid,
    40. // (mCallingSid ? mCallingSid : ""), mCallingUid);
    41. Parcel reply;
    42. status_t error;
    43. IF_LOG_TRANSACTIONS() {
    44. TextOutput::Bundle _b(alog);
    45. alog << "BR_TRANSACTION thr " << (void*)pthread_self()
    46. << " / obj " << tr.target.ptr << " / code "
    47. << TypeCode(tr.code) << ": " << indent << buffer
    48. << dedent << endl
    49. << "Data addr = "
    50. << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
    51. << ", offsets addr="
    52. << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
    53. }
    54. if (tr.target.ptr) {
    55. // We only have a weak reference on the target object, so we must first try to
    56. // safely acquire a strong reference before doing anything else with it.
    57. if (reinterpret_cast(
    58. tr.target.ptr)->attemptIncStrong(this)) {
    59. error = reinterpret_cast(tr.cookie)->transact(tr.code, buffer,
    60. &reply, tr.flags);
    61. reinterpret_cast(tr.cookie)->decStrong(this);
    62. } else {
    63. error = UNKNOWN_TRANSACTION;
    64. }
    65. } else {
    66. error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
    67. }
    68. mIPCThreadStateBase->popCurrentState();
    69. //ALOGI("<<<< TRANSACT from pid %d restore pid %d sid %s uid %d\n",
    70. // mCallingPid, origPid, (origSid ? origSid : ""), origUid);
    71. if ((tr.flags & TF_ONE_WAY) == 0) {
    72. LOG_ONEWAY("Sending reply to %d!", mCallingPid);
    73. if (error < NO_ERROR) reply.setError(error);
    74. sendReply(reply, 0);
    75. } else {
    76. LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
    77. }
    78. mCallingPid = origPid;
    79. mCallingSid = origSid;
    80. mCallingUid = origUid;
    81. mStrictModePolicy = origStrictModePolicy;
    82. mLastTransactionBinderFlags = origTransactionBinderFlags;
    83. mWorkSource = origWorkSource;
    84. mPropagateWorkSource = origPropagateWorkSet;
    85. IF_LOG_TRANSACTIONS() {
    86. TextOutput::Bundle _b(alog);
    87. alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
    88. << tr.target.ptr << ": " << indent << reply << dedent << endl;
    89. }
    90. }
    91. 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的工作

    篇幅有限,下篇继续
     

     

  • 相关阅读:
    [C国演义] 第十七章
    Power Apps-“编辑“窗体组件
    0基础编程教学,编程零基础该学什么,中文编程工具下载
    拼多多item_get_app - 根据ID取商品详情原数据
    硬核!基于禁忌搜索(TS)的TSP问题
    js小技巧(数组处理)
    计算机毕设 基于大数据的抖音短视频数据分析与可视化 - python 大数据 可视化
    力扣双周赛 -- 117(容斥原理专场)
    (C语言进阶)设计模式之--观察者模式
    yolov5 利用c++进行模型推理部署详解(openvino,tensoRT)
  • 原文地址:https://blog.csdn.net/somethingstill/article/details/126171664