Android系统开机动画的一辈子

前言

在上篇文章【Android从上电到加载launcher,都发生了啥】中,简单介绍了Android系统从上电到加载launcher的流程,但比较粗略,特别是init以后,开机动画如何启动,又如何结束的,丝毫没有涉及,这篇文章就来好好说说。java

概述

先放上一张流程图,须要说明的是,下图中init所作的事不止下图所展现的,这里只是画出跟开机动画相关的流程。android

系统上电后,经过内置的rom_code将uboot映像从flash中加载到内存中运行,以后跳转到uboot执行,作一些硬件外设参数的初始化工做,而后从flash中加载kernel到内存中运行并跳转到kernel执行。微信

init进程是kernel的第一个进程,也是Android系统的第一个进程。而跟开机动画有关的,主要是init中作的两件事,一件事是启动surfaceflinger进程,开机动画的启动就是在这里触发;另一件事是启动zygote进程,zygote进程起来后就fork出了system_server,system_server主要是启动系统服务,如AMS,WMS,PMS等。等待一些关键服务ready后,就开始加载launcher,launcher加载好就触发结束开机动画的操做,从而进入到launcher界面。 框架

image

bootanimation的开启

开机动画是在surfaceflinger中触发,而surfaceflinger进程是在init.rc中启动的,以下:async

service surfaceflinger /system/bin/surfaceflinger
复制代码

这里须要说明的是,在高版本的Android上,如AndroidP,surfaceflinger进程并非直接在init.rc文件中启动的,而是经过Android.bp文件去包含启动surfaceflinger.rc文件,而后在该文件中再去启动surfaceflinger:函数

AOSP/frameworks/native/services/surfaceflinger/Android.bp
...
init_rc: ["surfaceflinger.rc"],
...
AOSP/frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
...
复制代码

surfaceflinger启动了,就会跑到它的main函数:oop

AOSP/frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

int main(int, char**) {
    ...
    // instantiate surfaceflinger
    sp<SurfaceFlinger> flinger = new SurfaceFlinger(); 
    ...
    flinger->init();
    ...
    flinger->run();
}
复制代码

这里建立一个SurfaceFlinger实例,而后执行了init(),看看它的实现:post

AOSP/frameworks/native/services/surfaceflinger/surfaceflinger.cpp
void SurfaceFlinger::init() {
    ...
    mStartPropertySetThread = new StartPropertySetThread();
    mStartPropertySetThread->Start();
    ...
}
复制代码

surfaceflinger完成初始化后,会直接实例化一个StartPropertySetThread,而后启动,咱们来看下:动画

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");
// Start BootAnimation if not started
property_set("ctl.start", "bootanim");
// Exit immediately
#ifdef MTK_BOOT_PROF
    SurfaceFlinger::bootProf(1);
#endif
    return false;
}
复制代码

这里设置属性【service.bootanim.exit】并采用【ctl.start】的方式启动开机动画:this

service bootanim /system/bin/bootanimation
复制代码

在这以后,开机动画就会启动,由bootanimation进程实现具体动画播放。

bootanimation的实现流程

先看下bootanimation进程的入口:

AOSP/frameworks/base/cmds/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();

        waitForSurfaceFlinger();

        // create the boot animation object
        sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks());
        ALOGV("Boot animation set up. Joining pool.");

        IPCThreadState::self()->joinThreadPool();
    }
    ALOGV("Boot animation exit");
    return 0;
}
复制代码

new了一个BootAnimation实例,而后建立了一个binder线程池,用于显示动画时,与surfaceflinger进程通讯用。接下来看看BootAnimation的实现:

AOSP/frameworks/base/cmds/bootanimation.cpp
BootAnimation::BootAnimation(sp<Callbacks> callbacks)
        : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
        mTimeFormat12Hour(false), mTimeCheckThread(NULL), mCallbacks(callbacks) {
    mSession = new SurfaceComposerClient();
    ...
}
复制代码

这里建立了SurfaceComposerClient,用于与surfaceflinger通信。接下来就到了onFirstRef:

void BootAnimation::onFirstRef() {
    status_t err = mSession->linkToComposerDeath(this);
    ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
    if (err == NO_ERROR) {
        run("BootAnimation", PRIORITY_DISPLAY);
    }
}
复制代码

这里先注册surfaceflinger的死亡消息通知书【linkToComposerDeath】,只要surfaceflinger挂掉了,bootanimation进程就会收到通知,从而执行以下代码:

void BootAnimation::binderDied(const wp<IBinder>&)
{
    // woah, surfaceflinger died!
    ALOGD("SurfaceFlinger died, exiting...");

    // calling requestExit() is not enough here because the Surface code
    // might be blocked on a condition variable that will never be updated.
    kill( getpid(), SIGKILL );
    requestExit();
}
复制代码

直接退出,等待surfaceflinger的下一次重启,若是还有来生的话。

onFirstRef在建立了死亡通知书后,还作了一件事,那就是run bootanimation,个中细节不在这里列出,bootanimation重写了readyToRun和threadLoop,咱们直接看threadLoop:

bool BootAnimation::threadLoop()
{
    bool r;
    // We have no bootanimation file, so we use the stock android logo
    // animation.
    if (mZipFileName.isEmpty()) {
        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);
    eglReleaseThread();
    IPCThreadState::self()->stopProcess();
    return r;
}
复制代码

这里会根据有无定制的开机动画包,若是没有,则默认播放Android的那个经典动画,若是有,则进入movie播放开机动画:

bool BootAnimation::movie()
{
    ...
    playAnimation(*animation);
    ...
}

bool BootAnimation::playAnimation(const Animation& animation)
{
    ...
    //代码太长,就不贴出了,主要就是作动画播放的相关代码
    ...
    checkExit();
    ...
}
复制代码

开机动画开始播放了,那什么时候才结束播放呢?答案在checkExit方法中:

static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
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();
        mCallbacks->shutdown();
    }
}
复制代码

这里会一直检测【service.bootanim.exit】的值,当属性值为1的时候,则开机动画会requestExit,从而结束开机动画。那是谁给【service.bootanim.exit】的属性值设置为1呢?

bootanimation的结束

init启动zygote进程以后,由zygote孵化出了system_server,而后system_server启动了各类各类的系统所需的服务,其中就有AMS,AMS启动并ready后,会执行startHomeActivityLocked:

public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
    ...
    startHomeActivityLocked(currentUserId, "systemReady");
    ...
}

boolean startHomeActivityLocked(int userId, String reason) {
    ...
    Intent intent = getHomeIntent();
    ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    final String myReason = reason + ":" + userId + ":" + resolvedUserId;
    mActivityStartController.startHomeActivity(intent, aInfo, myReason);
    ...
}
复制代码

launcher在这里开始加载启动,在launcher的主线程处于空闲时,就会向ActivityManagerService发送一个activityIdle的消息:

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
    ...
    ActivityRecord r =
                    mStackSupervisor.activityIdleInternalLocked(token, false /* fromTimeout */,
                            false /* processPausingActivities */, config);

    ...
}
复制代码

这里经过activityIdleInternalLocked获取到ActivityRecord实例,咱们看看具体实现:

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
        boolean processPausingActivities, Configuration config) {
        
    ....
    //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
    if (isFocusedStack(r.getStack()) || fromTimeout) {
        booting = checkFinishBootingLocked();
    }
    ....
}
复制代码

这里会检测开机是否结束:

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
private boolean checkFinishBootingLocked() {
    final boolean booting = mService.mBooting;
    boolean enableScreen = false;
    mService.mBooting = false;
    if (!mService.mBooted) {
        mService.mBooted = true;
        enableScreen = true;
 }
    if (booting || enableScreen) {
        mService.postFinishBooting(booting, enableScreen);
    }
    return booting;
}
复制代码

这里会直接进入到postFinishBooting方法中执行:

//AMS
void postFinishBooting(boolean finishBooting, boolean enableScreen) {
    mHandler.sendMessage(mHandler.obtainMessage(FINISH_BOOTING_MSG,
            finishBooting ? 1 : 0, enableScreen ? 1 : 0));
}
复制代码

这里直接发一条消息【FINISH_BOOTING_MSG】,咱们看看具体handler的处理:

case FINISH_BOOTING_MSG: {
    if (msg.arg1 != 0) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
        finishBooting();
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
    if (msg.arg2 != 0) {
        enableScreenAfterBoot();
    }
    break;
复制代码

最终执行到了enableScreenAfterBoot方法:

void enableScreenAfterBoot() {
    ...
    mWindowManager.enableScreenAfterBoot();
    ...
}
复制代码

这里调用了WMS的方法【enableScreenAfterBoot】,咱们跳入看看:

public void enableScreenAfterBoot() {

    ...
    performEnableScreen();
    ...
}

private void performEnableScreen() {
    ...
    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;
    }
    
    ...
}
复制代码

到了这里,最终经过设置【service.bootanim.exit】的值,stop掉了开机动画,接着来的就是发出了开机广播。

结语

本篇文章简单介绍了开机动画从开始到结束的流程,涉及到的surfaceflinger进程,这个是开机动画可以显示的基础,若是它挂掉,开机动画也活不了。还有AMS等服务,在launcher加载完后,就设置属性【service.bootanim.exit】,结束开机动画,从而进入到launcher的界面。

互动

若是文章存在错误描述,可直接留言,一块儿探讨!

可能感兴趣的文章

Android从上电到加载Launcher,发生了啥

Android studio使用系统源码的AIDL接口

Android系统框架

最后

我在微信公众号也有写文章,更新比较及时,有兴趣者能够扫描以下二维码,或者微信搜索【Android系统实战开发】,关注有惊喜哦!

相关文章
相关标签/搜索