Android开机动画关闭流程

一步一图项目上要加一个开机动画结束的回调,我这边看下如何加

好,老规矩,如何启动动画?动画是谁启动的?怎么关闭的?谁通知关闭的

带着问题看源码

动画的启动流程

开机动画的主入口在哪?

 这个main.cpp就是主入口

那么是谁通知它启动的?

Android系统在启动SystemServer进程时,通过两个阶段来启动系统所有服务,在第一阶段启动本地服务,如SurfaceFlinger,SensorService等,在第二阶段则启动一系列的Java服务。开机动画是在什么时候启动的呢?通过查看源码,Android开机动画是在启动SurfaceFlinger服务时启动的。SystemServer的main函数首先调用init1来启动本地服务,init1函数通过JNI调用C语言中的system_init()函数来实现服务启动。

那么当SurfaceFliger启动之后 会调用init函数

void SurfaceFlinger::init()
{
    char value[PROPERTY_VALUE_MAX];
    property_get("debug.sf.showupdates", value, "0");
    mDebugRegion = atoi(value);
#ifdef DDMS_DEBUGGING
    property_get("debug.sf.ddms", value, "0");
    mDebugDDMS = atoi(value);
    if (mDebugDDMS) {
        DdmConnection::start(getServiceName());
    }
#endif
    property_get("ro.bootmode", value, "mode");
    if (!(strcmp(value, "engtest")
        && strcmp(value, "special")
        && strcmp(value, "wdgreboot")
        && strcmp(value, "unknowreboot")
        && strcmp(value, "panic"))) {
        SurfaceFlinger::sBootanimEnable = false;
    }
}

然后一系列调用,当surfaceFliger 先启动一个线程,进行初始化然后当初始化结束之后调用 startBootAnim

int Thread::_threadLoop(void* user)
{
    省略一车代码
    Thread* const self = static_cast<Thread*>(user);
    
            self->mStatus = self->readyToRun();
            
}

status_t SurfaceFlinger::readyToRun()
{
    初始化代码,本次不关心
    mReadyToRunBarrier.open();
    // start boot animation
    startBootAnim();
    return NO_ERROR;
}

当显示系统初始化完毕后,调用startBootAnim()函数来显示开机动画。

void SurfaceFlinger::startBootAnim() {
    // start boot animation
    if(SurfaceFlinger::sBootanimEnable){
        property_set("service.bootanim.exit", "0");
        property_set("ctl.start", "bootanim");
    }
}

该进程对应的源码位于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) {
//启动Binder线程池,用于接收其他进程的请求 
        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.");
		//将当前线程注册到Binder线程池中

        IPCThreadState::self()->joinThreadPool();
    }
    return 0;
}

在构造BootAnimation对象时,会调用onFirstRef函数。

void BootAnimation::onFirstRef() {

    if (err == NO_ERROR) {
         省略无用代码
        preloadAnimation();
        
    }
}

先选择需要播放的动画,然后播放

播放路径有很多,这地方很简单,感兴趣可以看一下

static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
static const char PRODUCT_BOOTANIMATION_DARK_FILE[] = "/product/media/bootanimation-dark.zip";
static const char PRODUCT_BOOTANIMATION_FILE[] = "/product/media/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
static const char APEX_BOOTANIMATION_FILE[] = "/apex/com.android.bootanimation/etc/bootanimation.zip";
static const char PRODUCT_ENCRYPTED_BOOTANIMATION_FILE[] = "/product/media/bootanimation-encrypted.zip";
static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
static const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip";
static const char PRODUCT_SHUTDOWNANIMATION_FILE[] = "/product/media/shutdownanimation.zip";
static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";

 上面是路径

bool BootAnimation::preloadAnimation() {
    选择路径 会循环直到找到,如果没有我理解会加载一个默认值
    findBootAnimationFile();
    if (!mZipFileName.isEmpty()) {
        播放动画
        mAnimation = loadAnimation(mZipFileName);
        return (mAnimation != nullptr);
    }

    return false;
}

该函数首先为SurfaceComposerClient对象注册Binder死亡通知,然后调用BootAnimation的run方法,由于BootAnimation同时继承于Thread类,前面介绍SurfaceFlinger时已经介绍到,当某个类继承于Thread类时,当调用该类的run函数时,函数首先会执行readyToRun()函数来完成线程执行前的一些工作,然后线程反复执行threadLoop()函数,在BootAnimation类中,同样重新了这两个方法

bool BootAnimation::threadLoop()
{
    bool r;
	//如果mAndroidAnimation为true,表示动画文件不存在,则显示Android滚动字样
    if (mAndroidAnimation) {
        r = android();
    } else {//显示动画
        r = movie();
    }
	//资源回收
    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroyContext(mDisplay, mContext);
    eglDestroySurface(mDisplay, mSurface);
    mFlingerSurface.clear();
    mFlingerSurfaceControl.clear();
    eglTerminate(mDisplay);
    IPCThreadState::self()->stopProcess();
    return r;
}

开机画面主要是由一个zip格式的压缩包bootanimation.zip组成,压缩包里面包含数张png格式的图片,还有一个desc.txt的文本文档,开机时按desc.txt里面的指令,屏幕上会按文件名称顺序连续的播放一张张的图片,就像播放原始的胶带影片一样,形成动画。desc.txt是一个保存形式为ANSI格式的文件,用于设置这个动画像素(大小),帧数,闪烁次数,文件夹名称等。内容如下:
480 854 10
p 1 2 folder1
p 0 2 folder2

课代表总结,SurfaceFliger在初始化第一轮由init.rc启动,初始化结束然后进行启动动画播放,新起一个线程循环播放我们的动画,按顺序获取动画路径,也就是可以做拦截

OK

那么看下结束流程

一个Activity组件在启动起来之后,就会被记录起来,等到它所运行在的主线程空闲的时候,这个主线程就会向ActivityManagerService发送一个Activity组件空闲的通知。
由于应用程序Launcher是系统中第一个被启动的应用程序,即它的根Activity组件是系统中第一个被启动的Activity组件,因此,当ActivityManagerService接收到它的空闲通知的时候,就可以知道系统是刚刚启动起来的。
在这种情况下,ActivityManagerService就会停止显示开机动画,以便可以在屏幕中显示应用程序Lancher的界面。

结束流程是一堆调用链,所以总结下

结束是Activity idle机制进行 也就是主线程空闲通知ATP 一堆调用链先放开机广播,然后进行调用让SurfaceFliger通知动画结束最后通知AMS

如何关闭动画的?

动画是启动了一个线程进行循环播放,关闭就是中断了这个线程,结束掉播放

相关推荐

  1. Android 14 transtion 动画流程

    2024-06-08 16:02:04       29 阅读
  2. Android12 关机流程

    2024-06-08 16:02:04       58 阅读
  3. Android 开机流程

    2024-06-08 16:02:04       35 阅读
  4. Android11 FallbackHome启动和关闭流程分析

    2024-06-08 16:02:04       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-08 16:02:04       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-08 16:02:04       100 阅读
  3. 在Django里面运行非项目文件

    2024-06-08 16:02:04       82 阅读
  4. Python语言-面向对象

    2024-06-08 16:02:04       91 阅读

热门阅读

  1. 什么是旋转多普勒效应?

    2024-06-08 16:02:04       24 阅读
  2. 03-3.2.4 双端队列

    2024-06-08 16:02:04       27 阅读
  3. 富格林:曝光纠正出金亏损陋习

    2024-06-08 16:02:04       31 阅读
  4. es6中箭头的用法

    2024-06-08 16:02:04       28 阅读
  5. linux shell脚本启动springboot服务

    2024-06-08 16:02:04       28 阅读
  6. GeoJson格式简单说明(2024-06-06)

    2024-06-08 16:02:04       30 阅读
  7. python的np.linspace()函数

    2024-06-08 16:02:04       25 阅读
  8. python-web应用程序-Django-From组件

    2024-06-08 16:02:04       32 阅读
  9. export 和 export default 的区别

    2024-06-08 16:02:04       29 阅读
  10. 以“交流“为主题写一篇文章

    2024-06-08 16:02:04       25 阅读
  11. Go 语言中的切片:灵活的数据结构

    2024-06-08 16:02:04       25 阅读