Android Framework开机动画播放到结束源码分析

大家好,我是Zzz今天给大家继续分享android开机动画播放到结束的源码分析,还是主打一个干货分享,这个blog主要就是源代码的分析,环境基于aosp13_r6如有错误请指出立马改成。

前言:在开机启动过程init进程已经把bootanimation拉起来了,拉起来以后首先执行的是bootanimation_main.cpp的main方法

int main()
{
    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);//设置进程的属性这里设置为DISPLAY

    bool noBootAnimation = bootAnimationDisabled(); //开机动画是否被禁止,一般默认情况为true
    ALOGI_IF(noBootAnimation,  "boot animation disabled");
    if (!noBootAnimation) {

        sp<ProcessState> proc(ProcessState::self());
        ProcessState::self()->startThreadPool();//启动线程池 ,用来初始化类似binder 跨进程通信的服务

        // create the boot animation object (may take up to 200ms for 2MB zip)
        //这里创建了一个bootanimation的实例,使用的智能指针回调到bootanimation.cpp的onFirstRef()
        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;
}

new BootAnimation(audioplay::createAnimationCallbacks()); //这里创建了一个bootanimation的实例 代码路径在frameworks/base/Bootanimation.cpp下

BootAnimation::BootAnimation(sp<Callbacks> callbacks)
        : Thread(false), mLooper(new Looper(false)), mClockEnabled(true), mTimeIsAccurate(false),
        mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) {
    mSession = new SurfaceComposerClient();//创建一个跨进程通信的client

    std::string powerCtl = android::base::GetProperty("sys.powerctl", "");//获取一下开关机的属性
    if (powerCtl.empty()) {
        mShuttingDown = false;
    } else {
        mShuttingDown = true;
    }
    ALOGD("%sAnimationStartTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
            elapsedRealtime());
}

在 bootanimation_main.cpp的main方法中因为new Bootanimation 使用了智能指针所以会回调到Bootanimation.cpp的onFirstRef()方法

void BootAnimation::onFirstRef() {
    status_t err = mSession->linkToComposerDeath(this);
    SLOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
    if (err == NO_ERROR) {
        // Load the animation content -- this can be slow (eg 200ms)
        // called before waitForSurfaceFlinger() in main() to avoid wait
        ALOGD("%sAnimationPreloadTiming start time: %" PRId64 "ms",
                mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
        preloadAnimation();//预加载动画
        ALOGD("%sAnimationPreloadStopTiming start time: %" PRId64 "ms",
                mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
    }
}

预加载动画方法preloadAnimation()

bool BootAnimation::preloadAnimation() {
    findBootAnimationFile();//找开机动画文件
    if (!mZipFileName.isEmpty()) {//当找到文件时
        mAnimation = loadAnimation(mZipFileName);//拿着文件去加载动画
        return (mAnimation != nullptr);
    }

    return false;
}

配置开机动画

void BootAnimation::findBootAnimationFile() {
   .......
    const bool playDarkAnim = android::base::GetIntProperty("ro.boot.theme", 0) == 1;
    //开机动画文件   主要就是这两个文件路径  OEM_BOOTANIMATION_FILE, SYSTEM_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
    };
    
    static const std::vector<std::string> shutdownFiles = {
        PRODUCT_SHUTDOWNANIMATION_FILE, OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE, ""
    };
    static const std::vector<std::string> userspaceRebootFiles = {
        PRODUCT_USERSPACE_REBOOT_ANIMATION_FILE, OEM_USERSPACE_REBOOT_ANIMATION_FILE,
        SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE,
    };

    if (android::base::GetBoolProperty("sys.init.userspace_reboot.in_progress", false)) {
        findBootAnimationFileInternal(userspaceRebootFiles);
    } else if (mShuttingDown) {
        findBootAnimationFileInternal(shutdownFiles);
    } else {
        findBootAnimationFileInternal(bootFiles);
    }
}

加载开机动画

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());

    Animation *animation =  new Animation;
    animation->fileName = fn;
    animation->zip = zip;
    animation->clockFont.map = nullptr;
    mLoadedFiles.add(animation->fileName);

    parseAnimationDesc(*animation);//解析zip的动画
    if (!preloadZip(*animation)) {//预加载动画
        releaseAnimation(animation);
        return nullptr;
    }

    mLoadedFiles.remove(fn);
    return animation;
}

然后执行到readyToRun,因为在Bootanimation_main.cpp中调用了run方法 而Bootanimation.cpp本身就是一个Thread,可以在Bootanimation.h头文件中看到

c++ run Thread之后会先调用readyToRun在执行到threadLoop

boot->run("BootAnimation", PRIORITY_DISPLAY);

readyToRun()主要就是绘制一些画布之类的

status_t BootAnimation::readyToRun() {
   .......

    // initialize opengl and egl
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(display, nullptr, nullptr);
    EGLConfig config = getEglConfig(display);
    EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr);
    // Initialize egl context with client version number 2.0.
    EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
    EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes);
    EGLint w, h;
    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
        return NO_INIT;

    mDisplay = display;
    mContext = context;
    mSurface = surface;
    mInitWidth = mWidth = w;
    mInitHeight = mHeight = h;
    mFlingerSurfaceControl = control;
    mFlingerSurface = s;
    mTargetInset = -1;

  ........

    return NO_ERROR;
}

在执行threadLoop() 方法

bool BootAnimation::threadLoop() {
    bool result;
    initShaders();

    // We have no bootanimation file, so we use the stock android logo
    // animation.
    if (mZipFileName.isEmpty()) {//如果文件为空则使用OpenGL进行绘制反之使用zip
        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;
}

这里我们看android()开机动画绘制,这里使用OpenGL

bool BootAnimation::android() {
    glActiveTexture(GL_TEXTURE0);
    SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
            elapsedRealtime());
    initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
    initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");
    ......
    do {
        processDisplayEvents();
     ......
        glDisable(GL_SCISSOR_TEST);
        glClear(GL_COLOR_BUFFER_BIT);

        glEnable(GL_SCISSOR_TEST);
        glDisable(GL_BLEND);
        glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
        drawTexturedQuad(x,                 yc, mAndroid[1].w, mAndroid[1].h);
        drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h);

        glEnable(GL_BLEND);
        glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
        drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h);
.....
        checkExit();//这里是动画结束退出
    } while (!exitPending());

    glDeleteTextures(1, &mAndroid[0].name);
    glDeleteTextures(1, &mAndroid[1].name);
    return false;
}

执行这个方法请求退出checkExit()

void BootAnimation::checkExit() {
    // Allow surface flinger to gracefully request shutdown
    char value[PROPERTY_VALUE_MAX];
    property_get(EXIT_PROP_NAME, value, "0");//设置退出属性  service.bootanim.exit
    int exitnow = atoi(value);
    if (exitnow) {
        requestExit();
    }
}

当执行完checkExit()后设置了退出属性,那么是谁执行退出呢?可以在代码中搜索一下在frameworks目录下执行grep "service.bootanim.exit"

property_set("service.bootanim.exit", "1"); 为1的时候是退出 0的时候启动

在这里我们发现了两处一个是WindowManagerService.java:3700: 另外一个是SurfaceFlinger.cpp:664: 也就是说在android系统中会有两处执行退出开机动画操作

./frameworks/base/core/proto/android/os/system_properties.proto:521:    optional int32  service_bootanim_exit = 23;
./frameworks/base/cmds/bootanimation/BootAnimation.cpp:105:static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
./frameworks/base/cmds/bootanimation/FORMAT.md:121:the system property `service.bootanim.exit` to a nonzero string.)
./frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java:3700: SystemProperties.set("service.bootanim.exit", "1");
./frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp:33:    property_set("service.bootanim.exit", "0");
./frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:664:    property_set("service.bootanim.exit", "1");

最后我们看zip动画播放

bool BootAnimation::movie() {
    if (mAnimation == nullptr) {
        mAnimation = loadAnimation(mZipFileName);//这里加载开机动画
    }

    if (mAnimation == nullptr)
        return false;

    .....

    // Check if npot textures are supported
    mUseNpotTextures = false;
    String8 gl_extensions;
   ......
   
   playAnimation(*mAnimation);//这个播放动画方法,播放完成后会调用的checkExit()方法进行退出

    if (mTimeCheckThread != nullptr) {
        mTimeCheckThread->requestExit();
        mTimeCheckThread = nullptr;
    }
    ....
    releaseAnimation(mAnimation);
    mAnimation = nullptr;

    return false;
}

看到最后,aosp13开机动画的播放就介绍完成了。谢谢大家

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值