蝎子王一共几部:Android-IPC-Binder(4)

来源:百度文库 编辑:偶看新闻 时间:2024/05/05 05:40:14

Service Manager Handle Add Service

到现在为止,service_manager已经得到了一个从media_server发送过来的BR_TRANSACTION类型的数据包,于是它调用binder_parser()函数去处理该数据包。

  1. // platform/frameworks/base/cmds/servicemanager/binder.c   
  2. int binder_parse(struct binder_state *bs, struct binder_io *bio,  
  •                  uint32_t *ptr, uint32_t size, binder_handler func)  
  • {  
  •   ......  
  •   case BR_TRANSACTION: {  
  •     struct binder_txn *txn = (void *) ptr;  
  •     if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) {  
  •       LOGE("parse: txn too small!/n");  
  •       return -1;  
  •     }  
  •     binder_dump_txn(txn);  
  •     if (func) {  
  •       unsigned rdata[256/4];  
  •       struct binder_io msg;  
  •       struct binder_io reply;  
  •       int res;  
  •       bio_init(&reply, rdata, sizeof(rdata), 4);  
  •       bio_init_from_txn(&msg, txn);  
  •       res = func(bs, txn, &msg, &reply);  
  •       binder_send_reply(bs, &reply, txn->data, res);  
  •     }  
  •     ptr += sizeof(*txn) / sizeof(uint32_t);  
  •     break;  
  •   }  
  •   ......  
  • }  
  • binder_parse会调用svcmgr_handler(也就是参数func)按照BpServerManager相反的步骤处理BR_TRANSACTION数据包。这里binder_txn结构实际上与binder_transaction_data结构是一样的。在本文的例子中,事务码(transaction code)为SVC_MGR_ADD_SERVICE。

    1. // platform/frameworks/base/cmds/servicemanager/binder.c   
    2. int svcmgr_handler(struct binder_state *bs,  
    3.                    struct binder_txn *txn,  
    4.                    struct binder_io *msg,  
    5.                    struct binder_io *reply)  
    6. {  
    7.   struct svcinfo *si;  
    8.   uint16_t *s;  
    9.   unsigned len;  
    10.   void *ptr;  
    11.   if (txn->target != svcmgr_handle)  
    12.     return -1;  
    13.   s = bio_get_string16(msg, &len);  
    14.   if ((len != (sizeof(svcmgr_id) / 2)) ||  
    15.       memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {  
    16.     fprintf(stderr,"invalid id %s/n", str8(s));  
    17.     return -1;  
    18.   }  
    19.   switch(txn->code) {  
    20.   case SVC_MGR_GET_SERVICE:  
    21.   case SVC_MGR_CHECK_SERVICE:  
    22.     s = bio_get_string16(msg, &len);  
    23.     ptr = do_find_service(bs, s, len);  
    24.     if (!ptr)  
    25.       break;  
    26.     bio_put_ref(reply, ptr);  
    27.     return 0;  
    28.   case SVC_MGR_ADD_SERVICE:  
    29.     s = bio_get_string16(msg, &len);  
    30.     ptr = bio_get_ref(msg);  
    31.     if (do_add_service(bs, s, len, ptr, txn->sender_euid))  
    32.       return -1;  
    33.     break;  
    34.   case SVC_MGR_LIST_SERVICES: {  
    35.     unsigned n = bio_get_uint32(msg);  
    36.     si = svclist;  
    37.     while ((n-- > 0) && si)  
    38.       si = si->next;  
    39.     if (si) {  
    40.       bio_put_string16(reply, si->name);  
    41.       return 0;  
    42.     }  
    43.     return -1;  
    44.   }  
    45.   default:  
    46.     LOGE("unknown code %d/n", txn->code);  
    47.     return -1;  
    48.   }  
    49.   bio_put_uint32(reply, 0);  
    50.   return 0;  
    51. }  
     

    于是service_manager知道了一个名为s的服务将会运行,并且ervice_manager通过bio_get_ref()获取到对象的信息。

    1. // platform/frameworks/base/cmds/servicemanager/binder.c   
    2. void *bio_get_ref(struct binder_io *bio)  
    3. {  
    4.   struct binder_object *obj;  
    5.   obj = _bio_get_obj(bio);  
    6.   if (!obj)  
    7.     return 0;  
    8.   if (obj->type == BINDER_TYPE_HANDLE)  
    9.     return obj->pointer;  
    10.   return 0;  
    11. }  
     

     

    bio_get_ref()函数做的工作与flatten_binder()函数相反。do_add_service()函数最终会调用binder_acquire()来获取ptr所指对象的强引用。

    小结:

     

    本节展示了服务是如何添加到service manager中去的。

    假设你想要实现自己的服务IFunnyTest,你需要做一下步骤:

    • 将你的服务的名字添加到service_manager中的allowed service列表中。

    Get IAudioFlinger

    获取服务接口的唯一方法就是通过IServiceManager::getService()函数。假设AudioSystem需要获取一个IAudioFlinger。

    1. // platform/frameworks/base/media/libmedia/AudioSystem.cpp   
    2. // establish binder interface to AudioFlinger service   
    3. const sp& AudioSystem::get_audio_flinger()  
    4. {  
    5.   Mutex::Autolock _l(gLock);  
    6.   if (gAudioFlinger.get() == 0) {  
    7.     sp sm = defaultServiceManager();  
    8.     sp binder;  
    9.     do {  
    10.       binder = sm->getService(String16("media.audio_flinger"));  
    11.       if (binder != 0)  
    12.         break;  
    13.       LOGW("AudioFlinger not published, waiting...");  
    14.       usleep(500000); // 0.5 s   
    15.     } while(true);  
    16.     if (gAudioFlingerClient == NULL) {  
    17.       gAudioFlingerClient = new AudioFlingerClient();  
    18.     } else {  
    19.       if (gAudioErrorCallback) {  
    20.         gAudioErrorCallback(NO_ERROR);  
    21.       }  
    22.     }  
    23.     binder->linkToDeath(gAudioFlingerClient);  
    24.     gAudioFlinger = interface_cast(binder);  
    25.     gAudioFlinger->registerClient(gAudioFlingerClient);  
    26.   }  
    27.   LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");  
    28.   return gAudioFlinger;  
    29. }  
     

    IServiceManager::getService()函数会调用BpServiceManager::getService()函数。

    1. virtual sp getService(const String16& name) const  
    2. {  
    3.   unsigned n;  
    4.   for (n = 0; n < 5; n++){  
    5.     sp svc = checkService(name);  
    6.     if (svc != NULL) return svc;  
    7.     LOGI("Waiting for sevice %s.../n", String8(name).string());  
    8.     sleep(1);  
    9.   }  
    10.   return NULL;  
    11. }  
    12.       
    13. virtual sp checkService( const String16& name) const  
    14. {  
    15.   Parcel data, reply;  
    16.    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());  
    17.   data.writeString16(name);  
    18.   remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);  
    19.   return reply.readStrongBinder();  
    20. }  
     

     

    与前文分析类似,该调用最终会通过binder内核驱动在service_manager进程中处理。代码参见上一节svcmgr_handler()函数的SVC_MGR_GET_SERVICE分支。

     

    此时service_manager会回复一个之前由media_server设置的的handle(也就是AudioFlinger的实例的地址)。BpServiceManager::checkService()会由remote()->transact()调用返回。与IServiceManager的分析类似,它会创建一个新的BpBinder实例指向service_manager返回的handle。interface_cast(binder) 最终返回一个BpAudioFlinger实例。

    小结:

    与获取IServieManager类似,但是这一次是通过service_manager去获取一个handle。之前获取IServiceManager时总是返回handle 0。

    RPC Call IAudioFlinger::SetMode

    如果我们在AAA这个进程中调用IAudioFlinger::SetMode()函数,实际上是调用的BpAudioFlinger::setMode()函数。

    1. // platform/frameworks/base/media/libmedia/IAudioFlinger.cpp   
    2. class BpAudioFlinger : public BpInterface  
    3. {  
    4. public:  
    5.   ......  
    6.   virtual status_t setMode(int mode)  
    7.   {  
    8.     Parcel data, reply;  
    9.     data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());  
    10.     data.writeInt32(mode);  
    11.     remote()->transact(SET_MODE, data, &reply);  
    12.     return reply.readInt32();  
    13.   }  
    14.   ......  
    15. }  
     

     

    与IServiceManager::addService()类似,该函数最终会生成一个数据包,并写入到binder内核驱动中,然后等待读取回复。不同的是,这次的target handle指向了media_server进程中的某个地址。

    Handle IAudioFlinger::SetMode

    binder内核驱动最终会唤醒media_server进程中的在IPCThreadState::joinThreadPool()中运行的读线程。现在让我们回顾一下这段代码。

    1. void IPCThreadState::joinThreadPool(bool isMain)  
    2. {  
    3.     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL/n", (void*)pthread_self(), getpid());  
    4.     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);  
    5.       
    6.     status_t result;  
    7.     do {  
    8.         int32_t cmd;  
    9.           
    10.         // When we've cleared the incoming command queue, process any pending derefs   
    11.         if (mIn.dataPosition() >= mIn.dataSize()) {  
    12.             size_t numPending = mPendingWeakDerefs.size();  
    13.             if (numPending > 0) {  
    14.                 for (size_t i = 0; i < numPending; i++) {  
    15.                     RefBase::weakref_type* refs = mPendingWeakDerefs[i];  
    16.                     refs->decWeak(mProcess.get());  
    17.                 }  
    18.                 mPendingWeakDerefs.clear();  
    19.             }  
    20.             numPending = mPendingStrongDerefs.size();  
    21.             if (numPending > 0) {  
    22.                 for (size_t i = 0; i < numPending; i++) {  
    23.                     BBinder* obj = mPendingStrongDerefs[i];  
    24.                     obj->decStrong(mProcess.get());  
    25.                 }  
    26.                 mPendingStrongDerefs.clear();  
    27.             }  
    28.         }  
    29.         // now get the next command to be processed, waiting if necessary   
    30.         result = talkWithDriver();  
    31.         if (result >= NO_ERROR) {  
    32.             size_t IN = mIn.dataAvail();  
    33.             if (IN < sizeof(int32_t)) continue;  
    34.             cmd = mIn.readInt32();  
    35.             IF_LOG_COMMANDS() {  
    36.                 alog << "Processing top-level Command: "  
    37.                     << getReturnString(cmd) << endl;  
    38.             }  
    39.             result = executeCommand(cmd);  
    40.         }  
    41.           
    42.         // After executing the command, ensure that the thread is returned to the   
    43.         // default cgroup and priority before rejoining the pool.  This is a failsafe   
    44.         // in case the command implementation failed to properly restore the thread's   
    45.         // scheduling parameters upon completion.   
    46.         int my_id;  
    47. #ifdef HAVE_GETTID   
    48.         my_id = gettid();  
    49. #else   
    50.         my_id = getpid();  
    51. #endif   
    52.         if (!set_sched_policy(my_id, SP_FOREGROUND)) {  
    53.             // success; reset the priority as well   
    54.             setpriority(PRIO_PROCESS, my_id, ANDROID_PRIORITY_NORMAL);  
    55.         }  
    56.         // Let this thread exit the thread pool if it is no longer   
    57.         // needed and it is not the main process thread.   
    58.         if(result == TIMED_OUT && !isMain) {  
    59.             break;  
    60.         }  
    61.     } while (result != -ECONNREFUSED && result != -EBADF);  
    62.     LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p/n",  
    63.         (void*)pthread_self(), getpid(), (void*)result);  
    64.       
    65.     mOut.writeInt32(BC_EXIT_LOOPER);  
    66.     talkWithDriver(false);  
    67. }  
     

     

    这一次,talkWithDriver()函数会返回BpServiceManager::setMode()生成的数据包,并调用executeCommand()函数执行命令。在本例中,命令为BR_TRANSACTION。

    1. status_t IPCThreadState::executeCommand(int32_t cmd)  
    2. {  
    3.     ......  
    4.     switch(cmd){  
    5.     ......  
    6.     case BR_TRANSACTION:  
    7.         {  
    8.             binder_transaction_data tr;  
    9.             ......  
    10.             Parcel reply;  
    11.             ......  
    12.             if (tr.target.ptr) {  
    13.                 sp b((BBinder*)tr.cookie);  
    14.                 const status_t error = b->transact(tr.code, buffer, &reply, 0);  
    15.                 if (error < NO_ERROR) reply.setError(error);  
    16.                   
    17.             } else {  
    18.                 const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);  
    19.                 if (error < NO_ERROR) reply.setError(error);  
    20.             }  
    21.               
    22.             if ((tr.flags & TF_ONE_WAY) == 0) {  
    23.                 LOG_ONEWAY("Sending reply to %d!", mCallingPid);  
    24.                 sendReply(reply, 0);  
    25.             } else {  
    26.                 LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);  
    27.             }  
    28.               
    29.             ......  
    30.         }  
    31.         break;  
    32.     ......  
    33.     } // end of switch   
    34.     ......  
    35. }  
     

     

    if(tr.target.ptr)为真的分支部分是最重要的。它从binder内核驱动中获取到一个地址并转换为BBinder类型的指针(该指针在执行IServiceManager::addService()函数时放入binder内核驱动)。记住,AudioFlinger继承自BBinder。该指针实际上与AudioFlinger实例是同一个指针。于是接下来的transact()函数调用最终是调用的BnAudioFlinger的onTransact()虚函数。

    1. status_t BnAudioFlinger::onTransact(  
    2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
    3. {  
    4.     switch(code) {  
    5.     ......  
    6.     case SET_MODE: {  
    7.         CHECK_INTERFACE(IAudioFlinger, data, reply);  
    8.         int mode = data.readInt32();  
    9.         reply->writeInt32( setMode(mode) );  
    10.         return NO_ERROR;  
    11.     } break;  
    12.     ......  
    13.     } // end of switch   
    14. }  
     

    然后调用sendReply()写入reply。

    1. status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)  
    2. {  
    3.     status_t err;  
    4.     status_t statusBuffer;  
    5.     err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);  
    6.     if (err < NO_ERROR) return err;  
    7.       
    8.     return waitForResponse(NULL, NULL);  
    9. }  
     

    结果(reply)被写入到binder内核驱动。然后内核驱动会唤醒AAA进程中的读线程(去取结果)。

    总结

    Android IPC system一共由四个部分组成:

    • Binder驱动:IPC系统的核心。在服务提供方(service provider)和服务使用方(service user)之间传输数据。
    • 服务提供方:提供某种服务。解析从binder驱动中收到的RPC调用数据,并执行相应的动作。
    • service_manager:一个特殊的服务提供方。为其他的服务提供方提供服务管理服务。
    • 服务使用方:远程调用服务提供方。生成一个RPC调用数据,然后发送给binder驱动。

    本文例子中主要的流程如下:

     

    1. service_manager启动。在binder驱动中注册一个特殊节点0。

    2. media_server从该特殊节点0获取到一个IServiceManager代理。

    3. media_server调用IServiceManager::addService()去添加IAudioFlinger服务。该调用发送给节点0,由节点0发送给binder驱动。

    4. binder驱动知道该数据是给节点0,并且包含有binder一个对象的命令。于是它生成另一个节点(假设为A)给IAudioFlinger服务,并将数据发送给service_manager。

    5. service_manager从binder驱动中读取该数据,然后处理IServiceManager::addService()远程调用。

    6. 另一个进程P获取到节点0的一个IServiceManager代理。

    7. 进程P调用IServiceManager::getService()来获取IAudioFlinger服务。该调用会发送给节点0,节点0发送数据给binder驱动。

    8. binder驱动知道数据是给节点0,于是将它传递给service_manager。

    9. service_manager从binder驱动中读取数据,然后处理IServiceManager::getService()调用,并返回代表IAudioFlinger服务的节点A。

    10. 进程P调用IAudioFlinger::setMode,调用会传递给节点A。

    11. binder驱动知道数据是给节点A,于是将数据传递给media_server。

    12. media_server从binder驱动中读取数据,然后处理IAudioFlinger::setMode()远程调用,然后发送reply数据给binder驱动。

    13. binder驱动将reply传递给进程P。

    14. 进程P从binder驱动中读取数据并最终获取到reply。