Android开机动画启动到结束流程

总体流程

在这里插入图片描述

涉及代码路径

bootanimation frameworks/base/cmds/bootanimation/
surfaceflinger frameworks/native/services/surfaceflinger/
init system/core/init/

流程详细分析

注:新的框架代码中的有些方法名可能统一改为了驼峰法,但是大体流程相同

1.init进程启动

内核起来后会启动第一个进程,即init进程。
init进程会根据init.rc配置启动surfaceflinger进程
surfaceflinger代码路径中有surfaceflinger.rc
在这里插入图片描述

surfaceflinger进程便启动了,跟着就会跑进程的main()函数。

顺便说一句bootanimation里面也有一个bootanim.rc文件,但是里面有个disabled,因此init.rc执行时,不会启动bootanimation进程,什么时候启动请看后文
在这里插入图片描述

2.SurfaceFlinger进程启动

frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

int main(int, char**) {
    startHidlServices();

    signal(SIGPIPE, SIG_IGN);
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);

    // start the thread pool
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();

    // instantiate surfaceflinger
    sp<SurfaceFlinger> flinger = new SurfaceFlinger();

    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);

    set_sched_policy(0, SP_FOREGROUND);

    // Put most SurfaceFlinger threads in the system-background cpuset
    // Keeps us from unnecessarily using big cores
    // Do this after the binder thread pool init
    if (cpusets_enabled()) set_cpuset_policy(0, SP_SYSTEM);

    // initialize before clients can connect
    flinger->init();

    // publish surface flinger
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);

    // publish GpuService
    sp<GpuService> gpuservice = new GpuService();
    sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);

    struct sched_param param = {0};
    param.sched_priority = 2;
    if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
        ALOGE("Couldn't set SCHED_FIFO");
    }

    // run surface flinger in this thread
    flinger->run();

    return 0;
}

这段代码的核心部分,首先new一个SurfaceFlinger实例 sp<SurfaceFlinger> flinger = new SurfaceFlinger();(这个SurfaceFlinger是#include "SurfaceFlinger.h",正真的实现是在SurfaceFlinger.cpp中),初始化flinger->init();(SurfaceFlinger.cpp中的init方法),然后注册到service manager里sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);,最后在这个线程中运行SurfaceFlingerflinger->run();

2.SurfaceFlinger初始化和启动StartPropertySetThread线程

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

// Do not call property_set on main thread which will be blocked by init
// Use StartPropertySetThread instead.
void SurfaceFlinger::init() {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");

    ALOGI("Phase offest NS: %" PRId64 "", vsyncPhaseOffsetNs);
    
   ......
   
    // Inform native graphics APIs whether the present timestamp is supported:
    if (getHwComposer().hasCapability(
            HWC2::Capability::PresentFenceIsNotReliable)) {
        mStartPropertySetThread = new StartPropertySetThread(false);
    } else {
        mStartPropertySetThread = new StartPropertySetThread(true);
    }

    if (mStartPropertySetThread->Start() != NO_ERROR) {
        ALOGE("Run StartPropertySetThread failed!");
    }

    ALOGV("Done initializing");
}

初始化graphics之后,创建StartPropertySetThread对象,mStartPropertySetThread->Start()启动设置bootanimation的属性线程,下面我们继续看看StartPropertySetThread做了什么

3.StartPropertySetThread线程执行和设置动画属性

frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp

#include <cutils/properties.h>
#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");
    // Start BootAnimation if not started
    property_set("ctl.start", "bootanim");
    // Exit immediately
    return false;
}

} // namespace android

之前我们提到过看开机动画的bootanim.rc文件可以看到,其默认是disable的,也就是说,开机动画进程,默认是不会自启动的,需要有其他地方(即StartPropertySetThread)来触发而通过此处的ctl.start属性,能够触发bootanim进程,从而开始显示开机动画
从代码中可以看出StartPropertySetThread主要设置了开机动画相关的关键属性。property_set("service.bootanim.exit", "0")设置service.bootanim.exit 为0,该属性值决定开机动画是否退出,然后通过property_set("ctl.start", "bootanim")启动bootanim service。

4.通知init进程启动bootanim服务

为什么设置一个属性bootanim进程就会启动了呢?
当系统属性发生改变时,init进程就会接收到一个系统属性变化通知,这个通知最终是由在init进程中的函数handle_property_set_fd来处理。下面我们来看看init的main方法

init的main()

system/core/init/init.cpp

int main(int argc, char** argv) {
    ......

    property_init();

    ......

    signal_handler_init();

    property_load_boot_defaults();
    export_oem_lock_status();
    start_property_service();
    set_usb_controller();

   ......

    return 0;
}

这个方法中property_init()对属性服务进行初始化,然后start_property_service()启动属性的service。

start_property_service()

system/core/init/property_service.cpp

void start_property_service() {
    property_set("ro.property_service.version", "2");

    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                   false, 0666, 0, 0, nullptr, sehandle);
    if (property_set_fd == -1) {
        PLOG(ERROR) << "start_property_service socket creation failed";
        exit(1);
    }

    listen(property_set_fd, 8);

    register_epoll_handler(property_set_fd, handle_property_set_fd);
}

在init进程中创建了一个CreateSocket用于跨进程通信,并且使用listen(property_set_fd, 8)监听,
register_epoll_handler(property_set_fd, handle_property_set_fd)使用epoll机制来轮询事件,其中一个事件是系统属性值被修改。得到该事件后,会执行handle_property_set_fd()。
简而言之,以我们的开机动画为例,假如有用进程对之前提到的设置动画的属性感兴趣就接受并处理。

handle_property_set_fd()

handle_property_set_fd方法仍在property_service.cpp中

static void handle_property_set_fd() {
    ......

    switch (cmd) {
    case PROP_MSG_SETPROP: {
        char prop_name[PROP_NAME_MAX];
        char prop_value[PROP_VALUE_MAX];

        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
            !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
          return;
        }

        prop_name[PROP_NAME_MAX-1] = 0;
        prop_value[PROP_VALUE_MAX-1] = 0;

        handle_property_set(socket, prop_value, prop_value, true);
        break;
      }

    case PROP_MSG_SETPROP2: {
        std::string name;
        std::string value;
        if (!socket.RecvString(&name, &timeout_ms) ||
            !socket.RecvString(&value, &timeout_ms)) {
          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
          socket.SendUint32(PROP_ERROR_READ_DATA);
          return;
        }

        handle_property_set(socket, name, value, false);
        break;
      }

    default:
        LOG(ERROR) << "sys_prop: invalid command " << cmd;
        socket.SendUint32(PROP_ERROR_INVALID_CMD);
        break;
    }
}

这些case都执行了handle_property_set方法,继续跟踪该方法。

handle_property_set()

该方法同样在property_service.cpp中

static void handle_property_set(SocketConnection& socket,
                                const std::string& name,
                                const std::string& value,
                                bool legacy_protocol) {
  ......
  if (android::base::StartsWith(name, "ctl.")) {
    if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
      handle_control_message(name.c_str() + 4, value.c_str());
      if (!legacy_protocol) {
        socket.SendUint32(PROP_SUCCESS);
      }
    } else {
      LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
                 << " service ctl [" << value << "]"
                 << " uid:" << cr.uid
                 << " gid:" << cr.gid
                 << " pid:" << cr.pid;
      if (!legacy_protocol) {
        socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
      }
    }
  } else {
    ......
  }

  freecon(source_ctx);
}

android::base::StartsWith(name, "ctl.")从这里我们可以看出是在匹配条件,前面动画设置的属性是property_set("ctl.start", "bootanim"),正好匹配。 该函数会进一步执行handle_control_message(name.c_str() + 4, value.c_str()),启动开机动画会传入的参数name.c_str() + 4=start,value.c_str()=bootanim。
继续看这个方法做了什么。

handle_control_message()

/system/core/init/init.cpp

void handle_control_message(const std::string& msg, const std::string& name) {
    Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
    if (svc == nullptr) {
        LOG(ERROR) << "no such service '" << name << "'";
        return;
    }

    if (msg == "start") {
        svc->Start();
    } else if (msg == "stop") {
        svc->Stop();
    } else if (msg == "restart") {
        svc->Restart();
    } else {
        LOG(ERROR) << "unknown control msg '" << msg << "'";
    }
}

前面调用handle_control_message(name.c_str() + 4, value.c_str()),传递实参是start,bootanim,即对应这个方法中的形参msg,name
ServiceManager::GetInstance().FindServiceByName(name)找到对应的Service* 对象,从service_list中查询要启动的服务是否有存在,若存在,返回服务的相关信息。因为init.rc中有bootanimation的定义,因此在init进程执行parse_config()时,会将该服务添加到service_list中。这里的name是bootanim如果找到了该服务,就调用start启动服务,首先会执行bootanimation_main.cpp中的main方法。

5.bootanimation的实现

执行bootanimation的main方法

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

        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;
}

bootAnimationDisabled()用于判断开机动画是否被禁止,若未被禁止即noBootAnimation值为false(一般都为false,后面介绍bootAnimationDisabled方法),则走到条件中。
这个里面主要进行启动线程池,用于初始化binder线程,用于surfaceflinger通信。等待SurfaceFlinger起来后,创建BootAnimation对象

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");
    return atoi(value) > 0;
}

属性值debug.sf.nobootanimationro.boot.quiescent决定开机动画是否禁止,从代码中可以看到,两个属性的值默认为0,atoi(value) > 0即0>0为return false,因此前面main方法中变量noBootAnimation的值为false

创建BootAnimation对象

/frameworks/base/cmds/bootanimation/BootAnimation.cpp

BootAnimation::BootAnimation(sp<Callbacks> callbacks)
        : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
        mTimeFormat12Hour(false), mTimeCheckThread(NULL), mCallbacks(callbacks) {
    mSession = new SurfaceComposerClient(); 

    std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
    if (powerCtl.empty()) {
        mShuttingDown = false;
    } else {
        mShuttingDown = true;
    }
}

在构造方法中,创建SurfaceComposerClient用于与SurfaceFlinger跨进程通信。获取了一个用于判断开关机状态的属性sys.powerctl

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

sp<BootAnimation> boot = new BootAnimation(new AudioAnimationCallbacks());前面创建BootAnimation对象时是sp(智能指针,强指针)方式创建,onFirstRef()属于其父类RefBase,该函数在强引用sp新增引用计数时,第一次强引用会自动调用此函数。因此创建BootAnimation对象时除了会调用自身构造方法以外,还会调用onFirstRef()。
这里执行一个run方法,是调用了Thread的run方法,因为BootAnimation.h文件中发现BootAnimation继承了Thread

/frameworks/base/cmds/bootanimation/BootAnimation.h
class BootAnimation : public Thread, public IBinder::DeathRecipient {...}

system/core/libutils/Threads.cpp

status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
    ...
    
    if (mCanCallJava) {
        res = createThreadEtc(_threadLoop,//创建线程
                this, name, priority, stack, &mThread);
    } else {
        res = androidCreateRawThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    }
    ....
}

在run方法中创建了_threadLoop线程

int Thread::_threadLoop(void* user)
{
....
    do {
        bool result;
        if (first) {
            first = false;
            self->mStatus = self->readyToRun();//被bootanimation重写
            result = (self->mStatus == NO_ERROR);
 
            if (result && !self->exitPending()) {
                ...
                result = self->threadLoop();//被bootanimation重写
            }
        } else {
            result = self->threadLoop();
        }
 
        ...
    
    return 0;
}

从代码流程上可以看出先执行readyToRun(),再执行threadLoop(),其中这两个方法均被bootanimation重写

readyToRun()函数实现

/frameworks/base/cmds/bootanimation/BootAnimation.cpp

status_t BootAnimation::readyToRun() {
    mAssets.addDefaultAssets();

    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
            ISurfaceComposer::eDisplayIdMain));
    DisplayInfo dinfo;
    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
    if (status)
        return -1;

    // create the native surface
    sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
            dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);

    SurfaceComposerClient::openGlobalTransaction();
    control->setLayer(0x40000000);
    SurfaceComposerClient::closeGlobalTransaction();

    sp<Surface> s = control->getSurface();
	//上面的代码简而言之,就是获取了一个画布,用于在屏幕上绘制内容
	
    // initialize opengl and egl
    const EGLint attribs[] = {
            EGL_RED_SIZE,   8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE,  8,
            EGL_DEPTH_SIZE, 0,
            EGL_NONE
    };
    EGLint w, h;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(display, 0, 0);
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
    surface = eglCreateWindowSurface(display, config, s.get(), NULL);
    context = eglCreateContext(display, config, NULL, NULL);
    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;
    mWidth = w;
    mHeight = h;
    mFlingerSurfaceControl = control;
    mFlingerSurface = s;
	//以上内容均为opengl初始化

    // If the device has encryption turned on or is in process
    // of being encrypted we show the encrypted boot animation.
    char decrypt[PROPERTY_VALUE_MAX];
    property_get("vold.decrypt", decrypt, "");

    bool encryptedAnimation = atoi(decrypt) != 0 ||
        !strcmp("trigger_restart_min_framework", decrypt);

    if (!mShuttingDown && encryptedAnimation &&
        (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
        mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
        return NO_ERROR;
    }
    static const char* bootFiles[] = {OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE};
    static const char* shutdownFiles[] =
        {OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE};
	//通过开关机状态判断使用哪个动画文件
	//mShuttingDown变量,见Bootanimation构造方法
	//bootFiles开机文件,shutdownFiles关机文件
    for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) {
        if (access(f, R_OK) == 0) { //判断文件是否存在
            mZipFileName = f;	//存在则赋值,使用此路径动画
            return NO_ERROR;
        }
    }
    return NO_ERROR;
}
//开机动画路径
static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.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 SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";

通过修改路径中的文件来自定义开机动画

threadLoop()函数实现

/frameworks/base/cmds/bootanimation/BootAnimation.cpp

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;
}

如果mZipFileName 为空,则执行android(),即显示默认的Android动画;不为空,则执行movie(),即显示自定义动画。

android()
bool BootAnimation::android()
{
    ALOGD("%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");

    mCallbacks->init({});

    // clear screen
   ......
    do {
        ......

        checkExit();
    } while (!exitPending());

    glDeleteTextures(1, &mAndroid[0].name);
    glDeleteTextures(1, &mAndroid[1].name);
    return false;
}
movie()
bool BootAnimation::movie()
{
    Animation* animation = loadAnimation(mZipFileName);
	......

    // Check if npot textures are supported
    ......

    // Blend required to draw time on top of animation frames.
   ......

    playAnimation(*animation);

	......

    releaseAnimation(animation);

	......
}

bool BootAnimation::playAnimation(const Animation& animation)
{
    const size_t pcount = animation.parts.size();
    nsecs_t frameDuration = s2ns(1) / animation.fps;
    const int animationX = (mWidth - animation.width) / 2;
    const int animationY = (mHeight - animation.height) / 2;

    ALOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
            elapsedRealtime());
    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 != NULL) {
            playAnimation(*part.animation);
            if (exitPending())
                break;
            continue; //to next part
        }

        for (int r=0 ; !part.count || r<part.count ; r++) {
            // Exit any non playuntil complete parts immediately
            ......

            for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
                ......

                checkExit();
            }

            usleep(part.pause * ns2us(frameDuration));

            // For infinite parts, we've now played them at least once, so perhaps exit
            if(exitPending() && !part.count)
                break;
        }

    }

    // Free textures created for looping parts now that the animation is done.
    ......

    return true;
}

movie()调用了playAnimation方法,该方法调用了checkExit方法。
无论是android()还是movie(),都会调用checkExit(),这里我们主要关注一下checkExit(),该方法用于检测是否退出动画

检测是否退出动画
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();
    }
}

获取EXIT_PROP_NAME属性值,根据属性值判断当前是否退出动画。EXIT_PROP_NAME对应的属性就是service.bootanim.exit

static const char EXIT_PROP_NAME[] = "service.bootanim.exit";

前面我们讲StartPropertySetThread::threadLoop()方法时,里面曾有property_set("service.bootanim.exit", "0"),即设置属性service.bootanim.exit值为0。从判断条件if (exitnow)可以看出,属性service.bootanim.exit值为0时,不退出,即非0时退出。
关于这个requestExit() 和exitPending()可以参考https://blog.csdn.net/llping2011/article/details/9706599 大致意思就是mExitPendding = true 这个变量值由Thread类的requestExit函数设置,即调用requestExit() ,则exitPending()就会返回true.

通过查找代码,我们发现在WindowManagerService.java和SurfaceFlinger.cpp中有设置service.bootanim.exit值为1,退出动画。
在这里插入图片描述
注:surfaceflinger.cpp应用是android原生的;SurfaceFlinger_hwc1.cpp这个应该是不同平台自己定义的。有了解这块的朋友可以在评论区补充一下。

6.开机动画结束流程

优先看下java代码
/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

   private void performEnableScreen() {
        synchronized(mWindowMap) {
            if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
                    + " mShowingBootMessages=" + mShowingBootMessages
                    + " mSystemBooted=" + mSystemBooted
                    + " mOnlyCore=" + mOnlyCore,
                    new RuntimeException("here").fillInStackTrace());
            ......

            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;
            }

            ......
            
            try {
                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
                if (surfaceFlinger != null) {
                    Slog.i(TAG_WM, "******* 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) {
                Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!");
            }
        }

        ......
    }

这里可以直接打印堆栈进行跟踪performEnableScreen(),找到其调用源头。
这里先简述一下流程,有时间在补充
首先进入idle,然后跨进程调用到AMS中,执行了postFinishBooting,在调用到WMS中的performEnableScreen,此时会判断条件if (!mBootAnimationStopped),然后执行SystemProperties.set("service.bootanim.exit", "1");,即设置动画退出。
在代码中还有一句IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger")这里是跨进程通信,

surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
                            data, null, 0);

跨进程调用到SurfaceFlinger,通过FIRST_CALL_TRANSACTION,找到对应的是SurfaceFlinger.cpp的status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)这个方法。
最终会在SurfaceFlinger执行prop的设置,也就是我们之前在SurfaceFlinger.cpp文件中看到的property_set("service.bootanim.exit", "1")
详细流程可以参考:
https://blog.csdn.net/ahaochina/article/details/70739825
https://blog.csdn.net/xlnaan/article/details/80904309

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值