注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

Android系统的Binder机制之四(系统Service篇)  

2012-03-01 18:41:58|  分类: 深入研究 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
前面我们已经介绍了Android Binder机制的Service ManagerService对象代理(上)Service对象代理(下)。本文将介绍一下Android机制的另外一个重要部分——系统Service。
一、系统Service实例——Media server
    首先我们先看一下Android一个实例Media Service,代码位于framework/base/media/mediaserver/main_mediaserver.cpp文件:

int main(int argc, char** argv)
{
    sp<ProcessState> proc(ProcessState::self());//创建并获得一个ProcessState实例
    sp<IServiceManager> sm = defaultServiceManager();//取得一个ServiceManager对象
AudioFlinger::instantiate();
    MediaPlayerService::instantiate();//初始化MediaPlayerService服务
CameraService::instantiate();
AudioPolicyService::instantiate();
    ProcessState::self()->startThreadPool();//启动Process的线程池
    IPCThreadState::self()->joinThreadPool();//将自己加入到刚才的线程池
}

 我们发现Media Server是一个进程,并且该程序的实现表面上也挺简单,其实并不简单,让我们慢慢分析一下Media Server。
1sp,究竟是smart pointer还是strong pointer呢?其实我后来发现不用太关注这个,就把它当做一个普通的指针看待,即sp<IServiceManager>相当于IServiceManager*吧。sp是google搞出来的为了方便C/C++程序员管理指针的分配和释放的一套方法,类似JAVA的什么WeakReference之类的。我个人觉得,要是自己写程序的话,不用这个东西也成。好了,以后的分析中,sp<XXX>就看成是XXX*就可以了。
2、第一个调用的函数是ProcessState::self()ProcessState源码位置在framework\base\libs\binder\ProcessState.cpp中,参照ProcessState::self()的源码可以知道它其实是创建一个ProcessState;然后把该ProcessState的指针赋值给了proc变量,程序运行完,proc会自动delete内部的内容,所以就自动释放了先前分配的资源。

sp<ProcessState> ProcessState::self()
{
    if (gProcess != NULL) return gProcess;//在一个进程中,第一次进来肯定不走这儿
    AutoMutex _l(gProcessMutex);--->锁保护
    if (gProcess == NULL) gProcess = new ProcessState;//创建一个ProcessState对象
  return gProcess;//看见没,这里返回的是指针,但是函数返回的是sp<xxx>,所以把sp<xxx>看成是XXX*是可以的
}

那么为什么创建一个ProcessState呢?回想一下《

Android系统的Binder机制之二(服务代理对象 上篇)》中介绍ProcessState对象时提到:如果一个进程要使用Binder机制,

那么他的进程中必须要创建一个ProcessState对象来负责管理Service的代理对象。

3、第二句调用defaultServiceManager获得一个Service Manager代理对象,
我在《Android系统的Binder机制之二(服务代理对象 上篇)》已经对此有了详细的介绍这里就不赘述了。
4、后面几行都是创建具体的Service,我们展开之后发现都是一些调用Service Manager的addService进行注册的函数,以MediaPlayerServic为例,instantiate代码如下:
MediaPlayerService::instantiate() 的代码也差不多。
MediaPlayerService.cpp (frameworks\base\media\libmediaplayerservice)中
void MediaPlayerService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.player"), new MediaPlayerService());
}

4、最后调用ProcessState的startThreadPool方法和IPCThreadState的joinThreadPool使Media Server进入等待请求的循环当中。
    我们可以看出一个进程中可以有多个Service,Media Server这个进程中就存在AudioFlinger,MediaPlayerService,CameraService,AudioPolicyService四个Service
二、系统Service的基础——BBinder
    我们仔细查看一下Media Server中定义的四个Service我们将会发现他们都是继承自BBinder,而BBinder又继承自IBinder接口,详细情况请自行查看他们的代码。每个Service都改写了BBinder的onTransact虚函数,当用户发送请求到达Service时,框架将会调用Service的onTransact函数,后面我们将会详细的介绍这个机制。
三、Service注册
    每个Service都需要向“大管家”Service Manager进行注册,调用Service Manager的addService方法注册。这样Service Manager将会运行客户端查询和获取该Service(代理对象),然后客户端就可以通过该Service的代理对象请求该Service的服务。
四、Service进入等待请求的循环
    每个Service必须要进入死循环,等待客户端请求的到达,本例中最后两句就是使Service进行等待请求的循环之中。
ProcessStatestartThreadPool方法的代码如下
void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}
void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        int32_t s = android_atomic_add(1, &mThreadPoolSeq);
        char buf[32];
        sprintf(buf, "Binder Thread #%d", s);
        LOGV("Spawning new pooled thread, name=%s\n", buf);
        sp<Thread> t = new PoolThread(isMain);
        t->run(buf);
    }
}
IPCThreadState的joinThreadPool方法的代码如下

void IPCThreadState::joinThreadPool(bool isMain)
{
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    // This thread may have been spawned by a thread that was in the background
    // scheduling group, so first we will make sure it is in the default/foreground
    // one to avoid performing an initial transaction in the background.
    androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
    status_t result;
    do {
        int32_t cmd;
        // When we've cleared the incoming command queue, process any pending derefs
        if (mIn.dataPosition() >= mIn.dataSize()) {
            size_t numPending = mPendingWeakDerefs.size();
            if (numPending > 0) {
                for (size_t i = 0; i < numPending; i++) {
                    RefBase::weakref_type* refs = mPendingWeakDerefs[i];
                    refs->decWeak(mProcess.get());
                }
                mPendingWeakDerefs.clear();
            }

            numPending = mPendingStrongDerefs.size();
            if (numPending > 0) {
                for (size_t i = 0; i < numPending; i++) {
                    BBinder* obj = mPendingStrongDerefs[i];
                    obj->decStrong(mProcess.get());
                }
                mPendingStrongDerefs.clear();
            }
        }
        // now get the next command to be processed, waiting if necessary
        result = talkWithDriver();
        if (result >= NO_ERROR) {
            size_t IN = mIn.dataAvail();
            if (IN < sizeof(int32_t)) continue;
            cmd = mIn.readInt32();
            IF_LOG_COMMANDS() {
                alog << "Processing top-level Command: "
                    << getReturnString(cmd) << endl;
            }
            result = executeCommand(cmd);
        }
        // After executing the command, ensure that the thread is returned to the
        // default cgroup before rejoining the pool.  The driver takes care of
        // restoring the priority, but doesn't do anything with cgroups so we
        // need to take care of that here in userspace.  Note that we do make
        // sure to go in the foreground after executing a transaction, but
        // there are other callbacks into user code that could have changed
        // our group so we want to make absolutely sure it is put back.
        androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);
        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);

    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p\n",
        (void*)pthread_self(), getpid(), (void*)result);
    
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}
    Service在IPCThreadState的joinThreadPool方法中,调用talkWithDriver方法和Binder驱动进行交互,读取客户端的请求。当客户端请求到达之后调用executeCommand方法进行处理。
    我们再看一下Service怎样处理客户端的请求?我们们查看一下executeCommand方法的源码:

   1: status_t IPCThreadState::executeCommand(int32_t cmd)
   2: {
   3:     BBinder* obj;
   4:     RefBase::weakref_type* refs;
   5:     status_t result = NO_ERROR;
   6:     
   7:     switch (cmd) {
   8:         ...... 
   9:          case BR_TRANSACTION:
  10:         {
  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:             } 
  18:             ......            
  19:         }
  20:         break;
  21:     
  22:     ......
  23:     }
  24:  
  25:     if (result != NO_ERROR) {
  26:         mLastError = result;
  27:     }
  28:     
  29:     return result;
  30: }
可以看到IPCThreadState将会直接调用BBinder的transact方法来处理客户端请求,我们再看一下BBinder的transact方法:
status_t BBinder::transact(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 != NULL) {
        reply->setDataPosition(0);
    }
    return err;
}
我们发现他将会叫用自己的虚函数onTransact。我们前面提到所有的Service都集成自BBinder,并且都改写了onTransact虚函数。那么IPCThreadState将会调用Service定义onTransact方法来响应客户请求。
五、结论
    本文简单介绍了一下系统Service的原理,台湾的高焕堂先生有一篇文章,手把手教怎样实现一个系统Service,你可以在我的博文《(转)高焕堂——Android框架底层结构知多少?》中找到。
  评论这张
 
阅读(820)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017