AOSP15开机动画 (BootAnimation) 流程全解析与实战

186 阅读5分钟

本文档详细记录了 Android 15 (AOSP 15) 系统中,从 init 进程启动到 SurfaceFlinger 触发,再到 BootAnimation 执行与结束的完整代码流转及架构设计。


一、BootAnimation动画流程源码分析

1. init 阶段:解析与服务定义

在系统启动初期,init 进程解析 .rc 文件,定义服务的启动类别和权限。

1.1 SurfaceFlinger 配置

  • 路径frameworks/native/services/surfaceflinger/surfaceflinger.rc
  • 说明:SF 属于 coreanimation 类,通常在系统显示驱动加载后启动。
service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    capabilities CHOWN DAC_OVERRIDE SYS_NICE
    onrestart restart zygote
    task_profiles ServiceCapacityLow HighPerformance

1.2 BootAnimation 配置

  • 路径frameworks/base/cmds/bootanimation/bootanim.rc
  • 说明:默认标记为 disabled,必须由其他进程(SF)通过属性显式启动。
service bootanim /system/bin/bootanimation
   class core
   user graphics
   group graphics audio
   disabled       # 初始状态不启动
   oneshot        # 运行一次后不自动重启
   ioprio rt 4
   task_profiles MaxPerformance

2. SurfaceFlinger 阶段:触发逻辑

AOSP 15 对 SF 初始化进行了重构,删除了旧版本的异步属性设置线程类。

2.1 入口:main_surfaceflinger.cpp

  • 路径frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
  • 操作:实例化 SurfaceFlinger 并执行 flinger->init()

2.2 关键方法:initBootProperties

  • 路径:frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
// init()方法中执行异步
mInitBootPropsFuture.callOnce([this] {
    return std::async(std::launch::async, &SurfaceFlinger::initBootProperties, this);
});

// 设置开始启动动画
void SurfaceFlinger::initBootProperties() {
    property_set("service.sf.present_timestamp", mHasReliablePresentFences ? "1" : "0");

    if (base::GetBoolProperty("debug.sf.boot_animation"s, true)) {
        // Reset and (if needed) start BootAnimation.
        property_set("service.bootanim.exit", "0");
        property_set("service.bootanim.progress", "0");
        property_set("ctl.start", "bootanim");
    }
}

3. 执行阶段:BootAnimation 进程渲染

bootanimation 进程启动后,核心逻辑由 BootAnimation 类驱动。

3.1 核心初始化流程

  • 路径frameworks/base/cmds/bootanimation/BootAnimation.cpp

1、 onFirstRef(): 初始化 Binder 通信。

2、 readyToRun():

  • 调用 waitForSurfaceFlinger() 确保 SF 已注册。
  • 创建 SurfaceComposerClient 连接。
  • 创建渲染 Layer(通常名为 "BootAnimation")。

3、threadLoop(): 核心渲染循环。

  • 如果 /system/media/bootanimation.zip 存在,则解析并执行 movie()。
  • 否则执行默认的 android()(即渐变 Logo 动画)。
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(mDisplays.front());
    } else {
        result = movie();
    }

    .....
    return result;
}

4. 结束阶段:从 WMS 到退出

动画的停止是由 WindowManagerService 根据系统加载状态决定的。

4.1 WMS 发出完成信号

当系统完成启动且桌面(Launcher)准备好显示首帧时:

  • 路径frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
  • 调用SurfaceControl.bootFinished()

4.2 SF 修改退出属性

SF 收到 WMS 的 Binder 调用后,更新系统属性

  • 路径frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::bootFinished() {
    if (mBootFinished == true) {
        ALOGE("Extra call to bootFinished");
        return;
    }
    mBootFinished = true;
    FlagManager::getMutableInstance().markBootCompleted();

    ......

    // stop boot animation
    // formerly we would just kill the process, but we now ask it to exit so it
    // can choose where to stop the animation.
    property_set("service.bootanim.exit", "1");

    ......
}

4.3 动画进程响应

BootAnimation 在渲染循环中会调用 checkExit()

void BootAnimation::checkExit() {
    ATRACE_CALL();
    // Allow SurfaceFlinger to gracefully request shutdown
    char value[PROPERTY_VALUE_MAX];
    property_get(EXIT_PROP_NAME, value, "0");
    int exitnow = atoi(value);
    if (exitnow) {
        requestExit();
    }
}

二、bootanimation.zip制作实战

在 AOSP 15 中,系统支持通过自定义 bootanimation.zip 来替换默认的启动动画。该文件必须以 存储(Store) 模式进行压缩(即压缩率为 0),先上效果图。

1. 目录结构

一个标准的 bootanimation.zip 结构如下:

bootanimation.zip
├── desc.txt                # 核心控制文件(必选)
├── part0/                  # 第一阶段动画图片文件夹
│   ├── 00001.jpg
│   └── ...
├── part1/                  # 第二阶段动画图片文件夹
└── ...

2. desc.txt 语法详解

desc.txt 是一个纯文本文件,定义了动画的分辨率、帧率以及各阶段的播放逻辑。

2.1 文件格式示例

1080 2400 30
p 1 0 part0
p 0 0 part1

2.2 参数含义

  • 第一行 (Header):[宽度] [高度] [帧率]

    • 示例中:1080x2400 分辨率,每秒播放 30 帧。
  • 后续行 (Part Definition):[类型] [循环次数] [暂停帧数] [文件夹名]

    • 类型:

      • p (Plain):播放完该阶段后,如果系统启动未完成,则进入下一阶段。
      • c (Complete):必须完整播放该阶段的所有帧,即使系统已经准备好进入桌面(AOSP 15 常用此项确保品牌 Logo 完整展示)。
    • 循环次数:0 表示无限循环,直到系统发出退出信号。

    • 暂停帧数:播放完当前阶段后,停留在最后一帧的帧数。

3. AOSP 15 高级配置技巧

3.1 动态颜色 (Dynamic Coloring)

AOSP 15 支持根据系统主题色渲染动画(通常用于 Google Pixel 风格)。这需要在 desc.txt 中加入特殊的动态颜色标记,并配合特定的图片格式,但这通常需要修改 BootAnimation.cpp 中的像素处理逻辑

3.2 多显示器支持

针对折叠屏或车机(多屏环境),AOSP 15 支持为不同显示器指定动画:

  • 主屏:bootanimation.zip
  • 副屏:bootanimation_secondary.zip

3.3 压缩注意事项(关键)

在打包时,严禁使用默认压缩,如果使用了压缩(Deflate),bootanim 进程在映射 Buffer 时会失败,导致黑屏或显示默认的 "ANDROID" 文字。用window要设置“zip”和设置存储格式,或在Linux 命令行中,应使用:

zip -0qr bootanimation.zip 

4. 集成到 AOSP 镜像

要将自定义动画集成到系统编译中,请修改你的 Product Makefile(如 device.mk):

# 将本地的 zip 文件拷贝到系统的媒体目录下
PRODUCT_COPY_FILES += \
    device/provider/project/bootanimation.zip:system/media/bootanimation.zip

如果报没有权限,可以添加一下system/media白名单权限

PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
    system/media/bootanimation.zip

5. 调试实用命令

# 1. 过滤开机动画进程日志
adb logcat -s BootAnimation

# 2. 手动停止/启动动画(用于调试,需 root)
adb shell setprop ctl.stop bootanim
adb shell setprop ctl.start bootanim

# 3. 检查系统启动状态属性
adb shell getprop | grep boot
# 查看 service.bootanim.exit 的值

6. 常见问题排查 (Troubleshooting)

在 AOSP 15 开发过程中,如果自定义动画未能如期显示或出现异常,通常可以从压缩方式配置文件逻辑系统权限以及底层架构四个维度进行排查。

现象可能原因解决方法
开机完全黑屏压缩格式错误必须使用 zip -0(存储模式)打包,严禁压缩
显示 "ANDROID" 闪烁文字资源文件丢失或路径错误检查 /system/media/bootanimation.zip 是否存在
动画异常卡顿/跳帧图片过大或 CPU 负载过高降低分辨率,建议使用 JPG 格式减小解码压力
动画播不完就跳到桌面desc.txt 逻辑配置问题将关键阶段的类型从 p 改为 c (Complete)
多屏设备副屏不亮缺少副屏资源包需提供 bootanimation_secondary.zip