分享

Android-IPC-Binder(4)

 mandrave 2012-01-06

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,  
  3.                  uint32_t *ptr, uint32_t size, binder_handler func)  
  4. {  
  5.   ......  
  6.   case BR_TRANSACTION: {  
  7.     struct binder_txn *txn = (void *) ptr;  
  8.     if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) {  
  9.       LOGE("parse: txn too small!/n");  
  10.       return -1;  
  11.     }  
  12.     binder_dump_txn(txn);  
  13.     if (func) {  
  14.       unsigned rdata[256/4];  
  15.       struct binder_io msg;  
  16.       struct binder_io reply;  
  17.       int res;  
  18.       bio_init(&reply, rdata, sizeof(rdata), 4);  
  19.       bio_init_from_txn(&msg, txn);  
  20.       res = func(bs, txn, &msg, &reply);  
  21.       binder_send_reply(bs, &reply, txn->data, res);  
  22.     }  
  23.     ptr += sizeof(*txn) / sizeof(uint32_t);  
  24.     break;  
  25.   }  
  26.   ......  
  27. }  

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<IAudioFlinger>& AudioSystem::get_audio_flinger()  
  4. {  
  5.   Mutex::Autolock _l(gLock);  
  6.   if (gAudioFlinger.get() == 0) {  
  7.     sp<IServiceManager> sm = defaultServiceManager();  
  8.     sp<IBinder> 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<IAudioFlinger>(binder);  
  25.     gAudioFlinger->registerClient(gAudioFlingerClient);  
  26.   }  
  27.   LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?");  
  28.   return gAudioFlinger;  
  29. }  
 

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

  1. virtual sp<IBinder> getService(const String16& name) const  
  2. {  
  3.   unsigned n;  
  4.   for (n = 0; n < 5; n++){  
  5.     sp<IBinder> 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<IBinder> 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<IAudioFlinger>(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<IAudioFlinger>  
  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<BBinder> 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。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多