AOSP开机动画调测技术点(基于Android13)

news2024/11/27 20:50:19

AOSP开机动画调测技术点(基于Android13)

开机动画替换

  1. 首先,在你的计算机上创建一个名为"bootanimation"的文件夹,并将"part0"、"part1"和"desc.txt"这三个文件复制到该文件夹中。这些文件包含了开机动画的图像帧和描述信息。

  2. 在命令行中切换到bootanimation文件夹,并执行以下命令将文件夹中的内容打包成一个名为"bootanimation.zip"的压缩文件:

zip -r -0 bootanimation.zip part0 part1 desc.txt

这个命令的含义是将当前目录下的"part0"、"part1"和"desc.txt"三个文件打包成一个名为"bootanimation.zip"的压缩文件。

  • -r:表示递归地将指定目录下的所有文件和子目录都包含在压缩文件中。
  • -0:表示使用不进行压缩的存储模式,即不对文件进行压缩处理,直接存储到压缩包中。
  1. 使用ADB(Android Debug Bridge)将生成的bootanimation.zip文件复制到设备的/system/media/目录中。请注意,这一步需要设备具有root权限以及重新挂载/system分区。你可以使用以下命令完成这一步骤:
adb root
adb remount
adb push bootanimation.zip /system/media/
  1. 执行以下命令来启动新的开机动画:
   adb shell setprop service.bootanim.exit 0
   adb shell setprop ctl.start bootanim
  1. 现在你可以观察到新的开机动画效果。如果想退出新的开机动画,执行以下命令:
   adb shell setprop service.bootanim.exit 1

Android开机动画(desc.txt)格式

开机动画分为2个阶段的图片资源加载,part0和part2, 加载规则在desc.txt文件中进行描述

desc.txt  part0  part1

part0与part1中的图片需要按照数字大小顺序标记。

desc.txt内容如下:

通用参数

第一行定义了动画的一般参数:

WIDTH HEIGHT FPS [PROGRESS]
  • WIDTH: 动画的宽度(像素)
  • HEIGHT: 动画的高度(像素)
  • FPS: 每秒的帧数,例如60
  • PROGRESS: 是否在最后一部分显示进度百分比
    • 百分比将以"x"坐标为基准,在动画高度的1/3处显示。

动态着色属性

如果使用动态着色功能,则提供一个可选的行来指定动态着色属性的格式。如果不使用动态着色,则可以跳过此行。

动画部分

接下来,根据以下格式提供多行来定义动画的各个部分:

TYPE COUNT PAUSE PATH [FADE [#RGBHEX [CLOCK1 [CLOCK2]]]]
  • TYPE: 单个字符,表示此动画段的类型:
    • p – 该部分会播放,除非在启动结束之前被中断
    • c – 该部分将播放到完成,无论如何
    • f – 与 p 类似,但在继续播放的同时,指定的帧数正在淡出。只有第一个被中断的 f 部分会被淡出,其他后续的 f 部分会被跳过。
  • COUNT: 播放动画的次数,或者为0以无限循环,直到启动完成
  • PAUSE: 此部分结束后延迟的帧数
  • PATH: 包含此部分帧图片的目录(例如 part0
  • FADE: (仅适用于 f 类型) 被中断时要淡出的帧数,其中 0 表示立即淡出,使 f ... 0 的行为类似于 p,并且不将其视为淡出部分
  • RGBHEX: (可选) 背景颜色,表示为 #RRGGBB
  • CLOCK1, CLOCK2: (可选) 绘制当前时间(用于手表)的坐标:
    • 如果只提供 CLOCK1,则它是时钟的y坐标,x坐标默认为 c
    • 如果同时提供 CLOCK1CLOCK2,则 CLOCK1 是x坐标,CLOCK2 是y坐标
    • 值可以是正整数、负整数或 c
      • c – 将文本居中
      • n – 将文本定位到距起始位置的n像素处;在x轴上为左边缘,在y轴上为底部边缘
      • -n – 将文本定位到距结束位置的n像素处;在x轴上为右边缘,在y轴上为顶部边缘
    • 示例:
      • -24c -24 将文本定位到距离屏幕顶部24像素处,水平居中
      • 16 c 将文本定位到距离屏幕左侧16像素处,垂直居中
      • -32 32 将文本定位到距离屏幕边缘向上32像素,向左32像素的位置

此外,还有一个特殊的类型 $SYSTEM,它加载并播放 /system/media/bootanimation.zip
以上是关于Android开机动画的desc.txt配置文件的格式说明。该文件定义了动画的属性和各个部分的行为。

源码分析

frameworks/base/cmds/bootanimation

.
├── Android.bp
├── audioplay.cpp
├── audioplay.h
├── BootAnimation.cpp
├── BootAnimation.h
├── bootanimation_main.cpp
├── BootAnimationUtil.cpp
├── BootAnimationUtil.h
├── bootanim.rc
├── FORMAT.md
└── OWNERS

定义服务

开启动画启动规则定义在bootanim.rc

service bootanim /system/bin/bootanimation
    class core animation
    user graphics
    group graphics audio
    disabled
    oneshot
    ioprio rt 0
    task_profiles MaxPerformance

开机动画的服务配置文件字段解释如下:

  • service: 指明服务的名称为"bootanim",即开机动画服务。
  • /system/bin/bootanimation: 指定了开机动画的执行文件路径为"/system/bin/bootanimation"。
  • class core animation: 表示此服务属于核心服务,并且是与动画相关的服务。
  • user graphics: 指定服务运行的用户为"graphics"。
  • group graphics audio: 指定服务运行的组为"graphics audio",表示具有这两个组的权限。
  • disabled: 表示此服务当前处于禁用状态,不会自动启动。
  • oneshot: 表示此服务只执行一次,完成任务后即退出。
  • ioprio rt 0: 设置了I/O调度优先级。
  • task_profiles MaxPerformance: 指定了任务的性能规格为最大性能。

根据你提供的信息,开机动画服务当前处于禁用状态,不会自动启动。

启动开机动画

开机动画在SurfaceFlinger初始化完成之后播放

//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::init() {
	......
	......
	//启动mStartPropertySetThread线程播放开机动画
	mStartPropertySetThread = getFactory().createStartPropertySetThread(presentFenceReliable);

    if (mStartPropertySetThread->Start() != NO_ERROR) {
        ALOGE("Run StartPropertySetThread failed!");
    }
}

那么看看StartPropertySetThread线程中具体如何运行

//frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp
bool StartPropertySetThread::threadLoop() {
    // Set property service.sf.present_timestamp, consumer need check its readiness
    property_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");
    // Clear BootAnimation exit flag
    property_set("service.bootanim.exit", "0");
    property_set("service.bootanim.progress", "0");
    // Start BootAnimation if not started
    property_set("ctl.start", "bootanim");
    // Exit immediately
    return false;
}

StartPropertySetThread中通过设置属性方式启动动画播放。

所以如果需要手动运行bootanimation, 需要通过下面命令完成:

setprop service.bootanim.exit 0
setprop ctl.start bootanim

接下来我们进入bootanimation实现的代码分析动画播放的具体流程。

动画播放流程

  1. 首先从main函数分析,开机动画运行在一个线程中
//frameworks/base/cmds/bootanimation/bootanimation_main.cpp
int main()
{
sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
waitForSurfaceFlinger();
boot->run("BootAnimation", PRIORITY_DISPLAY);
}
  1. 找寻开机动画文件
//frameworks/base/cmds/bootanimation/BootAnimation.cpp
void BootAnimation::onFirstRef() {
	......
	preloadAnimation();
	......
}
bool BootAnimation::preloadAnimation() {
	  //查找开机动画
	  findBootAnimationFile();
    if (!mZipFileName.isEmpty()) {
    	//加载开机动画
        mAnimation = loadAnimation(mZipFileName);
        return (mAnimation != nullptr);
    }
    return false;
}
//找寻开机动画文件主要流程即在该函数中完成
void BootAnimation::findBootAnimationFile() {
	......
	//加密设备开机动画路径
	static const std::vector<std::string> encryptedBootFiles = {
            PRODUCT_ENCRYPTED_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE,
        };
    // 启动动画路径
    static const std::vector<std::string> bootFiles = {
        APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE,
        OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE
    };   
    ......    
}
  1. 加载开机动画文件并解析desc文件
//frameworks/base/cmds/bootanimation/BootAnimation.cpp
BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) {
    if (mLoadedFiles.indexOf(fn) >= 0) {
        SLOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
            fn.string());
        return nullptr;
    }
    ZipFileRO *zip = ZipFileRO::open(fn);
    if (zip == nullptr) {
        SLOGE("Failed to open animation zip \"%s\": %s",
            fn.string(), strerror(errno));
        return nullptr;
    }
    ALOGD("%s is loaded successfully", fn.string());
	//解析bootanimation.zip并填充Animation
    Animation *animation =  new Animation;
    animation->fileName = fn;
    animation->zip = zip;
    animation->clockFont.map = nullptr;
    mLoadedFiles.add(animation->fileName);
	//解析desc.txt文件并填充Animation对象
    parseAnimationDesc(*animation);
    if (!preloadZip(*animation)) {
        releaseAnimation(animation);
        return nullptr;
    }
    mLoadedFiles.remove(fn);
    return animation;
}
  1. 初始化显示参数
//frameworks/base/cmds/bootanimation/BootAnimation.cpp
status_t BootAnimation::readyToRun() {

//设置分辨率、创建Surface等
ui::Size resolution = displayMode.resolution;
    resolution = limitSurfaceSize(resolution.width, resolution.height);
    // create the native surface
    sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
            resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);

}

// initialize opengl and egl
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(display, nullptr, nullptr);
    
  1. 进入最终播放流程
//frameworks/base/cmds/bootanimation/BootAnimation.cpp
bool BootAnimation::threadLoop() {
    bool result;
    initShaders();
    // 初始化着色器

    // 为启动视频功能进行初始化
    mStartbootanimaTime = 0;
    mBootVideoTime = -1;
	//Android还支持播放视频文件,这样可以方便广告植入,开展开机广告业务
    if (mVideoAnimation) {
        result = video();
    } else {
        // 如果没有启动动画文件,那么使用默认的安卓logo动画。
        if (mZipFileName.isEmpty()) {
            ALOGD("No animation file");
            result = android();
        } else {
            result = movie();
        }
    }

    // 关闭回调
    mCallbacks->shutdown();
    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroyContext(mDisplay, mContext);
    eglDestroySurface(mDisplay, mSurface);
    mFlingerSurface.clear();
    mFlingerSurfaceControl.clear();
    eglTerminate(mDisplay);
    eglReleaseThread();
    IPCThreadState::self()->stopProcess();

    return result;
}

bool BootAnimation::movie() {
    if (mAnimation == nullptr) {
        mAnimation = loadAnimation(mZipFileName);
    }
	......
	 playAnimation(*mAnimation);
	......
	releaseAnimation(mAnimation);
	......
}

bool BootAnimation::playAnimation(const Animation& animation) {
    const size_t pcount = animation.parts.size();
    nsecs_t frameDuration = s2ns(1) / animation.fps;
    for (size_t i=0 ; i<pcount ; i++) {
        const Animation::Part& part(animation.parts[i]);
        const size_t fcount = part.frames.size();

        // Handle animation package
        if (part.animation != nullptr) {
            playAnimation(*part.animation);
            if (exitPending())
                break;
            continue; //to next part
        }
        //
        /
        //使用gl绘制每一帧的图像
        //第2轮及以后的播放
         if (r > 0) {
                    glBindTexture(GL_TEXTURE_2D, frame.tid);
                } else {
                //第一轮播放需要初始化
                    glGenTextures(1, &frame.tid);
                    glBindTexture(GL_TEXTURE_2D, frame.tid);
                    int w, h;
                    // Set decoding option to alpha unpremultiplied so that the R, G, B channels
                    // of transparent pixels are preserved.
                    initTexture(frame.map, &w, &h, false /* don't premultiply alpha */);
                }
       //
       //
   }
}
    

动画退出时机

//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private void performEnableScreen() {
	
	///
	/
	if (!mBootAnimationStopped) {
                Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
                // 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.
                SystemProperties.set("service.bootanim.exit", "1");
                mBootAnimationStopped = true;
            }
	
	///
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1291245.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

易基因:人早期胚胎发育的表观遗传调控(染色质重塑+组蛋白修饰+DNA甲基化)|深度综述

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 哺乳动物发育研究促进了对协调胚胎发生遗传、表观遗传和细胞过程的理解&#xff0c;并揭示了对人类胚胎发生特异性新见解。最近研究生成了人类早期胚胎发生的第一个表观遗传学图谱&#…

继续研究超大规模数据场景的问题

关卡名 继续海量数据场景下的热门算法题 我会了✔️ 1. 对20GB文件进行排序 ✔️ 2. 超大文本中搜索两个单词的最短距离 ✔️ 3. 从10亿数字中寻找最小的100万个数字 ✔️ 1. 对20GB文件进行排序 题目要求&#xff1a;假设你有一个20GB的文件&#xff0c;每行一个字符串&…

什么是网站监控

在现今网络高度发展的时代中&#xff0c;网站是了解一家企业&#xff0c;个人最简单便捷的方式之一&#xff1b;个人查询资料信息也是需要通过网站。是与人们的生活密不可分。网站上面任何停机时间都可能直接导致收入损失和客户不满&#xff0c;这就也是为什么会出现网站监控服…

题目分析,高度理解一维二维数组的申请和[]是什么运算符

第0题: 动态申请二维数组并输出非负数和 和负数出现次数 思路:输入数组大小,然后申请内存并不对其初始化,提高速度,传入数据到申请的数组中,判断如果数组中有元素小于0对其进行计数,否则加上非0数最后输出答案,释放内存 第一题: 解答: 运行结果: 思路分析: 创建长度为20的…

C++ 教程 - 01

文章目录 C介绍环境配置第一个cpp程序案例练习 变量 C介绍 基于C语言&#xff0c;继承了C的所有语法&#xff1b; 静态类型语言&#xff0c;需要先编译&#xff0c;再执行&#xff1b; 贴近底层硬件&#xff0c;运行速度快&#xff1b; 支持面向对象、面向泛型&#xff0c…

一文读懂MySQL基础知识文集(8)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

CSS的逻辑组合伪类

CSS 的逻辑组合伪类有 4 种&#xff0c;分别是&#xff1a;:not()、:is()、:where()和&#xff1a;has()。 否定伪类:not() :not 伪类选择器用来匹配不符合一组选择器的元素。由于它的作用是防止特定的元素被选中&#xff0c;它也被称为反选伪类&#xff08;negation pseudo-…

编程实战:类C语法的编译型脚本解释器(九)编译语句

系列入口&#xff1a;编程实战&#xff1a;类C语法的编译型脚本解释器&#xff08;系列&#xff09;-CSDN博客 前文已经介绍了编译入口&#xff0c;核心就是语句&#xff0c;本文介绍语句的编译。 目录 一、代码概览 二、辅助函数 2.1 tokens.IsPosNotToken(pos) 2.2 toke…

华为快应用遇到的坑(uniapp开发)

我这边是使用uniapp开发的华为快应用&#xff0c;我想实现的效果就是收藏功能&#xff0c;点击白色收藏&#xff0c;收藏变成红色&#xff0c;点击红色收藏变成白色收藏 <template><cover-view click"collect"><cover-image v-if"is_collect&quo…

cocos creator “TypeError: Cannot set property ‘string‘ of null

背景&#xff1a; 学习cocos creator时遇到"TypeError: Cannot set property string of null" 错误。具体代码如下&#xff1a;property({ type: Label })public stepsLabel: Label | null null;update(deltaTime: number) {this.stepsLabel.string Math.floor(…

在Linux系统中更换yum源为阿里云

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff0…

学生成绩管理系统(Java)

开发环境: Windows 11 IDEA 2021.3.3 需求: package com.it.neu;import java.util.ArrayList; import java.util.Scanner;import static java.time.Clock.system;class Student { //创建学生类private String Stu_name;private String Stu_id;public Student(String id, S…

C++使用策略模式,减少使用switch...case...

目录 原理函数类模板函数使用switch...case...不使用switch...case... 知识点decltypestd::remove_reference 原理 函数 #include <iostream> #include <functional> #include <map>void fun1(int a, int b) {std::cout << "fun1 : a "<…

学生成绩的增删改查

接上一篇MySQL数据库与其管理工具Navicat link 1.下载JDBC 可以登录MySQL的官方网站&#xff1a;www.mysql.com&#xff0c;下载JDBC-MySQL数据库驱动&#xff08;JDBC Driver for MySQL&#xff09;下载mysql-connector-java-5.1.40.zip后&#xff0c;将该zip文件解压至硬盘&a…

当使用RSA加密,从手机前端到服务器后端的请求数据存在+

将转成了空格&#xff0c;导致解密出错 将空格转成了

Numpy 实现基尼指数算法的决策树

基尼系数实现决策树 基尼指数 Gini ⁡ ( D ) 1 − ∑ k 1 K ( ∣ C k ∣ ∣ D ∣ ) 2 \operatorname{Gini}(D)1-\sum_{k1}^{K}\left(\frac{\left|C_{k}\right|}{|D|}\right)^{2} Gini(D)1−k1∑K​(∣D∣∣Ck​∣​)2 特征 A A A条件下集合 D D D的基尼指数&#xff1a; Gi…

『VUE3后台—硅谷甄选』

一、准备前期 pnpm create vite

学习Python的未来前景分析

文章目录 前言学python可以干什么如果具备Python编程&#xff0c;能用Python做什么&#xff1a;学Python语言能干什么1.常规软件开发2.科学计算3.自动化运维4.云计算 学python编程对未来的影响关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Py…

2024年江苏省职业院校技能大赛信息安全管理与评估 第二阶段学生组(样卷)

2024年江苏省职业院校技能大赛信息安全管理与评估 第二阶段学生组&#xff08;样卷&#xff09; 竞赛项目赛题 本文件为信息安全管理与评估项目竞赛-第二阶段样题&#xff0c;内容包括&#xff1a;网络安全事件响应、数字取证调查、应用程序安全。 本次比赛时间为180分钟。 …

星钻图形输出

答案&#xff1a; #include <stdio.h> int a 0, b 0; void printLine(int a , int b) //输出一行包含&#xff1a;若干个空格 若干个*&#xff0c;第一&#xff0c;二个参数为空格数和*数&#xff1b; (定义一个星钻输出函数) {while (a--) //打印a个空格{printf(…