Android开机动画

Android开机动画

  • 1、BootLoader开机图片
  • 2、Kernel开机图片
  • 3、系统启动时(BootAnimation)动画
    • 3.1 bootanimation.zip位置
    • 3.2 bootanimation启动
    • 3.3 SurfaceFlinger启动bootanimation
    • 3.4 播放开机动画playAnimation
    • 3.6 开机动画退出检测
    • 3.7 简易时序图
  • 4、bootanimation.zip文件

android12-release
推荐 Android 12 开机动画代码与流程详解


在这里插入图片描述

1、BootLoader开机图片

一般使用rle格式图片;例如放在splash分区

adb reboot bootloader
fastboot flash splash splash.img
fastboot reboot

2、Kernel开机图片

记录 kernel/drivers/video/msm/msm_fb.c 也是读出根目录下的xx.rle,并显示为开机画面

3、系统启动时(BootAnimation)动画

使用BootAnimation程序显示开机画面,如需修改开机画面,不用修改代码,只需按格式要求做bootanimation.zip包,放在系统的/system/media目录中,或/oem/media/product/media等目录。

代码路径:frameworks/base/cmds/bootanimation

3.1 bootanimation.zip位置

frameworks/base/cmds/bootanimation/BootAnimation.cpp,例如bootanimation.zip
在这里插入图片描述

3.2 bootanimation启动

frameworks/base/cmds/bootanimation/Android.bp
frameworks/base/cmds/bootanimation/bootanim.rc
frameworks/base/cmds/bootanimation/bootanimation_main.cpp
frameworks/base/cmds/bootanimation/BootAnimation.cpp
frameworks/base/cmds/bootanimation/BootAnimationUtil.cpp

SurfaceFlinger进程名:bootanim
bin文件:/system/bin/bootanimation
对应启动入口:/frameworks/base/cmds/bootanimation/bootanimation_main.cpp

bootAnimationDisabled()检测系统属性(debug.sf.nobootanimation、ro.boot.quiescent、ro.bootanim.quiescent.enabled),noBootAnimation 是否启动开机动画。注意init进程在启动bootanimation服务是disable的,不会主动将应用程序bootanimation启动起来。启动bootanimation是从surfaceFlinger这边来启动的

frameworks/base/cmds/bootanimation/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)sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());waitForSurfaceFlinger();boot->run("BootAnimation", PRIORITY_DISPLAY);ALOGV("Boot animation set up. Joining pool.");IPCThreadState::self()->joinThreadPool();}return 0;
}

frameworks/base/cmds/bootanimation/BootAnimationUtil.cpp

bool bootAnimationDisabled() {char value[PROPERTY_VALUE_MAX];property_get("debug.sf.nobootanimation", value, "0");if (atoi(value) > 0) {return true;}property_get("ro.boot.quiescent", value, "0");if (atoi(value) > 0) {// Only show the bootanimation for quiescent boots if this system property is set to enabledif (!property_get_bool("ro.bootanim.quiescent.enabled", false)) {return true;}}return false;
}

3.3 SurfaceFlinger启动bootanimation

SurfaceFlinger启动-Android12 初始化时候 mStartPropertySetThread->Start() 在线程中设置property_set("ctl.start", "bootanim")启动开机动画

/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp

#include <cutils/properties.h>
#include "StartPropertySetThread.h"namespace android {StartPropertySetThread::StartPropertySetThread(bool timestampPropertyValue):Thread(false), mTimestampPropertyValue(timestampPropertyValue) {}status_t StartPropertySetThread::Start() {return run("SurfaceFlinger::StartPropertySetThread", PRIORITY_NORMAL);
}bool StartPropertySetThread::threadLoop() {// Set property service.sf.present_timestamp, consumer need check its readinessproperty_set(kTimestampProperty, mTimestampPropertyValue ? "1" : "0");// Clear BootAnimation exit flagproperty_set("service.bootanim.exit", "0");property_set("service.bootanim.progress", "0");// Start BootAnimation if not startedproperty_set("ctl.start", "bootanim");// Exit immediatelyreturn false;
}} // namespace android

3.4 播放开机动画playAnimation

  • result = android()android原生动画;result = movie()自动动画
  • playAnimation(*mAnimation)播放动画;releaseAnimation(mAnimation)释放动画资源
  • 播放动画过程:initTexture(frame.map, &w, &h)drawClock(animation.clockFont, part.clockPosX, part.clockPosY)drawProgress(lastDisplayedProgress, animation.progressFont, posX, posY)checkExit()
  • checkExit()检测属性"service.bootanim.exit"退出动画
bool BootAnimation::threadLoop() {bool result;// We have no bootanimation file, so we use the stock android logo// animation.if (mZipFileName.isEmpty()) {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);}if (mAnimation == nullptr)return false;// mCallbacks->init() may get called recursively,// this loop is needed to get the same resultsfor (const Animation::Part& part : mAnimation->parts) {if (part.animation != nullptr) {mCallbacks->init(part.animation->parts);}}mCallbacks->init(mAnimation->parts);bool anyPartHasClock = false;for (size_t i=0; i < mAnimation->parts.size(); i++) {if(validClock(mAnimation->parts[i])) {anyPartHasClock = true;break;}}if (!anyPartHasClock) {mClockEnabled = false;}// Check if npot textures are supportedmUseNpotTextures = false;String8 gl_extensions;const char* exts = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));if (!exts) {glGetError();} else {gl_extensions.setTo(exts);if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||(gl_extensions.find("GL_OES_texture_npot") != -1)) {mUseNpotTextures = true;}}// Blend required to draw time on top of animation frames.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);glShadeModel(GL_FLAT);glDisable(GL_DITHER);glDisable(GL_SCISSOR_TEST);glDisable(GL_BLEND);glBindTexture(GL_TEXTURE_2D, 0);glEnable(GL_TEXTURE_2D);glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);bool clockFontInitialized = false;if (mClockEnabled) {clockFontInitialized =(initFont(&mAnimation->clockFont, CLOCK_FONT_ASSET) == NO_ERROR);mClockEnabled = clockFontInitialized;}initFont(&mAnimation->progressFont, PROGRESS_FONT_ASSET);if (mClockEnabled && !updateIsTimeAccurate()) {mTimeCheckThread = new TimeCheckThread(this);mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);}playAnimation(*mAnimation);if (mTimeCheckThread != nullptr) {mTimeCheckThread->requestExit();mTimeCheckThread = nullptr;}if (clockFontInitialized) {glDeleteTextures(1, &mAnimation->clockFont.texture.name);}releaseAnimation(mAnimation);mAnimation = nullptr;return false;
}
bool BootAnimation::playAnimation(const Animation& animation) {const size_t pcount = animation.parts.size();nsecs_t frameDuration = s2ns(1) / animation.fps;SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",elapsedRealtime());int fadedFramesCount = 0;int lastDisplayedProgress = 0;for (size_t i=0 ; i<pcount ; i++) {const Animation::Part& part(animation.parts[i]);const size_t fcount = part.frames.size();glBindTexture(GL_TEXTURE_2D, 0);// Handle animation packageif (part.animation != nullptr) {playAnimation(*part.animation);if (exitPending())break;continue; //to next part}// process the part not only while the count allows but also if already fadingfor (int r=0 ; !part.count || r<part.count || fadedFramesCount > 0 ; r++) {if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;mCallbacks->playPart(i, part, r);glClearColor(part.backgroundColor[0],part.backgroundColor[1],part.backgroundColor[2],1.0f);// For the last animation, if we have progress indicator from// the system, display it.int currentProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);bool displayProgress = animation.progressEnabled &&(i == (pcount -1)) && currentProgress != 0;for (size_t j=0 ; j<fcount ; j++) {if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;processDisplayEvents();const int animationX = (mWidth - animation.width) / 2;const int animationY = (mHeight - animation.height) / 2;const Animation::Frame& frame(part.frames[j]);nsecs_t lastFrame = systemTime();if (r > 0) {glBindTexture(GL_TEXTURE_2D, frame.tid);} else {if (part.count != 1) {glGenTextures(1, &frame.tid);glBindTexture(GL_TEXTURE_2D, frame.tid);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);}int w, h;initTexture(frame.map, &w, &h);}const int xc = animationX + frame.trimX;const int yc = animationY + frame.trimY;Region clearReg(Rect(mWidth, mHeight));clearReg.subtractSelf(Rect(xc, yc, xc+frame.trimWidth, yc+frame.trimHeight));if (!clearReg.isEmpty()) {Region::const_iterator head(clearReg.begin());Region::const_iterator tail(clearReg.end());glEnable(GL_SCISSOR_TEST);while (head != tail) {const Rect& r2(*head++);glScissor(r2.left, mHeight - r2.bottom, r2.width(), r2.height());glClear(GL_COLOR_BUFFER_BIT);}glDisable(GL_SCISSOR_TEST);}// specify the y center as ceiling((mHeight - frame.trimHeight) / 2)// which is equivalent to mHeight - (yc + frame.trimHeight)const int frameDrawY = mHeight - (yc + frame.trimHeight);glDrawTexiOES(xc, frameDrawY, 0, frame.trimWidth, frame.trimHeight);// if the part hasn't been stopped yet then continue fading if necessaryif (exitPending() && part.hasFadingPhase()) {fadeFrame(xc, frameDrawY, frame.trimWidth, frame.trimHeight, part,++fadedFramesCount);if (fadedFramesCount >= part.framesToFadeCount) {fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading}}if (mClockEnabled && mTimeIsAccurate && validClock(part)) {drawClock(animation.clockFont, part.clockPosX, part.clockPosY);}if (displayProgress) {int newProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0);// In case the new progress jumped suddenly, still show an// increment of 1.if (lastDisplayedProgress != 100) {// Artificially sleep 1/10th a second to slow down the animation.usleep(100000);if (lastDisplayedProgress < newProgress) {lastDisplayedProgress++;}}// Put the progress percentage right below the animation.int posY = animation.height / 3;int posX = TEXT_CENTER_VALUE;drawProgress(lastDisplayedProgress, animation.progressFont, posX, posY);}handleViewport(frameDuration);eglSwapBuffers(mDisplay, mSurface);nsecs_t now = systemTime();nsecs_t delay = frameDuration - (now - lastFrame);//SLOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));lastFrame = now;if (delay > 0) {struct timespec spec;spec.tv_sec  = (now + delay) / 1000000000;spec.tv_nsec = (now + delay) % 1000000000;int err;do {err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, nullptr);} while (err<0 && errno == EINTR);}checkExit();}usleep(part.pause * ns2us(frameDuration));if (exitPending() && !part.count && mCurrentInset >= mTargetInset &&!part.hasFadingPhase()) {if (lastDisplayedProgress != 0 && lastDisplayedProgress != 100) {android::base::SetProperty(PROGRESS_PROP_NAME, "100");continue;}break; // exit the infinite non-fading part when it has been played at least once}}}// Free textures created for looping parts now that the animation is done.for (const Animation::Part& part : animation.parts) {if (part.count != 1) {const size_t fcount = part.frames.size();for (size_t j = 0; j < fcount; j++) {const Animation::Frame& frame(part.frames[j]);glDeleteTextures(1, &frame.tid);}}}return true;
}

3.6 开机动画退出检测

  • checkExit()检测属性"service.bootanim.exit"退出动画;在playAnimation方法和android方法中都有一个checkExit方法来负责检查是否退出动画
  • WMS中performEnableScreen()设置SystemProperties.set("service.bootanim.exit", "1")
void BootAnimation::checkExit() {// Allow surface flinger to gracefully request shutdownchar value[PROPERTY_VALUE_MAX];property_get(EXIT_PROP_NAME, value, "0");int exitnow = atoi(value);if (exitnow) {requestExit();}
}

在这里插入图片描述

private void performEnableScreen() {synchronized (mGlobalLock) {ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: mDisplayEnabled=%b"+ " mForceDisplayEnabled=%b" + " mShowingBootMessages=%b"+ " mSystemBooted=%b mOnlyCore=%b. %s", mDisplayEnabled,mForceDisplayEnabled, mShowingBootMessages, mSystemBooted, mOnlyCore,new RuntimeException("here").fillInStackTrace());if (mDisplayEnabled) {return;}if (!mSystemBooted && !mShowingBootMessages) {return;}if (!mShowingBootMessages && !mPolicy.canDismissBootAnimation()) {return;}// Don't enable the screen until all existing windows have been drawn.if (!mForceDisplayEnabled) {if (mBootWaitForWindowsStartTime < 0) {// First time we will start waiting for all windows to be drawn.mBootWaitForWindowsStartTime = SystemClock.elapsedRealtime();}for (int i = mRoot.getChildCount() - 1; i >= 0; i--) {if (mRoot.getChildAt(i).shouldWaitForSystemDecorWindowsOnBoot()) {return;}}long waitTime = SystemClock.elapsedRealtime() - mBootWaitForWindowsStartTime;mBootWaitForWindowsStartTime = -1;if (waitTime > 10) {ProtoLog.i(WM_DEBUG_BOOT,"performEnableScreen: Waited %dms for all windows to be drawn",waitTime);}}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;}if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {ProtoLog.i(WM_DEBUG_BOOT, "performEnableScreen: Waiting for anim complete");return;}try {IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");if (surfaceFlinger != null) {ProtoLog.i(WM_ERROR, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");Parcel data = Parcel.obtain();data.writeInterfaceToken("android.ui.ISurfaceComposer");surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHEDdata, null, 0);data.recycle();}} catch (RemoteException ex) {ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");}EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);mDisplayEnabled = true;ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!");// Enable input dispatch.mInputManagerCallback.setEventDispatchingLw(mEventDispatchingEnabled);}try {mActivityManager.bootAnimationComplete();} catch (RemoteException e) {}mPolicy.enableScreenAfterBoot();// Make sure the last requested orientation has been applied.updateRotationUnchecked(false, false);
}

3.7 简易时序图

在这里插入图片描述

4、bootanimation.zip文件

bootanimation.zip
在这里插入图片描述 在这里插入图片描述
bootanimation.zip\desc.txt:

1080 2400 5
p 0 5 part0

bootanimation.zip\part0:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【力扣周赛】第 361 场周赛(⭐前缀和+哈希表 树上倍增、LCA⭐)

文章目录 竞赛链接Q1&#xff1a;7020. 统计对称整数的数目竞赛时代码——枚举预处理 Q2&#xff1a;8040. 生成特殊数字的最少操作&#xff08;倒序遍历、贪心&#xff09;竞赛时代码——检查0、00、25、50、75 Q3&#xff1a;2845. 统计趣味子数组的数目竞赛时代码——前缀和…

嵌入式基础知识-DMA

本篇来介绍DMA的一些基础知识。 1 DMA简介 DMA&#xff08;Direct Memory Access&#xff09;,中文名为直接内存访问&#xff0c;它是一些计算机总线架构提供的功能&#xff0c;能使数据从附加设备&#xff08;如磁盘驱动器&#xff09;直接发送到计算机主板的内存上。对应嵌…

视频汇聚/视频云存储/视频监控管理平台EasyCVR部署后无法正常启用是什么问题?该如何解决?

安防监控/视频监控/视频汇聚平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;视频云存储/安防监控汇聚平台EasyCVR支持多种播放协议&#xff0c;包括&#xff1a;HLS、HTTP-FLV、WebSoc…

kafka-- kafka集群环境搭建

kafka集群环境搭建 # 准备zookeeper环境 (zookeeper-3.4.6) # 下载kafka安装包 https://archive.apache.org/dist/kafka/2.1.0/kafka_2.12-2.1.0.tgz # 上传 : 172.16.144.133 cd /usr/local/softwaretar -zxvf /usr/local/software/kafka_2.12-2.1.0.tgz -C /usr/local…

BCSP-玄子Share-Java框基础_工厂模式/代理模式

三、设计模式 3.1 设计模式简介 软件设计中的三十六计是人们在长期的软件开发中的经验总结是对某些特定问题的经过实践检验的特定解决方法被广泛运用在 Java 框架技术中 3.1.1 设计模式的优点 设计模式是可复用的面向对象软件的基础可以更加简单方便地复用成功的设计和体系…

UDP和TCP协议报文格式详解

在初识网络原理(初识网络原理_蜡笔小心眼子&#xff01;的博客-CSDN博客)这篇博客中,我们简单的了解了一下TCP/IP五层网络模型,这篇博客将详细的学习一下五层网络模型中传输层的两个著名协议:UDP和TCP 目录 一, 传输层的作用 二, UDP 1,UDP协议的特点 2,UDP报文格式 三, TC…

qt连接tcp通信和连接数据库

通过数据库实现学生管理系统 widget.cpp #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//判断数据库对象是否包含了自己使用的数据库 Studemt.dbif(!db.co…

RK3399平台开发系列讲解(内核调试篇)IO 数据工具:iostat和iotop

🚀返回专栏总目录 文章目录 一、iostat 命令二、/proc/diskstats 文件三、iotop 命令沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 在 Linux 系统上,iostat 和 iotop 这两个 IO 数据工具非常常用。它们都是性能分析领域中不可缺少的工具性软件。 一、iostat 命令…

Python钢筋混凝土结构计算.pdf-已知弯矩确定混凝土梁截面尺寸

计算原理 确定混凝土梁截面的合理尺寸通常需要考虑弯矩、受力要求和约束条件等多个因素。以下是一种常见的计算公式&#xff0c;用于基于已知弯矩确定混凝土梁截面的合理尺寸&#xff1a; 请注意&#xff0c;以上公式仅提供了一种常见的计算方法&#xff0c;并且具体的规范和设…

优化Docker权限管理:配置Docker用户组

Docker 利用 Linux 的用户和组权限来管理对 Docker 守护进程的访问权限。一般情况下&#xff0c;只有 root 用户和属于 docker 用户组的用户才被允许访问 Docker 守护进程。在 Linux 系统上使用 Docker 时&#xff0c;如果您尚未配置 docker 用户组&#xff0c;那么作为非 root…

EasyPOI处理excel、CSV导入导出

1 简介 使用POI在导出导出excel、导出csv、word时代码有点过于繁琐&#xff0c;好消息是近两年在开发市场上流行一种简化POI开发的类库&#xff1a;easyPOI。从名称上就能发现就是为了简化开发。 能干什么&#xff1f; Excel的快速导入导出,Excel模板导出,Word模板导出,可以…

通过cpolar内网穿透,在家实现便捷的SSH远程连接公司内网服务器教程

文章目录 1. Linux CentOS安装cpolar2. 创建TCP隧道3. 随机地址公网远程连接4. 固定TCP地址5. 使用固定公网TCP地址SSH远程 本次教程我们来实现如何在外公网环境下&#xff0c;SSH远程连接家里/公司的Linux CentOS服务器&#xff0c;无需公网IP&#xff0c;也不需要设置路由器。…