Android Binder Mechanism (4) -- 如何使用已注册的系统Service

http://blog.csdn.net/baiyanning/article/details/6202778


上一篇文章中我们讨论了如何向系统注册Service。本篇文章我们将讨论如何使用这个已注册的系统Service。

    在本系列文章的第一篇中,客户端应用程序使用如下两条语句取得了ExampleService代理对象的引用。

  1. sp<IServiceManager> sm = defaultServiceManager();     
  2. binder = sm->getService(String16("byn.example"));  

     第一句我们之前已经详细解释过了,全局函数defaultServiceManager()返回的是ServiceManager代理对象的引用。第二句话以ExampleService的方法名为参数调用getService()方法,返回的是ExampleService代理对象的引用。这个过程和上一篇文章介绍的addService的过程是非常类似的,这里就不详细展开了。

    客户应用程序获得了ExampleService代理对象的引用之后,通过如下语句调用服务:

  1. data.writeInt32(getpid());     
  2. data.writeInt32(n);     
  3. binder->transact(0, data, &reply);   

    第一句话写入当前进程的进程ID,这里只是为了输出log用,没有实际意义;

    第二句话写入参数n;

    最后一句话调用ExampleService代理对象的transact方法发送请求。第一个参数0是请求代码(code),如果一个服务提供了多个API接口,那么服务器端就通过这个参数区分调用的是哪一个API;第二个参数打包后的调用参数;最后一个参数保存返回值。因为ExampleService代理对象继承自BpBinder,所以这里调用的是BpBinder::transact()方法,进而调用IPCThreadState::transact()方法。这个过程在上一篇文章中已经介绍过。

    现在我们重点剖析一下服务器端的情况。

    服务器端在向系统注册服务之后,首先调用ProcessState::self()->startThreadPool()方法启动一个线程池;然后调用IPCThreadState::self()->joinThreadPool()方法进入一个无限循环,等待其它进程的服务请求。我们看一下joinThreadPool方法的源代码:

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

    在joinThreadPool()方法中,通过调用talkWithDriver方法与binder设备进行通信,通常Service进程会阻塞在这里;一旦客户请求到来,该方法返回,并调用后面的executeCommand()方法进行处理。我们看一下executeCommand()方法的源代码:

  1. // File: frameworks/base/libs/binder/IPCThreadState.cpp  
  2. status_t IPCThreadState::executeCommand(int32_t cmd)  
  3. {  
  4.     BBinder* obj;  
  5.     RefBase::weakref_type* refs;  
  6.     status_t result = NO_ERROR;  
  7.       
  8.     switch (cmd) {  
  9.     case BR_ERROR:  
  10.         result = mIn.readInt32();  
  11.         break;  
  12.           
  13.     case BR_OK:  
  14.         break;  
  15.           
  16.     case BR_ACQUIRE:  
  17.         refs = (RefBase::weakref_type*)mIn.readInt32();  
  18.         obj = (BBinder*)mIn.readInt32();  
  19.         LOG_ASSERT(refs->refBase() == obj,  
  20.                    "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",  
  21.                    refs, obj, refs->refBase());  
  22.         obj->incStrong(mProcess.get());  
  23.         IF_LOG_REMOTEREFS() {  
  24.             LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);  
  25.             obj->printRefs();  
  26.         }  
  27.         mOut.writeInt32(BC_ACQUIRE_DONE);  
  28.         mOut.writeInt32((int32_t)refs);  
  29.         mOut.writeInt32((int32_t)obj);  
  30.         break;  
  31.           
  32.     case BR_RELEASE:  
  33.         refs = (RefBase::weakref_type*)mIn.readInt32();  
  34.         obj = (BBinder*)mIn.readInt32();  
  35.         LOG_ASSERT(refs->refBase() == obj,  
  36.                    "BR_RELEASE: object %p does not match cookie %p (expected %p)",  
  37.                    refs, obj, refs->refBase());  
  38.         IF_LOG_REMOTEREFS() {  
  39.             LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);  
  40.             obj->printRefs();  
  41.         }  
  42.         mPendingStrongDerefs.push(obj);  
  43.         break;  
  44.           
  45.     case BR_INCREFS:  
  46.         refs = (RefBase::weakref_type*)mIn.readInt32();  
  47.         obj = (BBinder*)mIn.readInt32();  
  48.         refs->incWeak(mProcess.get());  
  49.         mOut.writeInt32(BC_INCREFS_DONE);  
  50.         mOut.writeInt32((int32_t)refs);  
  51.         mOut.writeInt32((int32_t)obj);  
  52.         break;  
  53.           
  54.     case BR_DECREFS:  
  55.         refs = (RefBase::weakref_type*)mIn.readInt32();  
  56.         obj = (BBinder*)mIn.readInt32();  
  57.         // NOTE: This assertion is not valid, because the object may no  
  58.         // longer exist (thus the (BBinder*)cast above resulting in a different  
  59.         // memory address).  
  60.         //LOG_ASSERT(refs->refBase() == obj,  
  61.         //           "BR_DECREFS: object %p does not match cookie %p (expected %p)",  
  62.         //           refs, obj, refs->refBase());  
  63.         mPendingWeakDerefs.push(refs);  
  64.         break;  
  65.           
  66.     case BR_ATTEMPT_ACQUIRE:  
  67.         refs = (RefBase::weakref_type*)mIn.readInt32();  
  68.         obj = (BBinder*)mIn.readInt32();  
  69.            
  70.         {  
  71.             const bool success = refs->attemptIncStrong(mProcess.get());  
  72.             LOG_ASSERT(success && refs->refBase() == obj,  
  73.                        "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",  
  74.                        refs, obj, refs->refBase());  
  75.               
  76.             mOut.writeInt32(BC_ACQUIRE_RESULT);  
  77.             mOut.writeInt32((int32_t)success);  
  78.         }  
  79.         break;  
  80.       
  81.     case BR_TRANSACTION:  
  82.         {  
  83.             binder_transaction_data tr;  
  84.             result = mIn.read(&tr, sizeof(tr));  
  85.             LOG_ASSERT(result == NO_ERROR,  
  86.                 "Not enough command data for brTRANSACTION");  
  87.             if (result != NO_ERROR) break;  
  88.               
  89.             Parcel buffer;  
  90.             buffer.ipcSetDataReference(  
  91.                 reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),  
  92.                 tr.data_size,  
  93.                 reinterpret_cast<const size_t*>(tr.data.ptr.offsets),  
  94.                 tr.offsets_size/sizeof(size_t), freeBuffer, this);  
  95.               
  96.             const pid_t origPid = mCallingPid;  
  97.             const uid_t origUid = mCallingUid;  
  98.               
  99.             mCallingPid = tr.sender_pid;  
  100.             mCallingUid = tr.sender_euid;  
  101.               
  102.             //LOGI(">>>> TRANSACT from pid %d uid %d/n", mCallingPid, mCallingUid);  
  103.               
  104.             Parcel reply;  
  105.             IF_LOG_TRANSACTIONS() {  
  106.                 TextOutput::Bundle _b(alog);  
  107.                 alog << "BR_TRANSACTION thr " << (void*)pthread_self()  
  108.                     << " / obj " << tr.target.ptr << " / code "  
  109.                     << TypeCode(tr.code) << ": " << indent << buffer  
  110.                     << dedent << endl  
  111.                     << "Data addr = "  
  112.                     << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)  
  113.                     << ", offsets addr="  
  114.                     << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;  
  115.             }  
  116.             if (tr.target.ptr) {  
  117.                 sp<BBinder> b((BBinder*)tr.cookie);  
  118.                 const status_t error = b->transact(tr.code, buffer, &reply, 0);  
  119.                 if (error < NO_ERROR) reply.setError(error);  
  120.                   
  121.             } else {  
  122.                 const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);  
  123.                 if (error < NO_ERROR) reply.setError(error);  
  124.             }  
  125.               
  126.             //LOGI("<<<< TRANSACT from pid %d restore pid %d uid %d/n",  
  127.             //     mCallingPid, origPid, origUid);  
  128.               
  129.             if ((tr.flags & TF_ONE_WAY) == 0) {  
  130.                 LOG_ONEWAY("Sending reply to %d!", mCallingPid);  
  131.                 sendReply(reply, 0);  
  132.             } else {  
  133.                 LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);  
  134.             }  
  135.               
  136.             mCallingPid = origPid;  
  137.             mCallingUid = origUid;  
  138.               
  139.             IF_LOG_TRANSACTIONS() {  
  140.                 TextOutput::Bundle _b(alog);  
  141.                 alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "  
  142.                     << tr.target.ptr << ": " << indent << reply << dedent << endl;  
  143.             }  
  144.               
  145.         }  
  146.         break;  
  147.       
  148.     case BR_DEAD_BINDER:  
  149.         {  
  150.             BpBinder *proxy = (BpBinder*)mIn.readInt32();  
  151.             proxy->sendObituary();  
  152.             mOut.writeInt32(BC_DEAD_BINDER_DONE);  
  153.             mOut.writeInt32((int32_t)proxy);  
  154.         } break;  
  155.           
  156.     case BR_CLEAR_DEATH_NOTIFICATION_DONE:  
  157.         {  
  158.             BpBinder *proxy = (BpBinder*)mIn.readInt32();  
  159.             proxy->getWeakRefs()->decWeak(proxy);  
  160.         } break;  
  161.           
  162.     case BR_FINISHED:  
  163.         result = TIMED_OUT;  
  164.         break;  
  165.           
  166.     case BR_NOOP:  
  167.         break;  
  168.           
  169.     case BR_SPAWN_LOOPER:  
  170.         mProcess->spawnPooledThread(false);  
  171.         break;  
  172.           
  173.     default:  
  174.         printf("*** BAD COMMAND %d received from Binder driver/n", cmd);  
  175.         result = UNKNOWN_ERROR;  
  176.         break;  
  177.     }  
  178.   
  179.     if (result != NO_ERROR) {  
  180.         mLastError = result;  
  181.     }  
  182.       
  183.     return result;  
  184. }  

    这里,函数会根据一系列枚举值作相应的处理。在binder协议中:

    BR_XXX等宏为BinderDriverReturnProtocol,表示Binder驱动返回协议。
    BC_XXX等宏为BinderDriverCommandProtocol,表示Binder驱动命令协议。

    因为这里是收到命令请求后要做相应的处理,所以这里的宏都是以BR开头的。这里会走到BR_TRANSACTION这个分支,调用BBinder的transact()方法做处理(b->transact(tr.code, buffer, &reply, 0))。我们看一下BBinder::transact()方法的源代码:

  1. // File: frameworks/base/libs/binder/binder.cpp  
  2. status_t BBinder::transact(  
  3.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  4. {  
  5.     data.setDataPosition(0);  
  6.   
  7.     status_t err = NO_ERROR;  
  8.     switch (code) {  
  9.         case PING_TRANSACTION:  
  10.             reply->writeInt32(pingBinder());  
  11.             break;  
  12.         default:  
  13.             err = onTransact(code, data, reply, flags);  
  14.             break;  
  15.     }  
  16.   
  17.     if (reply != NULL) {  
  18.         reply->setDataPosition(0);  
  19.     }  
  20.   
  21.     return err;  
  22. }  

我们看到调用的是虚函数onTransact()。因为ExampleService类继承自BBinder类,并改写了onTransact()方法,所以这里会调用到ExampleService::onTransact()方法。

  1. status_t ExampleService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)     
  2. {     
  3.     switch(code)     
  4.     {     
  5.         case 0: {     
  6.             pid_t pid = data.readInt32();     
  7.             int num   = data.readInt32();     
  8.             num = num + 100;     
  9.             reply->writeInt32(num);     
  10.             return NO_ERROR;     
  11.             }     
  12.             break;     
  13.         default:     
  14.             return BBinder::onTransact(code, data, reply, flags);     
  15.     }     
  16. }    

    看到这里首先根据请求代码作相应的处理。还记得我们发送请求时用的是代码0,所以这里会走到"case0"这个分支。程序先顺序读出两个参数:进程ID和被加数,将被加数加上100之后返回。至此,服务器端完成了客户端的服务请求。

    我们将总共四篇文章涉及到的主要类用下面的类图作一总结:

说明:

1. Android系统使用binder机制实现进程间通信(IPC),这里主要涉及到以下几个类:

    1.1 IBinder是Android系统对binder机制的抽象,任何一个向系统注册的Service都必须继承IBinder接口(如:ExampleService继承BBinder,而BBinder继承IBinder)

    1.2 IInterface我们在这一系列文章里没有过多涉及。它的目的是进一步抽象binder机制。比如要使用我们的ExampleService,客户端应用程序必须显式调用IPCThreadState::transaction()方法,对用户来说还是不太友好。如果我们定义一个新的类IExampleServiceInterface继承Interface,在这个类中定义add100()接口,ExampleService的代理对象也拥有该接口,那么客户端应用程序直接调用代理对象的add100()方法就好了,这样做对用户更友好。比如ServiceManager就是这样实现的(IServiceManager继承IInterface)。客户端调用的是addService接口而不是transaction方法。

    1.3 ProcessState类是一个singleton类型,每个进程只能创建一个实例,它的作用是管理当前进程中的所有Service代理对象(BpBinder对象)。任何一个使用binder机制的进程都必须创建一个该类的实例。

    1.4 IPCThreadState类是processState类的友元类,它的作用是封装对binder设备的I/O操作。客户端通过调用它的transact()方法完成发送请求;服务器端调用他的joinThreadState()方法等待客户端的服务请求。

2. Android的binder机制本质上是Proxy模式的一个具体实现。

3. ServiceManager是整个Android系统的Service管理员,任何一个系统Service首先要向它注册才能提供服务。注册时,首先要获得它的代理对象(BpServiceManager),然后通过调用它的addService()方法完成注册。客户端通过调用它的getService()获取系统服务的代理兑现。ServiceManager在系统中始终对应句柄0。

4. 客户端通过调用IPCThreadState的transaction方法发送请求;服务器端通过改写BBinder的onTransaction()方法实现接受请求。

 

(全文完)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值