返回顶部
首页 > 资讯 > 移动开发 >Android开机动画
  • 893
分享到

Android开机动画

AndroidBootAnimation 2023-09-18 09:09:04 893人浏览 安东尼
摘要

Android开机动画 1、BootLoader开机图片2、Kernel开机图片3、系统启动时(BootAnimation)动画3.1 bootanimation.zip位置3.2 boota

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

--结束END--

本文标题: Android开机动画

本文链接: https://lsjlt.com/news/411574.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作