Android开机动画流程—启动阶段

(1)前述

Android系统在启动的过程中,最多可以出现四个画面,每一个画面都用来描述一个不同的启动阶段。

  • Linux uboot显示(静态)
  • Linux 内核的启动画面(静态)
  • init 进程的启动画面(静态)
  • BootAnimation启动动画(动态)

无论是哪一个画面,它们都是在一个称为帧缓冲区(frame buffer,简称fb)的硬件设备上进行渲染的。接下来,我们就单独分析BootAnimation是如何开始显示的。

(2)BootAnimation启动阶段

(A)bootanimation启动概述

开机动画是由应用程序bootanimation来负责显示的,先看一下其rc文件。

//frameworks/base/cmds/bootanimation/bootanim.rc

service bootanim /system/bin/bootanimation
     class core animation
 	 user graphics
     group graphics audio
     disabled  //系统启动时,不会自动启动bootanimation
     oneshot  //只启动一次
     ioprio rt 0
     task_profiles MaxPerformance

应用程序bootanimation的用户和用户组名称分别被设置为graphics。注意, 用来启动应用程序bootanimation的服务是disable的,即init进程在启动的时候,不会主动将应用程序bootanimation启动起来。

SurfaceFlinger 服务启动的过程中会修改系统属性"ctl.start"的值以通知init进程启动bootanim来显示开机动画。当系统关键服务启动完毕后会由AMS通知SurfaceFlinger修改系统属性"ctl.stop"来通知init进程停止执行bootanim关闭动画。

(B)SurfaceFlinger如何启动bootAnimation

首先来看一下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

SurfaceFlinger服务的入口在下面的main_surfaceflinger.cpp中,我们查看它的main函数。

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

int main(int, char**) {
    // 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();

    // initialize before clients can connect
    flinger->init(); //我们主要看这里
    
    // run in this thread
    flinger->run();

    return 0;
}

主要工作就是新建一个SurfaceFlinger对象,然后调用其中的init函数,最后调用run函数。

//frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

sp<StartPropertySetThread> mStartPropertySetThread;

void SurfaceFlinger::init() {
      ALOGI(  "SurfaceFlinger's main thread ready to run. "
              "Initializing graphics H/W...");
      Mutex::Autolock _l(mStateLock);

//...
      if (mStartPropertySetThread->Start() != NO_ERROR) {
          ALOGE("Run StartPropertySetThread failed!");
      }
  
      ALOGV("Done initializing");
}
//frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp

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

这里将系统属性"service.bootanim.exit"设置为"0",并将"ctl.start"设置为"bootanim"。
当系统属性发生改变时,init进程就会接收到一个系统属性变化通知,这个通知最终是由在init进程中的函数handle_property_set_fd来处理的,具体中间流程是如何运行的,可以参考另外一篇文章Android系统设置属性详解

(C)bootAnimation启动

从前面的内容可以知道,名称等于"bootanim"的服务所对应的应用程序为/system/bin/bootanimation,应用程序入口函数的实现在frameworks/base/cmds/bootanimation/Bootanimation_main.cpp中。

//frameworks/base/cmds/bootanimation/bootanimation_main.cpp

int main()
 {
      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.");

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

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.nobootnimaition”的值是否不等于0。如果不等于的话,那么接下来就会启动一个Binder线程池,并且创建一个BootAnimation对象。这个Binder线程用于同SurfaceFlinger服务通信。

接着我们看看BootAnimation类的声明:

//frameworks/base/cmds/bootanimation/BootAnimation.h

class BootAnimation : public Thread, public IBinder::DeathRecipient  
{  
public:  
    BootAnimation();  
    virtual     ~BootAnimation();    
    .......  
private:  
    virtual bool        threadLoop();  
    virtual status_t    readyToRun();  
    virtual void        onFirstRef();  
    virtual void        binderDied(const wp<IBinder>& who);  
   
    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();
};

BootAnimation类继承了Thread类和IBinder::DeathRecipient类,其中几个重要的函数说明如下:

  • onFirstRef()—— 属于其父类RefBase,该函数在强引用sp新增引用计数時调用,就是当有sp包装的类初始化的时候调用;
  • binderDied() ——当对象死掉或者其他情况导致该Binder结束时,就会回调binderDied()方法;
  • readyToRun() ——Thread执行前的初始化工作;
  • threadLoop() ——每个线程类都要实现的,在这里定义thread的执行内容。这个函数如果返回true,且没有调用requestExit(),则该函数会再次执行;如果返回false,则threadloop中的内容仅仅执行一次,线程就会退出。

其他函数简述如下:

  • android()——显示系统默认的开机画面;
  • movie()——显示用户自定义的开机动画;
  • loadAnimation(const String8&)——加载动画;
  • playAnimation(const Animation&)——播放动画;
  • checkExit()——检查是否退出动画;

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

mSession = new SurfaceComposerClient();

void BootAnimation::onFirstRef() {
    status_t err = mSession->linkToComposerDeath(this);
    ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
}

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

由于BootAnimation类引用了SurfaceFlinger服务,当SurfaceFlinger服务意外死亡时,BootAnimation类就需要得到通知,这是通过调用成员变量mSession的成员函数linkToComposerDeath来注册SurfaceFlinger服务的死亡接收通知来实现的。

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

上一篇:深入Android系统(十二)Android图形显示系统-2-SurfaceFlinger与图像输出


下一篇:Android 绘图机制