binder 与 ProcessState & IPCThreadState

每次看binder相关内容时,都会牵扯到这两个类,每次都看也能理解。不过工作中用的少,脑袋记性不好,所以留下的印象并不是很深刻,这次下定决心,要记下来,下次不翻别人的资料和代码了,直接来瞄一眼自己写的,很快就会回忆起来。

如果说直观印象,我脑袋里立马能跳出来两句话:“启动线程池”,“加入线程池”。然后,我是越来越讨厌自己的囫囵吞枣了,我会逐渐把一切都弄清楚。一点点去地去扩充自己的理解。

每个进程都会有对象的binder守护线程来负责通信,app会有,native进程会有。app进程的binder驱动程序初始化的工作,是在启动app过程中默认完成。native进程一般都是显示调用上面两个类的方法来完成工作。

参考代码:aosp6.0

应用进程的binder初始化

zygote的socket收到system进程发送过来的启动app的消息后,通过fork创建出子进程,这个子进程就是我们需要启动的app进程。子进程创建后,调用 static 方法RuntimeInit.zygoteInit,该方法中,调用 native 方法 nativeZygoteInit(),就是在这个native方法中,完成了binder相关的初始化工作。


该jni方法注册的地方在: framework/base/cor/jni/AndroidRuntime.cpp:

static JNINativeMethod gMethods[] = {
    {"nativeZygoteInit", "()V", (void *)com_android_internal_os_RuntimeInit_nativeZygoteInit}
}

native层的实现:

static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
    gCurRuntime->onZygoteInit();
}

gCurRuntime又是什么鬼? “望文生义”一下,应该是 global current runtime,即全局的运行时。定义为:

static AndroidRuntime* gCurRuntime = NULL;
可以理解为运行环境的上下文,我个人理解,虚拟机(dalvik,art)是这个上下文的组成部分。
 
onZygoteInit()的实现在app_main.cpp的AppRuntime类中,该类继承AndroidRuntime。
    virtual void onZygoteInit()
    {
        sp<ProcessState> proc = ProcessState::self();
        ALOGV("App process: starting thread pool.\n");
        proc->startThreadPool();
    }
在onZygoteInit()中,终于看到了这次分析的目标:ProcessState以及该类的方法startThreadPool().
ALOGV中的信息很明确地说明了,下一步的操作是启动线程池。
ProcessState::self获得了该类的单例对象。
 
/frameworks/native/libs/binder/ProcessState.cpp:
void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}
先判断线程池有没有已经启动,如果没有启动,调用spawnPooledThread(true)来启动。
void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());
    }
}
这里面,启动了一个PoolThread,该类继承自Thread。
该类的定义仍在 framework/base/cor/jni/AndroidRuntime.cpp 中
class PoolThread : public Thread
{
public:
    PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }

protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};

突然间发现,另一个目标出现了:
IPCThreadState::self()->joinThreadPool(mIsMain);

frameworks/native/libs/binder/IPCThreadState.cpp:
void IPCThreadState::joinThreadPool(bool isMain)
{
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); 
    ......
    status_t result;
    do {
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        result = getAndExecuteCommand();
        ......
    } while (result != -ECONNREFUSED && result != -EBADF);
    ......
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}
mOut可以理解为和binder驱动共享的消息管道,app进程往里面write消息,binder驱动就会读到。同时,app进程也从mIn里面read从binder驱动中写的消息。
joinThreadPool()方法,中,开始和结束分别执行了一次write操作:
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
和
mOut.writeInt32(BC_EXIT_LOOPER);
分别通知binder进入和退出消息循环。
在循环过程中,通过getAndExecuteCommand()方法,从mIn中读取消息,并执行相关的命令。
status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd;

    result = talkWithDriver();
    if (result >= NO_ERROR) {
        ......
        result = executeCommand(cmd);
        ......
    }

    return result;
}
getAndExcuteCommand()自然分为两步操作:
1. get: talkWithDriver() // 获取消息
2. excute: executeCommand() // 解析出command之后,执行相关操作
talkWithDriver()就是用一些文件操作函数读写消息,这里先不表了。
以上是应用进程启动binder线程的相关步骤。
在我门播放音乐时,是通过binder和media进程里面的一些native service来通信的。这些native进程的binder线程,是怎么启动的呢?就以native media来举例说明:

native 进程中的binder的初始化

先谈一下media进程。android很多多媒体相关的服务,都是放在media进程中的。包括audio flinger,media player,camera service等。这个进程,是在init进程中启动的。
service media /system/bin/mediaserver
    class main
    user media
    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
    ioprio rt 4

进程名称:media,可执行的程序地址:/system/bin/mediaserver
代码路径:frameworks/ava/media/mediaserver/main_mediaserver.cpp
入口函数当然是main():
int main(int argc __unused, char** argv)
{
    signal(SIGPIPE, SIG_IGN);
    char value[PROPERTY_VALUE_MAX];
    bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
    pid_t childPid;

    if (doLog && (childPid = fork()) != 0) {
        
    } else {
        ....
        InitializeIcuOrDie();
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p", sm.get());
        AudioFlinger::instantiate();
        MediaPlayerService::instantiate();
        ResourceManagerService::instantiate();
        CameraService::instantiate();
        AudioPolicyService::instantiate();
        SoundTriggerHwService::instantiate();
        RadioService::instantiate();
        registerExtensions();
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }
}
这里面,先后启动了一些media service,然后就很直接到调用了ProcessState的startThreadPool()和IPCThreadState的joinThreadPool().这样,我们在app中
请求的一些media相关的服务,在media server进程中就会通过binder线程得知,从而执行相关的任务,完成后,把结果或者执行状态再通过binder返回到app进程中。
以上就是在应用进程中和native进程中,binder线程的大概的启动过程。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值