Android开机动画
android12-release
推荐 Android 12 开机动画代码与流程详解
1、BootLoader开机图片
一般使用
rle格式图片
;例如放在splash分区
adb reboot bootloaderfastboot flash splash splash.imgfastboot 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 enabled if (!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 #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 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;}} // 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 results for (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 supported mUseNpotTextures = 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 package if (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 fading for (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 necessary if (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 shutdown char 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_FINISHED data, 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 5p 0 5 part0
bootanimation.zip\part0:
来源地址:https://blog.csdn.net/qq_23452385/article/details/132639363