2011年03月24日

AndroidのBinderによるプロセス間のメソッド呼び出し(メモ3:Binder Thead)

今回はBinder Threadについて。

Eclipseでアプリケーションのデバッグをするとアプリケーションのプロセスの中に、"Binder Thread #1", "Binder Thread #2" などの名前のスレッドがあるのがわかります。これらはいったい何をしているのでしょうか。



Binder Threadのソースコード

まずはこのスレッドの名前を頼りにソースを検索してみます。

$ cd frameworks
$ grep -r '"Binder Thread #' * 2>/dev/null
base/libs/binder/ProcessState.cpp:        sprintf(buf, "Binder Thread #%d", s);

あっさり見つかりました。

frameworks/base/libs/binder/ProcessState.cpp

frameworks/base/libs/binder/IPCThreadState.cpp

このあたりのソースを見るとこのスレッドはPoolThreadのクラスで定義されていて、そのメインループは IPCThreadState::joinThreadPool であることがわかります。IPCThreadState::talkWithDriverの中から/dev/binderにioctlのシステムコールでカーネルとやりとりしています。

Binder Threadはいつ生成されるのか

PoolThread::run が呼ばれる経路をさかのぼってみました。

frameworks/base/cmds/app_main/app_main.cpp
  AppRuntime::onStarted()
     sp proc = ProcessState::self();
     ...
     proc->startThreadPool();

-->
frameworks/base/libs/binder/ProcessState.cpp
  ProcessState::startThreadPool()
     ...
     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 t = new PoolThread(isMain);
        t->run(buf);
    }
}

AppRuntime::onStarted() はZygoteからforkされた後すぐに呼び出されます。

このBinder Threadが他のプロセスからのリモートメソッド呼び出しを受け付けて実行します。

最初はBinder Threadはひとつだけですが、処理要求があった時にThreadの数を増やして要求待ちのスレッドの数がゼロにならないようにしています。要求待ちがタイムアウトした時にはThreadの数を減らしますが、一番最初に起動したmain threadだけは残るようになっています。

Proxyクラスからの/dev/binderのアクセス

/dev/binderへのアクセスはIPCThreadState::talkWithDriver で一本化されています。

リモートメソッド呼び出しの要求を出す側(Proxyクラス)からは以下の経路で使われています。

frameworks/base/libs/binder/BpBinder.cpp
  BpBinder::transact( .. )
  
-->
frameworks/base/libs/binder/IPCThreadState.cpp
  IPCThreadState::transact( .. )

-->
frameworks/base/libs/binder/IPCThreadState.cpp
  IPCThreadState::waitForResponse( .. )

-->
frameworks/base/libs/binder/IPCThreadState.cpp
  IPCThreadState::talkWithDriver(bool doRecieve)

Binder ThreadでのonTransaction( .. )までの経路

Binder Threadでリモートメソッド呼び出しの要求を受け取ってJavaのonTransactionメソッドを呼び出します。前々回では説明を省略しました。この経路はマジカルで私も理解できたわけではありませんが、以下のような経路をたどっていると思います。

frameworks/base/libs/binder/IPCThreadState.cpp
  IPCThreadState::joinThreadPool

-->
frameworks/base/libs/binder/IPCThreadState.cpp
  IPCThreadState::executeCommand(int32_t cmd)
    ...
    switch(cmd) {
    ...
    case BR_TRANSACTION:
        ...
        sp b ((BBinder*)tr.cookie);
        const status_t error = b->transact( .. );

-->
rameworks/base/libs/binder/Binder.cpp
  BBinder::transact( .. )
    ...
    err = onTransact( .. );

-->
frameworks/base/core/jni/android_util_Binder.cpp
class JavaBBinder : public BBinder
{
    ...
    virtual status_t onTransact( .. )
        ...

        JNIEnv* env = javavm_to_jnienv(mVM);
        ...
        jboolean res = env->CallBooleanMethod(mObject, .. )
        JNIでJavaのBinder#execTransactメソッドを呼び出す

-->
frameworks/base/core/java/android/os/Binder.java

    // Entry point from android_util_Binder.cpp's onTransact
    private boolean execTransact( .. ) {
        ...
        try {
            res = onTransact(code, data, reply, flags);
        } catch (RemoteException e) {
            ...
        }

-->
BinderのサブクラスのonTransact( .. )の呼び出し。
例えば ActivityManagerNative#onTransact( .. )

余談になりますが、JNIからのJavaのメソッドの呼び出しの時には、privateやprotectedなどの修飾子は意味を持ちません。

上の例でも android.os.Binder#execTransact( .. )はprivateのメソッドですが、JNI経由で呼び出されています。



トラックバックURL

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード