BootAnimation源码流程分析

发布于:2024-12-20 ⋅ 阅读:(16) ⋅ 点赞:(0)

BootAnimation流程

bootanimation源码位于frameworks/base/cmds/bootanimation,正如其名,主要功能是加载播放开机动画,是一个C程序,编译生成的可执行文件位于/system/bin

主要逻辑:解析系统路径下的bootanimation.zip(如/system/media/bootanimation.zip),然后通过openGl方式绘制显示出来

代码目录结构如下:

  • Android.bp编译脚本,编译成可执行文件
  • bootanimation_main.cpp:程序入口,启动BootAnimation线程
  • BootAnimation.cpp:具体的业务逻辑,
  • bootanim.rc:rc脚本,配置bootanimation为系统服务
bootanimation/
├── Android.bp
├── audioplay.cpp
├── AudioPlayer.cpp
├── AudioPlayer.h
├── audioplay.h
├── BootAnimation.cpp
├── BootAnimation.h
├── bootanimation_main.cpp
├── BootAnimationUtil.cpp
├── BootAnimationUtil.h
├── bootanim.rc
├── FORMAT.md
└── OWNERS

启动BootAnimation线程

入口main函数中创建了BootAnimation对象,实际上BootAnimation是一个线程,通过run方法启动了这个线程。
Android Native Thread启动后会回调readyToRun()–>threadLoop(),IPCThreadState这个是Android模板写法,可以网上了解下。

// frameworks\base\cmds\bootanimation\BootAnimation.cpp
int main()
{
    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);

    bool noBootAnimation = bootAnimationDisabled();
    ALOGI_IF(noBootAnimation,  "boot animation disabled");
    if (!noBootAnimation) {

        sp<ProcessState> proc(ProcessState::self());
        ProcessState::self()->startThreadPool();

        // create the boot animation object (may take up to 200ms for 2MB zip)

        sp<BootAnimation> boot = new BootAnimation();

        waitForSurfaceFlinger();

        boot->run("BootAnimation", PRIORITY_DISPLAY);

        ALOGV("Boot animation set up. Joining pool.");

        IPCThreadState::self()->joinThreadPool();
    }
    return 0;
}

接下来,我们看BootAnimation构造方法中做了什么。构造方法中就创建了一个SurfaceComposerClient,先跳过

// frameworks\base\cmds\bootanimation\BootAnimation.cpp
BootAnimation::BootAnimation(sp<Callbacks> callbacks)
        : Thread(false), mLooper(new Looper(false)), mClockEnabled(true), mTimeIsAccurate(false),
        mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) {
    mSession = new SurfaceComposerClient();

    std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
    if (powerCtl.empty()) {
        mShuttingDown = false;
    } else {
        mShuttingDown = true;
    }
    ALOGD("%sAnimationStartTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
            elapsedRealtime());
}

构造方法走完后,会接着后走onFirstRef(),这里做了预加载开机动画资源,为什么叫预加载呢?
在上面main()可以看到会先等SurfaceFlinger起来才会跑BootAnimation线程,不然SurfaceFlinger没起来,UI界面绘制不出来了

// frameworks\base\cmds\bootanimation\BootAnimation.cpp
void BootAnimation::onFirstRef() {
    status_t err = mSession->linkToComposerDeath(this);
    SLOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
    if (err == NO_ERROR) {
        // Load the animation content -- this can be slow (eg 200ms)
        // called before waitForSurfaceFlinger() in main() to avoid wait
        ALOGD("%sAnimationPreloadTiming start time: %" PRId64 "ms",
                mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
        preloadAnimation();
        ALOGD("%sAnimationPreloadStopTiming start time: %" PRId64 "ms",
                mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
    }
}

加载解析资源

preloadAnimation()做了两件事情,先是找到系统中bootanimation.zip开机动画资源,然后在解析成Animation对象。

// frameworks\base\cmds\bootanimation\BootAnimation.cpp
bool BootAnimation::preloadAnimation() {
    findBootAnimationFile();
    if (!mZipFileName.isEmpty()) {
        mAnimation = loadAnimation(mZipFileName);
        return (mAnimation != nullptr);
    }

    return false;
}
  • findBootAnimationFile()从系统/system/media或者/oem/media等几个位置找bootanimation.zip,如果文件存在就找到了该位置的开机动画资源

  • loadAnimation()会对bootanimation.zip中文件信息进行解析,转换为Animation对象。

绘制界面播放资源

BootAnimation()线程跑起来后,在readyToRun()方法中会准备Surface和OpenGl,在threadLoop()会创建Shader,然后调用movie()进行绘制

// frameworks\base\cmds\bootanimation\BootAnimation.cpp
bool BootAnimation::threadLoop() {
    bool result;
    initShaders();
    // We have no bootanimation file, so we use the stock android logo
    // animation.
    if (mZipFileName.isEmpty()) {
	    ALOGD("No animation file");
        result = android();
    } else {
        result = movie();
    }

    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroyContext(mDisplay, mContext);
    eglDestroySurface(mDisplay, mSurface);
    mFlingerSurface.clear();
    mFlingerSurfaceControl.clear();
    eglTerminate(mDisplay);
    eglReleaseThread();
    return result;
}

总结

至此,BootAnimation的大体流程介绍完成了,具体细节大家可以去看具体代码。流程图如下:
如果应用需要替换开机动画资源,可以把开机动画资源写入到一个分区,然后在BootAnimation程序里面新增一个查找路径。
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到