android boot流程 android bootanimation_android


  • 题序

     生命的开始意味着新奇,而生命的结束则多少会带来感伤与怀念,亲人的离去则是更多的痛彻心扉,以及无尽的怀念。愿逝者长眠,生者安好。

     生命有很多的长度,有些人来了,从不离开,而有些人来了,走了,再也不回头,不留下一丝的痕迹。bootanimation即是如此。


Bootanimation的启动

     Android kk版本中,在编译frameworke/base/cmds/bootanimation之后,会在out/target/product/device/system/bin目录下面生成一个名为bootanimation的bin档。

     而在对应的init.rc中会通过如下的service来启动boot animation。

     service bootanim /system/bin/bootanimation
          class main
          user graphics
          group graphics
          disabled
          oneshot

     其中:

class <name> # 设置名称为name的类别,感觉有点像开机启动service的优先级,默认的class名称为default

   user <effectuserid> # 设置服务进程的effective user ID

group <groupname> [ <groupname> ]* # 设置服务进程的effective group ID(第一个参数)和supplementary group IDs(第二个到最后)

disabled # 设置后,不能自动地通过class名称启动,必须显式地通过service名称启动,或是 表示init进程创建只是创建它,但不立刻执行。

     oneshot# 选项表示该服务只启动一次,而如果没有oneshot选项,这个可执行程序会一直存在---如果可执行程序被杀死,则会重新启动。

    其实在这个时候,因为设置了bootanim的属性为disabled的,这就意味着在init.c中,只是创建了bootanim这个service,但是其实并没有去启动他。那么bootanim到底在什么时候启动呢。

Android系统在init.rc中定义了很多Service,具体定义格式可以参考《Android Platform Developer’s Guide》中的“Android Init Language”。Init.rc中定义的Service将会被Init进程创建,其中已经定义的服务就包含bootanimation。  每一项服务必须在/init.rc中定义.Android系统启动时,init守护进程将解析init.rc和启动属性服务,属性“ ctl.start ”和“ctl.stop ”是用来启动和停止服务的。一旦收到设置“ ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ init.svc.<服务名>“属性中 。

     也就是说启动bootanim必须显式调用ctrl.start,bootanim才能够开始启动,这就是disabled这个属性的神奇之所在。

     在surfaceFlinger.cpp中,surfaceFlinger init()的时候,会通过调用startBootAnim()来启动bootanima service。

#startBootAnim() @ surfaceFlinger.cpp
 void SurfaceFlinger::startBootAnim(){
      property_set("service.bootanim.exit","0");
     property_set("ctl.start","bootanim");
 }

     还记不记得在init.c的main()函数中,在完全所有的初始化,如创建文件系统,解析init.rc,初始化property workspace等之后,进入了一个死循环。这个循环其实是在等待事件,如property setting,signal 及keychord等。

#main() @ init.c
void main()
{
     .....
     for(;;){
          .....
          for(i = 0; i < fd_count; i++)
          {     
               if(ufds[i].revents == POLLIN)
               {
                    if(ufds[i].fd == get_property_set_fd())
                         handle_property_set_fd();
                    else if( ufds[i].fd == get_keychord_fd())
                         handle_keychord();
                    else if ( ufds[i].fd == get_signal_fd())
                    handle_signale();
               }
          }
     }
     return 0;
}

     ok,到这儿之后,咱们再回到bootanim来。其实对于bootanim的最先入口,就是bootanimation_main().cpp中的main()函数。

#main() @ bootanimation_main.cpp

1. int main(int argc, char** argv)  
2. {  
3. #if defined(HAVE_PTHREADS)  
4.     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);  
5. #endif  
6.     char value[PROPERTY_VALUE_MAX];  
7.     property_get("debug.sf.nobootanimation", value, "0");  
8.     int noBootAnimation = atoi(value);  
9.     LOGI_IF(noBootAnimation,  "boot animation disabled");  
10.     if (!noBootAnimation) {  
11.         sp<ProcessState> proc(ProcessState::self());  
12.         ProcessState::self()->startThreadPool();  
13.         sp<BootAnimation> boot = new BootAnimation();  
14.   
15.         IPCThreadState::self()->joinThreadPool();  
16.   
17.     }  
18.     return 0;  
19. }

     bootanimation.cpp继承于Thread类,thread的启动及执行过程按下不表。

     当然,还有一种情况也会导致bootnimation启动,即当surfaceFlinger死掉的时候:

# binderDied() @ SurfaceFlinger.cpp
void SurfaceFlinger::binderDied(const wp<IBinder>& who)
{
     initializeDisplay();
     startBootAnim();
}

     自此,bootanimation的启动过程就厘清咯。我们在下一节中看看是怎么退出的。

  •      Bootanimtion的退出

     通读source code可以知道,不管是movie()模式还是android()模式,在每一次循环之后,都会调用一个api函数checkExit(),用来检测是否需要退出bootanimation

# checkExit() @ bootanimation.cpp
#define  EXIT_PROP_NAME "service.bootanim.exit"
void BootAnimation::checkExit() {
     char value[PROPERTY_VALUE_MAX];
property_get(EXIT_PROP_NAME, value, "0");//EXIT_PROP_NAME为字符串 service.bootanim.exit

int exitnow = atoi(value);

if (exitnow) {

     requestExit();

     }
}

     在android的thread类提供的方法中,有一个曰为requestexit()的api接口,其介绍如下:

virtual void requestExit(); 
  //ask this object's thread to exit,asynchronous,this function can be called in other thread

     从上面CheckExit的实现中,可以看到,要能够执行RequestExit(),需要"service.bootanim.exit"的属性设置成1。

     那么这个属性在启动的过程中,已经把这个属性设置成0咯,那么又是在哪个地方将其设置成1呢。

     这个其实也是surfaceFlinger干的事情。

# bootFinished() @ surfaceFlinger.cpp
void SurfaceFlinger::bootFinished()
{
     .....
     property_set("service.bootanim.exit","1");
}

     android的thread还提供了一个额外的api函数exitPending,用来查看是否执行退出正常。

bool exitPending() const; 
   
  //returns true if requestExit 
 () has been called

     也就是说如果requestExit()成功,则退出,否则再做一次循环。

     当然,bootanimation也存在异常退出的情况,就是binder died。

# binderDied() @ BootAnimation.cpp
void BootAnimation::binderDied(const wp<IBinder>& who)
{
     kill(getpid(),SIGKILL);
     requesetExit();
}