2011年04月21日

Androidのブートアニメーション

Androidをパワーオンリセットをするたびに目にするブートアニメーションですが、実はよくわかっていませんでした。これはいつだれがスタートして、いつだれがストップするのでしょうか?



ブートアニメーションのソースコード

frameworks/base/cmds/bootanimation

これを見るとANDROIDの文字のアニメーションはOpenGL ESで書かれていることがわかります。

また、/data/local か /system/media にbootanimation.zip というファイルがある場合はそれをムービーとして再生するようになっています。Nexus Oneの場合はそうなっていました。(そのファイルを取ってきてKZM-A9-Dualに入れたらNexus Oneと同じブートアニメーションになりました。)

bootanimation.zipの構造はこのページが詳しいです。

[HOW-TO] Creating a bootanimation.zip

ブートアニメーションの開始と終了の謎

init.rcには以下のようなserviceのエントリがあります。

init.rc

service bootanim /system/bin/bootanimation
    user graphics
    group graphics
    disabled
    oneshot

しかし属性がdisableになっているので、自動的には起動しません。開始のトリガーはどうなっているのでしょうか?

実は、initの管理するpropertyで"ctl.start" と "ctl.stop"は特殊な意味を持っていて、これがサービスの開始と終了のコマンドになっています。(system/core/init/property_service.c と system/core/init/init.c を見てください。)

これを使っているのが以下のところです。

frameworks/base/services/surfaceflinger/SurfaceFlinger.cpp

status_t SurfaceFlinger::readyToRun()
{
    LOGI(   "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");

    ...

    /*
     *  We're now ready to accept clients...
     */

    // start boot animation
    property_set("ctl.start", "bootanim");
    
    return NO_ERROR;
}
void SurfaceFlinger::bootFinished()
{
    const nsecs_t now = systemTime();
    const nsecs_t duration = now - mBootTime;
    LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );  
    mBootFinished = true;
    property_set("ctl.stop", "bootanim");
}

readyToRun()はThread::readyToRun()を継承していてSurfaceFlingerのスレッドが開始されるときに一度だけ呼ばれます。

bootFinished()は以下の関数から呼ばれています。

frameworks/base/libs/surfaceflinger_client/ISurfaceComposer.cpp

status_t BnSurfaceComposer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        ...
        case BOOT_FINISHED: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            bootFinished();
        } break;
        ...

このonTransactは以前にも見かけました。Binderを使ったプロセス間のメソッド呼び出しです。

どこか別のプロセスからbootFinished() を呼んでいるはずですが、ソースをgrepしても見つかりません。

PARTNER-Jetでブレークポイントをしかけてみると、確かにここは実行されていることが確認できました。

どこから呼ばれている?

やっと見つけました。

$ grep -r BOOT_FINISHED *
...
frameworkds/base/include/surfaceflinger/ISurfaceComposer.h:        BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
...

frameworks/base/services/java/com/android/server/WindowManagerService.java

performEnableScreen

            ...
            try {
                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
                if (surfaceFlinger != null) {
                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
                    Parcel data = Parcel.obtain();
                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
                                            data, null, 0);
                    data.recycle();
                }
            } catch (RemoteException ex) {
                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
            }

WindowManagerServiceでした。こんな変則的な呼び出し方をしていました。

さらにこのメソッドはActivityManagerService#enableScreenAfterBoot から呼ばれています。

おまけ

rootのshellで以下のコマンドを実行するとブートアニメーションが始まります。

# setprop ctl.start bootanim

止めるときは

# setprop ctl.stop bootanim


トラックバックURL

コメントする

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

QRコード
QRコード