Android 11 R 开机动画流程

1,767 阅读6分钟

1.SurfaceFlinger启动

高版本sf由bp文件启动

framework/native/services/surfaceflinger/Android.bp: init_rc: ["surfaceflinger.rc"],

//frameworks/native/services/surfaceflinger/surfaceflinger.rc
service surfaceflinger /system/bin/surfaceflinger
    class core animation
    user system
    group graphics drmrpc readproc
    capabilities SYS_NICE
    onrestart restart zygote
    task_profiles HighPerformance
    socket pdx/system/vr/display/client     stream 0666 system graphics u:object_r:pdx_display_client_endpoint_socket:s0
    socket pdx/system/vr/display/manager    stream 0666 system graphics u:object_r:pdx_display_manager_endpoint_socket:s0
    socket pdx/system/vr/display/vsync      stream 0666 system graphics u:object_r:pdx_display_vsync_endpoint_socket:s0
  

1.1 初始化sf对象

上边没啥用,知道走到frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp 的main方法就可以了。以下只关注两件事儿就可以了

  • 创建SF对象
  • 调用SF的init() 和run()
int main(int, char**) {
 
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);
    IPCThreadState::self()->disableBackgroundScheduling(true);
    // start the thread pool
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();

    // instantiate surfaceflinger  创建sf对象
    sp<SurfaceFlinger> flinger = surfaceflinger::createSurfaceFlinger();

    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); // 这块看起来是cpu绑核的逻辑,没找到实现

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

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

    startDisplayService(); // dependency on SF getting registered above

    // run surface flinger in this thread
    flinger->run();// 还有这块

    return 0;
}

1.2 StartPropertySetThread 设置service.bootanim.exit 和启动property_set("ctl.start", "bootanim");

接下来进入sf的实现,一坨和我们不太相关的代码。主要关注 mStartPropertySetThread,并调用了start()即可

// frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
void SurfaceFlinger::init() {

 initializeDisplays();

 getFactory().createStartPropertySetThread(presentFenceReliable);

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

接下来是StartPropertySetThread中的threadLoop方法,设置了我们要找的 property_set("service.bootanim.exit", "0") 以及通过ctl.start 启动bootanim

// frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp

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

2.BootAnimation启动

framework/base/cmds/bootanimation/Android.bp: init_rc: ["bootanim.rc"],

// frameworks/base/cmds/bootanimation/bootanim.rc
service bootanim /system/bin/bootanimation
    class core animation
    user graphics  // 用户组 graphics
    group graphics audio
    disabled  //系统启动时,不会自动启动bootanimation
    oneshot  // 一次
    ioprio rt 0
    task_profiles MaxPerformance

用来启动应用程序bootanimation的服务是disable的,即init进程在启动的时候,不会主动将应用程序bootanimation启动起来。

2.1 bootanimation_main.cpp main()方法

我们首先关注main()方法

bootAnimationDisabled()用来检查系统属性“debug.sf.nobootnimaition”的值是否不等于0。

如果不等于0,就会启动一个Binder线程池,并且创建一个BootAnimation对象。这个Binder线程用于同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)
#ifdef BOOTANIMATION_EXT
        sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks(),true);
#else
        sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());
#endif
        waitForSurfaceFlinger(); 这块在等sf服务起来 一般应该用不到

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

        ALOGV("Boot animation set up. Joining pool.");

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

2.2 BootAnimation.h 定义

接着看下BootAnimation的声明,具体定义可以看下注释,threadloop可以和前边联动

// frameworks/base/cmds/bootanimation/BootAnimation.h
class BootAnimation : public Thread, public IBinder::DeathRecipient  
{  
public:  
    BootAnimation();  
    virtual     ~BootAnimation();    
    .......  
private:  
    virtual bool        threadLoop(); // 每个线程类都要实现的,在这里定义thread的执行内容。这个函数如果返回true,且没有调用requestExit(),则该函数会再次执行;如果返回false,则threadloop中的内容仅仅执行一次,线程就会退出。
    virtual status_t    readyToRun();  //Thread执行前的初始化工作
    virtual void        onFirstRef();   //该函数在强引用sp新增引用计数時调用,就是当有sp包装的类初始化的时候调用
    virtual void        binderDied(const wp<IBinder>& who);  //当对象死掉或者其他情况导致该Binder结束时,就会回调binderDied()方法;
   
    status_t initTexture(Texture* texture, AssetManager& asset, const char* name);  
    status_t initTexture(const Animation::Frame& frame);  
    
    bool android();  //系统默认的开机画面
    bool movie();   //显示用户自定义的开机动画
    
     Animation* loadAnimation(const String8&);
	 bool playAnimation(const Animation&);
	 void releaseAnimation(Animation*) const;
 	 bool parseAnimationDesc(Animation&);
	 bool preloadZip(Animation &animation);
	 void findBootAnimationFile();
	 bool findBootAnimationFileInternal(const std::vector<std::string>& files);
	 bool preloadAnimation();
	 void checkExit();
};

onFirstRef这个留意

BootAnimation类间接地继承RefBase类,并重写了RefBase类的onFirstRef,当一个BootAnimation对象第一次被智能指针引用时,这个BootAnimation对象的成员函数onFirstRef就会被调用。

// frameworks/base/cmds/bootanimation/BootAnimation.cpp
mSession = new SurfaceComposerClient();

void BootAnimation::onFirstRef() {
    status_t err = mSession->linkToComposerDeath(this);
    //通过调用linkToComposerDeath来注册SurfaceFlinger服务的死亡接收通知,这样当SurfaceFlinger服务意外死亡时,BootAnimation类就可以得到通知
    ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
}

mSession的类型为SurfaceComposerClient,是用来和SurfaceFlinger执行Binder进程间通信的,它是在BootAnimation类的构造函数中创建的。

BootAnimation类继承了Thread类,当BootAnimation类的成员函数onFirstRef调用了父类Thread的成员函数run之后,系统就会创建一个线程,这个线程在第一次运行之前,会调用BootAnimation类的成员函数readyToRun来执行一些初始化工作,后面再调用BootAnimation类的成员函数threadLoop来显示开机画面

2.3 BootAnimation.cpp threadloop() 播放动画

接下来看下threadloop(),主要判断了zip文件是否存在。不存在就用logo,存在就用bootanimation.zip threadLoop()函数如果返回值为false,则该函数中的内容只会执行一次;如果返回true,则会不停的执行。这里返回false,因此只会执行一次。

//frameworks/base/cmds/bootanimation/BootAnimation.cpp
bool BootAnimation::threadLoop() {
    bool result;
    // We have no bootanimation file, so we use the stock android logo
    // animation.
    if (mZipFileName.isEmpty()) {
        result = android(); // 原生logo
    } else {
        result = movie(); //开机动画
    }
    return result;
}

主要看下movie()

bool BootAnimation::movie() {
    if (mAnimation == nullptr) {
        mAnimation = loadAnimation(mZipFileName);
    }

    playAnimation(*mAnimation);

    releaseAnimation(mAnimation);
    mAnimation = nullptr;

    return false;
}

playAnimation(*mAnimation),这里主要关注checkExit() 在android()默认logo的时候也会有check


bool BootAnimation::playAnimation(const Animation& animation) {
  
                if (!mShuttingDown) {
                    checkExit();
                }
    return true;
}

首先调用property_get获取属性EXIT_PROP_NAME的值,如果为1,则调用requestExit()要求退出当前线程,该函数是异步的

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) {
        ALOGD("%sAnimationShownTiming exit animation time: %" PRId64 "ms",
            mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime());
        requestExit();
        mCallbacks->shutdown();
    }
}

动画执行时通过调用exitPending()检测,该函数判断requestExit()是否被调用过,如果调用过则返回true,否则为false。

当属性"service.bootanim.exit"值被设为"1"时,android()就会调用requestExit(),exitPending()返回值为true。于是循环就会退出,开机动画就会结束。

//system/core/libutils/Thread.cpp
void Thread::requestExit()
{
    Mutex::Autolock _l(mLock);
    //这里将mExitPending 赋值为true
    mExitPending = true;
}

bool Thread::exitPending() const
{
    Mutex::Autolock _l(mLock);
    return mExitPending;
}

3.停止动画 WMS#performEnableScreen

最终service.bootanim.exit = 1是在WMS中设置的。 大概有以下几种情况调用performEnableScreen

1.正常启动

  • ActivityStackSupervisor 的activityIdleInternal()开始
  • checkFinishBootingLocked()
  • ActivityTaskManagerService#postFinishBooting()
  • WMS#enableScreenAfterBoot

2.PKMS启动 “正在优化xxx”这个弹窗的时候

3.factorytest以及AMS中uihandler一些error的情况

4.PhoneWindowManager windowdrawn 和windowstate变化的一些情况。

以上会有一些判断是否走到方法中,具体没有通过trace确认。后边甩张图/

private void performEnableScreen() {
    synchronized (mGlobalLock) {

if (!mBootAnimationStopped) {
    SystemProperties.set("service.bootanim.exit", "1");
    mBootAnimationStopped = true;
}

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

}

通过binder到native层

//frameworks/native/include/gui/ISurfaceComposer.h
     class BnSurfaceComposer: public BnInterface<ISurfaceComposer> {  
    public:  
        enum {  
            // Note: BOOT_FINISHED must remain this value, it is called from  
            // Java by ActivityManagerService.  
            BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,  
            ...  
        };  
      
        virtual status_t onTransact(uint32_t code, const Parcel& data,  
                Parcel* reply, uint32_t flags = 0);  
    }; 
//frameworks/native/libs/gui/ISurfaceComposer.cpp
case BOOT_FINISHED: {
    CHECK_INTERFACE(ISurfaceComposer, data, reply);
    bootFinished();
    return NO_ERROR;

最终来到sf中,停止再次设置,这里没想清楚二次set的作用

//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
  void SurfaceFlinger::bootFinished()  {  

   property_set("service.bootanim.exit""1");  
}

4.总结

开机动画主要是以下三部分

1.surfaceflinger启动,在init方法中,调用StartPropertySetThread#theadloop(),设置两个prop。 property_set("service.bootanim.exit", "0")设置标志位property_set("ctl.start", "bootanim")启动bootanim进程

2.bootanima启动,也是在BootAnimation.cpp threadloop()中,播放动画,并在checkExit()检查对应的prop是否为1。如果是1则退出

3.开机启动当activityIdleInternal()的时候调用到WMS performEnableScreen()设置service.bootanim.exit为1。以及通过binder通知sf在设置一遍。

BootAnimation(1).png

最后如果有人看到的话,还是希望各位多看书,少写文章。我这是最近研究开机时间,碰上了为了以后面试吹牛比。

掘金这个每次发布之前选标签的设计真沙比。


Android开机动画流程—结束阶段