安卓15开机动画结束流程简单分析

0 阅读3分钟

前面的一篇文章讲了如何启动bootanimation,这里假设bootanimation已经启动了。

bootanimation模块路径 frameworks/base/cmds/bootanimation

还是先看bootanimation的入口,还是main入口:

/* bootanimation_main.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)
        // 这里new BootAnimation
        sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());

        waitForSurfaceFlinger(); // 等待surfaceflinger,毕竟bootanimation的绘制要依赖它

        // BootAnimation 继承自 Thread 类,因此BootAnimation可以直接run
        boot->run("BootAnimation", PRIORITY_DISPLAY); 

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

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

概念补充:

Binder 机制:Android 跨进程通信的核心,ProcessState/IPCThreadState 是 Binder 框架的核心类,启动线程池是为了处理 SurfaceFlinger 等服务的 IPC 调用。IPCInter-Process Communication 的缩写,中文称为 “进程间通信”

sp 指针:Android 的强引用智能指针(Strong Pointer),用于管理对象的生命周期,避免内存泄漏。

这里当通过 new 创建 BootAnimation 对象并赋值给 sp<BootAnimation> 智能指针时,onFirstRef() 方法会被调用,onFirstRef() 的作用是在对象第一次被强引用(sp)持有时执行初始化逻辑

/* BootAnimation.cpp */

// BootAnimation 继承自 Thread 类,因此BootAnimation可以直接run
class BootAnimation : public Thread, public IBinder::DeathRecipient

// new的时候先执行构造函数,随后执行onFirstRef
BootAnimation::BootAnimation(sp<Callbacks> callbacks)
        : Thread(false), mLooper(new Looper(false)), mClockEnabled(true), mTimeIsAccurate(false),
        mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) {
	...
}

// 执行完构造函数后,再执行onFirstRef
void BootAnimation::onFirstRef() {
    ATRACE_CALL();
    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());
    }
}

bool BootAnimation::preloadAnimation() {
    ATRACE_CALL();
    findBootAnimationFile(); // 这里
    if (!mZipFileName.empty()) {
        mAnimation = loadAnimation(mZipFileName);
        return (mAnimation != nullptr);
    }

    return false;
}

// 开机动画存放路径
static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";

void BootAnimation::findBootAnimationFile() {
    // 从 bootFiles 列表中搜索
    static const std::vector<std::string> bootFiles = {
            APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : OEM_BOOTANIMATION_FILE,
            PRODUCT_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE
        };
    ...
    if (android::base::GetBoolProperty("sys.init.userspace_reboot.in_progress", false)) {
        findBootAnimationFileInternal(userspaceRebootFiles);
    } else if (mShuttingDown) {
        findBootAnimationFileInternal(shutdownFiles);
    } else {
        findBootAnimationFileInternal(bootFiles); // 这里,查找开机动画资源
    }
}

// 查找开机动画资源,存在就赋值给mZipFileName,返回true,否则返回false
bool BootAnimation::findBootAnimationFileInternal(const std::vector<std::string> &files) {
    ATRACE_CALL();
    for (const std::string& f : files) {
        if (access(f.c_str(), R_OK) == 0) {
            mZipFileName = f.c_str();
            return true;
        }
    }
    return false;
}

等到在bootanimation_main.cpp中执行boot->run("BootAnimation", PRIORITY_DISPLAY)时,会执行readyToRun()和threadLoop(),这两个是Thread 基类的函数,这里重写了。readyToRun() 先执行,threadLoop() 后执行。

readyToRun(): 线程进入循环之前,会先调用一次这个方法。

至于readyToRun和threadLoop的先后执行顺序,可以看system/core/libutils/Threads.cpp的定义:

/* system/core/libutils/Threads.cpp */

Thread::run -->  Thread::_threadLoop ,在_threadLoop中是先执行了readyToRun(),后执行threadLoop()

/* BootAnimation.cpp */

// 作用是 准备显示资源、创建渲染环境、初始化 OpenGL/EGL 环境
status_t BootAnimation::readyToRun() {
    ...
}



bool BootAnimation::threadLoop() {
    ATRACE_CALL();
    bool result;
    initShaders();

    // We have no bootanimation file, so we use the stock android logo
    // animation.
    if (mZipFileName.empty()) { //如果路径不存在,即没有内置自己的动画,就用安卓自己的开机动画
        ALOGD("No animation file");
        result = android();
    } else {
        result = movie(); 
    }

	...
}


bool BootAnimation::android() {
    ......
    do {
        不停的绘制开机动画
        .....

        checkExit(); // 检查是否结束动画的绘制
    } while (!exitPending());

    glDeleteTextures(1, &mAndroid[0].name);
    glDeleteTextures(1, &mAndroid[1].name);
    return false;
}


static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
void BootAnimation::checkExit() {
    ATRACE_CALL();
    // Allow surface flinger to gracefully request shutdown
    char value[PROPERTY_VALUE_MAX];
    property_get(EXIT_PROP_NAME, value, "0"); // 使用 property_get() 从系统属性服务中获取值,存储到 value 
    int exitnow = atoi(value);
    if (exitnow) { // 如果是1就退出
        requestExit();
    }
}

因此,开机动画是否退出的关键是属性service.bootanim.exit,是1就退出,0的话就继续。属性service.bootanim.exit在之前surfaceflinger启动的时候见过,当时给这个属性赋值为0了。


通过在framework中执行grep "service.bootanim.exit" ./ -rn可知,有SurfaceFlinger.cppWindowManagerService.java这两个地方将service.bootanim.exit设置为1了。

image-20260318142026397-1773885791313-1.png