Android 开机动画分析

     最近在做关机画面的事情,于是搜了些关于开/关机画面的文章。

     http://blog.csdn.net/yangwen123/article/details/11680759?utm_source=tuicool&utm_medium=referral

     这篇文章写的不错,Mark一下。

     总结:

      anroid系统先启动本地服务,例如surfaceflinger,surfaceflinger 调用startBootAnim() 启动开机画面的显示。

    

  1. void SurfaceFlinger::startBootAnim() {  
  2.     // start boot animation  
  3.     if(SurfaceFlinger::sBootanimEnable){  
  4.         property_set("service.bootanim.exit""0");  
  5.         property_set("ctl.start""bootanim");  
  6.     }  

      frameworks\base\cmds\bootanimation\bootanimation_main.cpp


   

Android系统在启动SystemServer进程时,通过两个阶段来启动系统所有服务,在第一阶段启动本地服务,如SurfaceFlinger,SensorService等,在第二阶段则启动一系列的Java服务。开机动画是在什么时候启动的呢?通过查看源码,Android开机动画是在启动SurfaceFlinger服务时启动的。SystemServer的main函数首先调用init1来启动本地服务,init1函数通过JNI调用C语言中的system_init()函数来实现服务启动。

  1. extern "C" status_t system_init()  
  2. {  
  3.     sp<ProcessState> proc(ProcessState::self());  
  4.     sp<IServiceManager> sm = defaultServiceManager();  
  5.     sp<GrimReaper> grim = new GrimReaper();  
  6.     sm->asBinder()->linkToDeath(grim, grim.get(), 0);  
  7.     char propBuf[PROPERTY_VALUE_MAX];  
  8.     property_get("system_init.startsurfaceflinger", propBuf, "1");  
  9.     if (strcmp(propBuf, "1") == 0) {  
  10.         // Start the SurfaceFlinger  
  11.         SurfaceFlinger::instantiate();  
  12.     }  
  13.     ...  
  14.     return NO_ERROR;  
  15. }  
通过调用SurfaceFlinger::instantiate()函数来启动SurfaceFlinger服务,SurfaceFlinger类继承于BinderService模板类,BinderService类的instantiate()函数就是构造对应类型的服务对象,并注册到ServiceManager进程中。
  1. static void instantiate() { publish(); }  
  2. static status_t publish(bool allowIsolated = false) {  
  3.     sp<IServiceManager> sm(defaultServiceManager());  
  4.     return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated);  
  5. }  

对于SurfaceFlinger服务来说,就是首先构造SurfaceFlinger对象,然后通过调用ServiceManger的远程Binder代理对象的addService函数来注册SurfaceFlinger服务。这里只介绍SurfaceFlinger的构造过程,对于服务注册过程,在Android服务注册完整过程源码分析中已经介绍的非常详细。

  1. SurfaceFlinger::SurfaceFlinger()  
  2.     :   BnSurfaceComposer(), Thread(false),  
  3.         mTransactionFlags(0),  
  4.         mTransationPending(false),  
  5.         mLayersRemoved(false),  
  6.         mBootTime(systemTime()),  
  7.         mVisibleRegionsDirty(false),  
  8.         mHwWorkListDirty(false),  
  9.         mElectronBeamAnimationMode(0),  
  10.         mDebugRegion(0),  
  11.         mDebugDDMS(0),  
  12.         mDebugDisableHWC(0),  
  13.         mDebugDisableTransformHint(0),  
  14.         mDebugInSwapBuffers(0),  
  15.         mLastSwapBufferTime(0),  
  16.         mDebugInTransaction(0),  
  17.         mLastTransactionTime(0),  
  18.         mBootFinished(false),  
  19.         mSecureFrameBuffer(0)  
  20. {  
  21.     init();  
  22. }  
SurfaceFlinger对象实例的构造过程很简单,就是初始化一些成员变量值,然后调用init()函数来完成初始化工作
  1. void SurfaceFlinger::init()  
  2. {  
  3.     char value[PROPERTY_VALUE_MAX];  
  4.     property_get("debug.sf.showupdates", value, "0");  
  5.     mDebugRegion = atoi(value);  
  6. #ifdef DDMS_DEBUGGING  
  7.     property_get("debug.sf.ddms", value, "0");  
  8.     mDebugDDMS = atoi(value);  
  9.     if (mDebugDDMS) {  
  10.         DdmConnection::start(getServiceName());  
  11.     }  
  12. #endif  
  13.     property_get("ro.bootmode", value, "mode");  
  14.     if (!(strcmp(value, "engtest")  
  15.         && strcmp(value, "special")  
  16.         && strcmp(value, "wdgreboot")  
  17.         && strcmp(value, "unknowreboot")  
  18.         && strcmp(value, "panic"))) {  
  19.         SurfaceFlinger::sBootanimEnable = false;  
  20.     }  
  21. }  
在SurfaceFlinger的init函数中,也并没有做任何复杂工作,只是简单读取系统属性得到开机模式,来相应设置一些变量而已,比如是否显示开机动画变量sBootanimEnable。由于SurfaceFlinger继承于RefBase类,并重写了该类的onFirstRef()函数,我们知道,RefBase类的子类对象在第一次创建时,会自动调用onFirstRef()函数,因此在SurfaceFlinger对象构造完成时,将调用onFirstRef()函数。
  1. void SurfaceFlinger::onFirstRef()  
  2. {  
  3.     mEventQueue.init(this);//事件队列初始化  
  4.     run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY);//运行SurfaceFlinger线程  
  5.     mReadyToRunBarrier.wait();  
  6. }  
这里不对SurfaceFlinger的相关内容做详细介绍,本文的主要内容是介绍开机动画显示过程。由于SurfaceFlinger同时继承于线程Thread类,而且SurfaceFlinger并没有重写Thread类的run方法,因此这里调用SurfaceFlinger的run函数,其实调用的就是其父类Thread的run函数。
  1. status_t Thread::run(const char* name, int32_t priority, size_t stack)  
  2. {  
  3.     Mutex::Autolock _l(mLock);  
  4.     if (mRunning) {  
  5.         return INVALID_OPERATION;  
  6.     }  
  7.     mStatus = NO_ERROR;  
  8.     mExitPending = false;  
  9.     mThread = thread_id_t(-1);  
  10.     mHoldSelf = this;  
  11.     mRunning = true;  
  12.     bool res;  
  13.     if (mCanCallJava) {  
  14.         res = createThreadEtc(_threadLoop,this, name, priority, stack, &mThread);  
  15.     } else {  
  16.         res = androidCreateRawThreadEtc(_threadLoop,this, name, priority, stack, &mThread);  
  17.     }  
  18.     if (res == false) {  
  19.         mStatus = UNKNOWN_ERROR;   // something happened!  
  20.         mRunning = false;  
  21.         mThread = thread_id_t(-1);  
  22.         mHoldSelf.clear();  // "this" may have gone away after this.  
  23.         return UNKNOWN_ERROR;  
  24.     }  
  25.     return NO_ERROR;  
  26. }  

该函数就是创建一个线程,并运行现在执行函数_threadLoop

  1. int Thread::_threadLoop(void* user)  
  2. {  
  3.     Thread* const self = static_cast<Thread*>(user);  
  4.     sp<Thread> strong(self->mHoldSelf);  
  5.     wp<Thread> weak(strong);  
  6.     self->mHoldSelf.clear();  
  7. #ifdef HAVE_ANDROID_OS  
  8.     self->mTid = gettid();  
  9. #endif  
  10.     bool first = true;  
  11.     do {  
  12.         bool result;  
  13.         if (first) {  
  14.             first = false;  
  15.             self->mStatus = self->readyToRun();  
  16.             result = (self->mStatus == NO_ERROR);  
  17.             if (result && !self->exitPending()) {  
  18.                 result = self->threadLoop();  
  19.             }  
  20.         } else {  
  21.             result = self->threadLoop();  
  22.         }  
  23.         {  
  24.         Mutex::Autolock _l(self->mLock);  
  25.         if (result == false || self->mExitPending) {  
  26.             self->mExitPending = true;  
  27.             self->mRunning = false;  
  28.             self->mThread = thread_id_t(-1);  
  29.             self->mThreadExitedCondition.broadcast();  
  30.             break;  
  31.         }  
  32.         }  
  33.         strong.clear();  
  34.         strong = weak.promote();  
  35.     } while(strong != 0);  
  36.     return 0;  
  37. }  
在线程开始运行时,变量first为true,因此会调用self->readyToRun()来做一些初始化工作,同时将变量first设置为false,在以后线程执行过程中,就反复执行self->threadLoop()了。作为Thread类的子类SurfaceFlinger重写了这两个方法,因此创建的SurfaceFlinger线程在执行前会调用SurfaceFlinger的readyToRun()函数完成初始化任务,然后反复执行SurfaceFlinger的threadLoop()函数。
  1. status_t SurfaceFlinger::readyToRun()  
  2. {  
  3.     ALOGI(   "SurfaceFlinger's main thread ready to run. "  
  4.             "Initializing graphics H/W...");  
  5.     int dpy = 0;  
  6.     {  
  7.         // initialize the main display  
  8.         GraphicPlane& plane(graphicPlane(dpy));  
  9.         DisplayHardware* const hw = new DisplayHardware(this, dpy);  
  10.         plane.setDisplayHardware(hw);  
  11.     }  
  12.     // create the shared control-block  
  13.     mServerHeap = new MemoryHeapBase(4096,MemoryHeapBase::READ_ONLY, "SurfaceFlinger read-only heap");  
  14.     ALOGE_IF(mServerHeap==0"can't create shared memory dealer");  
  15.     mServerCblk = static_cast<surface_flinger_cblk_t*>(mServerHeap->getBase());  
  16.     ALOGE_IF(mServerCblk==0"can't get to shared control block's address");  
  17.     new(mServerCblk) surface_flinger_cblk_t;  
  18.     // initialize primary screen  
  19.     const GraphicPlane& plane(graphicPlane(dpy));  
  20.     const DisplayHardware& hw = plane.displayHardware();  
  21.     const uint32_t w = hw.getWidth();  
  22.     const uint32_t h = hw.getHeight();  
  23.     const uint32_t f = hw.getFormat();  
  24.     hw.makeCurrent();  
  25.     // initialize the shared control block  
  26.     mServerCblk->connected |= 1<<dpy;  
  27.     display_cblk_t* dcblk = mServerCblk->displays + dpy;  
  28.     memset(dcblk, 0, sizeof(display_cblk_t));  
  29.     dcblk->w            = plane.getWidth();  
  30.     dcblk->h            = plane.getHeight();  
  31.     dcblk->format       = f;  
  32.     dcblk->orientation  = ISurfaceComposer::eOrientationDefault;  
  33.     dcblk->xdpi         = hw.getDpiX();  
  34.     dcblk->ydpi         = hw.getDpiY();  
  35.     dcblk->fps          = hw.getRefreshRate();  
  36.     dcblk->density      = hw.getDensity();  
  37.     // Initialize OpenGL|ES  
  38.     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);  
  39.     glPixelStorei(GL_PACK_ALIGNMENT, 4);  
  40.     glEnableClientState(GL_VERTEX_ARRAY);  
  41.     glShadeModel(GL_FLAT);  
  42.     glDisable(GL_DITHER);  
  43.     glDisable(GL_CULL_FACE);  
  44.     const uint16_t g0 = pack565(0x0F,0x1F,0x0F);  
  45.     const uint16_t g1 = pack565(0x17,0x2f,0x17);  
  46.     const uint16_t wormholeTexData[4] = { g0, g1, g1, g0 };  
  47.     glGenTextures(1, &mWormholeTexName);  
  48.     glBindTexture(GL_TEXTURE_2D, mWormholeTexName);  
  49.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  
  50.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  
  51.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);  
  52.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);  
  53.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 220,GL_RGB, GL_UNSIGNED_SHORT_5_6_5, wormholeTexData);  
  54.     const uint16_t protTexData[] = { pack565(0x030x030x03) };  
  55.     glGenTextures(1, &mProtectedTexName);  
  56.     glBindTexture(GL_TEXTURE_2D, mProtectedTexName);  
  57.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);  
  58.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  
  59.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);  
  60.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);  
  61.     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 110,GL_RGB, GL_UNSIGNED_SHORT_5_6_5, protTexData);  
  62.     glViewport(00, w, h);  
  63.     glMatrixMode(GL_PROJECTION);  
  64.     glLoadIdentity();  
  65.     // put the origin in the left-bottom corner  
  66.     glOrthof(0, w, 0, h, 01); // l=0, r=w ; b=0, t=h  
  67.     // start the EventThread  
  68.     mEventThread = new EventThread(this);  
  69.     mEventQueue.setEventThread(mEventThread);  
  70.     hw.startSleepManagement();  
  71.     /* 
  72.      *  We're now ready to accept clients... 
  73.      */  
  74.     mReadyToRunBarrier.open();  
  75.     // start boot animation  
  76.     startBootAnim();  
  77.     return NO_ERROR;  
  78. }  
该函数首先是初始化Android的图形显示系统,启动SurfaceFlinger事件线程,这些内容只有了解了Android的显示原理及SurfaceFlinger服务之后才能理解,这里不做介绍。当显示系统初始化完毕后,调用startBootAnim()函数来显示开机动画。
  1. void SurfaceFlinger::startBootAnim() {  
  2.     // start boot animation  
  3.     if(SurfaceFlinger::sBootanimEnable){  
  4.         property_set("service.bootanim.exit""0");  
  5.         property_set("ctl.start""bootanim");  
  6.     }  
  7. }  
startBootAnim()函数比较简单,就是通过判断开机动画的变量值了决定是否显示开机动画。启动开机动画进程也是通过Android属性系统来实现的,具体启动过程可以查看 Android 系统属性SystemProperty分析。在Android系统启动脚本init.rc中配置了开机动画服务进程。


property_set("ctl.start", "bootanim")就是启动bootanim进程来显示开机动画,该进程对应的源码位于frameworks\base\cmds\bootanimation\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.     ALOGI_IF(noBootAnimation,  "boot animation disabled");  
  10.     if (!noBootAnimation) {  
  11.         /*modify  boot animation and added shutdown animation*/  
  12.         char argvtmp[2][BOOTANIMATION_PATHSET_MAX];  
  13.         memset(argvtmp[0],0,BOOTANIMATION_PATHSET_MAX);  
  14.         memset(argvtmp[1],0,BOOTANIMATION_PATHSET_MAX);  
  15.         //没有参数时,执行开机动画,  
  16.         if(argc<2){  
  17.             //开机动画文件BOOTANIMATION_BOOT_FILM_PATH_DEFAULT="/system/media/bootanimation.zip"  
  18.             strncpy(argvtmp[0],BOOTANIMATION_BOOT_FILM_PATH_DEFAULT,BOOTANIMATION_PATHSET_MAX);  
  19.             //开机声音文件BOOTANIMATION_BOOT_SOUND_PATH_DEFAULT="/system/media/bootsound.mp3"  
  20.             strncpy(argvtmp[1],BOOTANIMATION_BOOT_SOUND_PATH_DEFAULT,BOOTANIMATION_PATHSET_MAX);  
  21.         }else{//否则执行关机动画  
  22.             //关机动画文件BOOTANIMATION_SHUTDOWN_FILM_PATH_DEFAULT="/system/media/shutdownanimation.zip"  
  23.             strncpy(argvtmp[0],BOOTANIMATION_SHUTDOWN_FILM_PATH_DEFAULT,BOOTANIMATION_PATHSET_MAX);  
  24.             //关机声音文件BOOTANIMATION_SHUTDOWN_SOUND_PATH_DEFAULT="/system/media/shutdownsound.mp3"  
  25.             strncpy(argvtmp[1],BOOTANIMATION_SHUTDOWN_SOUND_PATH_DEFAULT,BOOTANIMATION_PATHSET_MAX);  
  26.         }  
  27.         __android_log_print(ANDROID_LOG_INFO,"BootAnimation""begine bootanimation!");  
  28.         //启动Binder线程池,用于接收其他进程的请求  
  29.         sp<ProcessState> proc(ProcessState::self());  
  30.         ProcessState::self()->startThreadPool();  
  31.         //创建BootAnimation对象  
  32.         BootAnimation *boota = new BootAnimation();  
  33.         String8 descname("desc.txt");  
  34.         if(argc<2){//设置开机动画文件的默认路径  
  35.             String8 mpath_default(BOOTANIMATION_BOOT_FILM_PATH_DEFAULT);  
  36.             String8 spath_default(BOOTANIMATION_BOOT_SOUND_PATH_DEFAULT);  
  37.             boota->setmoviepath_default(mpath_default);  
  38.             boota->setsoundpath_default(spath_default);  
  39.             //boota->setdescname_default(descname_default);  
  40.         }else {//设置关机动画文件的默认路径  
  41.             String8 mpath_default(BOOTANIMATION_SHUTDOWN_FILM_PATH_DEFAULT);  
  42.             String8 spath_default(BOOTANIMATION_SHUTDOWN_SOUND_PATH_DEFAULT);  
  43.             boota->setmoviepath_default(mpath_default);  
  44.             boota->setsoundpath_default(spath_default);  
  45.             //boota->setdescname_default(descname_default);  
  46.             __android_log_print(ANDROID_LOG_INFO,"BootAnimation","shutdown exe bootanimation!");  
  47.         }  
  48.         String8 mpath(argvtmp[0]);  
  49.         String8 spath(argvtmp[1]);  
  50.         //设置动画的文件路径  
  51.         boota->setmoviepath(mpath);  
  52.         boota->setsoundpath(spath);  
  53.         boota->setdescname(descname);  
  54.         __android_log_print(ANDROID_LOG_INFO,"BootAnimation","%s", mpath.string());  
  55.         __android_log_print(ANDROID_LOG_INFO,"BootAnimation","%s", spath.string());  
  56.         sp<BootAnimation> bootsp = boota;  
  57.         //将当前线程注册到Binder线程池中  
  58.         IPCThreadState::self()->joinThreadPool();  
  59.     }  
  60.     return 0;  
  61. }  

该函数构造了一个BootAnimation对象,并且为该对象设置了开关机动画及声音文件路径,同时创建了Binder线程池,并将bootanim进程的主线程注册到Binder线程池中,用于接收客户进程的Binder通信请求。

  1. BootAnimation::BootAnimation() : Thread(false)  
  2. {  
  3.     mSession = new SurfaceComposerClient();  
  4. }  
在构造BootAnimation对象时,实例化SurfaceComposerClient对象,用于请求SurfaceFlinger显示开关机动画。由于BootAnimation类继承于RefBase,同时重写了onFirstRef()函数,因此在构造BootAnimation对象时,会调用该函数。
  1. void BootAnimation::onFirstRef() {  
  2.     status_t err = mSession->linkToComposerDeath(this);  
  3.     ALOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));  
  4.     if (err == NO_ERROR) {  
  5.         run("BootAnimation", PRIORITY_DISPLAY);  
  6.     }  
  7. }  
该函数首先为SurfaceComposerClient对象注册Binder死亡通知,然后调用BootAnimation的run方法,由于BootAnimation同时继承于Thread类,前面介绍SurfaceFlinger时已经介绍到,当某个类继承于Thread类时,当调用该类的run函数时,函数首先会执行readyToRun()函数来完成线程执行前的一些工作,然后线程反复执行threadLoop()函数,在BootAnimation类中,同样重新了这两个方法
  1. status_t BootAnimation::readyToRun() {  
  2.     //force screen display in vertical layout  
  3.     mSession->setOrientation(000);  
  4.     mAssets.addDefaultAssets();  
  5.     DisplayInfo dinfo;  
  6.     status_t status = session()->getDisplayInfo(0, &dinfo);  
  7.     if (status)  
  8.         return -1;  
  9.     // create the native surface  
  10.     sp<SurfaceControl> control;  
  11.     if (dinfo.w > dinfo.h) {  
  12.         control = session()->createSurface(0, dinfo.h, dinfo.w, PIXEL_FORMAT_RGB_565);  
  13.     } else {  
  14.         control = session()->createSurface(0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);  
  15.     }  
  16.     SurfaceComposerClient::openGlobalTransaction();  
  17.     control->setLayer(0x40000000);  
  18.     SurfaceComposerClient::closeGlobalTransaction();  
  19.     sp<Surface> s = control->getSurface();  
  20.     // initialize opengl and egl  
  21.     const EGLint attribs[] = {  
  22.             EGL_RED_SIZE,   8,  
  23.             EGL_GREEN_SIZE, 8,  
  24.             EGL_BLUE_SIZE,  8,  
  25.             EGL_DEPTH_SIZE, 0,  
  26.             EGL_NONE  
  27.     };  
  28.     EGLint w, h, dummy;  
  29.     EGLint numConfigs;  
  30.     EGLConfig config;  
  31.     EGLSurface surface;  
  32.     EGLContext context;  
  33.     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);  
  34.     eglInitialize(display, 00);  
  35.     eglChooseConfig(display, attribs, &config, 1, &numConfigs);  
  36.     surface = eglCreateWindowSurface(display, config, s.get(), NULL);  
  37.     context = eglCreateContext(display, config, NULL, NULL);  
  38.     eglQuerySurface(display, surface, EGL_WIDTH, &w);  
  39.     eglQuerySurface(display, surface, EGL_HEIGHT, &h);  
  40.     if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)  
  41.         return NO_INIT;  
  42.     mDisplay = display;  
  43.     mContext = context;  
  44.     mSurface = surface;  
  45.     mWidth = w;  
  46.     mHeight = h;  
  47.     mFlingerSurfaceControl = control;  
  48.     mFlingerSurface = s;  
  49.     mAndroidAnimation = true;  
  50.     // If the device has encryption turned on or is in process   
  51.     // of being encrypted we show the encrypted boot animation.  
  52.     char decrypt[PROPERTY_VALUE_MAX];  
  53.     property_get("vold.decrypt", decrypt, "");  
  54.     bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);  
  55.     //如果"/system/media/bootanimation-encrypted.zip"文件存在或者设置的动画文件存在,或者默认动画文件存在,或者"/data/local/bootanimation.zip"文件存在,都显示开机动画文件,否则显示Android滚动字样  
  56.     if ((encryptedAnimation &&  
  57.             (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&  
  58.             (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||  
  59.             ((access(moviepath, R_OK) == 0) &&  
  60.             (mZip.open(moviepath) == NO_ERROR)) ||  
  61.             ((access(movie_default_path, R_OK) == 0) &&  
  62.             (mZip.open(movie_default_path) == NO_ERROR)) ||  
  63.             ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&  
  64.             (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR))) {  
  65.         mAndroidAnimation = false;  
  66.     }  
  67.     return NO_ERROR;  
  68. }  
在该函数里创建SurfaceControl对象,通过SurfaceControl对象得到Surface对象,并初始化好OpenGL,同时判断动画文件是否存在,如果不存在,则设置标志位mAndroidAnimation为true,表示显示Android滚动字样。当初始化完这些必需资源后,线程进入循环执行体threadLoop()
  1. bool BootAnimation::threadLoop()  
  2. {  
  3.     bool r;  
  4.     //如果mAndroidAnimation为true,表示动画文件不存在,则显示Android滚动字样  
  5.     if (mAndroidAnimation) {  
  6.         r = android();  
  7.     } else {//显示动画  
  8.         r = movie();  
  9.     }  
  10.     //资源回收  
  11.     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);  
  12.     eglDestroyContext(mDisplay, mContext);  
  13.     eglDestroySurface(mDisplay, mSurface);  
  14.     mFlingerSurface.clear();  
  15.     mFlingerSurfaceControl.clear();  
  16.     eglTerminate(mDisplay);  
  17.     IPCThreadState::self()->stopProcess();  
  18.     return r;  
  19. }  
开机画面主要是由一个zip格式的压缩包bootanimation.zip组成,压缩包里面包含数张png格式的图片,还有一个desc.txt的文本文档,开机时按desc.txt里面的指令,屏幕上会按文件名称顺序连续的播放一张张的图片,就像播放原始的胶带影片一样,形成动画。desc.txt是一个保存形式为ANSI格式的文件,用于设置这个动画像素(大小),帧数,闪烁次数,文件夹名称等。内容如下:
480 854 10
p 1 2 folder1
p 0 2 folder2

480 427 30  ---这里的480代表图片的像素(大小)宽度,427代表图片的像素(大小)高度,30代表帧数;

p 1 0 part0 ---这里的p代表标志符,1代表循环次数为1次,0代表阶段间隔时间为0,part0代表对应的文件夹名,为第一阶段动画图片目录;

p 0 0 part1---这里的p代表标志符,0代表本阶段无限循环,0代表阶段间隔时间为0,part1代表对应的文件夹名,为第二阶段动画图片目录;

阶段切换间隔时间:单位是一个帧的持续时间,比如帧数是30,那么帧的持续时间就是1秒/30 = 33.3毫秒。阶段切换间隔时间期间开机动画进程进入休眠,把CPU时间让给初始化系统使用。也就是间隔长启动会快,但会影响动画效果。
folder1和folder2文件夹内包含的是两个动画的系列图片,图片为PNG格式。



  1. bool BootAnimation::movie()  
  2. {  
  3.     ZipFileRO& zip(mZip);  
  4.     //获取zip压缩文件中的文件数目  
  5.     size_t numEntries = zip.getNumEntries();  
  6.     //打开zip压缩文件中的desc.txt文件  
  7.     ZipEntryRO desc = zip.findEntryByName("desc.txt");  
  8.     FileMap* descMap = zip.createEntryFileMap(desc);  
  9.     ALOGE_IF(!descMap, "descMap is null");  
  10.     if (!descMap) {  
  11.         return false;  
  12.     }  
  13.     //读取desc.txt文件内容  
  14.     String8 desString((char const*)descMap->getDataPtr(),descMap->getDataLength());  
  15.     char const* s = desString.string();  
  16.     Animation animation;  
  17.     //读取persist.sys.silence属性来决定是否播放开机音乐  
  18.     char silence[PROPERTY_VALUE_MAX];  
  19.     property_get("persist.sys.silence", silence, "0");  
  20.     if(strcmp("1", silence)==0){  
  21.         // do something.  
  22.     }else{  
  23.         soundplay();  
  24.     }  
  25.     //解析desc.txt文件内容  
  26.     for (;;) {     //从字符串s中查找是否有字符串"\n",如果有,返回s中"\n"起始位置的指针,如果没有,返回null。  
  27.         const char* endl = strstr(s, "\n");  
  28.         if (!endl) break;  
  29.         //取得文件一行内容  
  30.         String8 line(s, endl - s);  
  31.         const char* l = line.string();  
  32.         int fps, width, height, count, pause;  
  33.         char path[256];  
  34.         char pathType;  
  35.         //从文件第一行中读取宽度,高度,帧数  
  36.         //480 854 10 <---> width height fps  
  37.         if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {  
  38.             //LOGD("> w=%d, h=%d, fps=%d", fps, width, height);  
  39.             animation.width = (width > 0 ? width : mWidth);  
  40.             animation.height = (height > 0 ? height : mHeight);  
  41.             animation.fps = fps;  
  42.         //p 1 2 folder1 <---> pathType count pause path  
  43.         }else if (sscanf(l, " %c %d %d %s", &pathType, &count, &pause, path) == 4) {  
  44.             //LOGD("> type=%c, count=%d, pause=%d, path=%s", pathType, count, pause, path);  
  45.             Animation::Part part;//一个part描述一个动画文件夹内容  
  46.             part.playUntilComplete = pathType == 'c';  
  47.             part.count = count;  
  48.             part.pause = pause;  
  49.             part.path = path;  
  50.             animation.parts.add(part);  
  51.         }  
  52.         s = ++endl;  
  53.     }  
  54.     //读取动画个数  
  55.     const size_t pcount = animation.parts.size();  
  56.     //遍历zip压缩包中的所有文件  
  57.     for (size_t i=0 ; i<numEntries ; i++) {  
  58.         char name[256];  
  59.         ZipEntryRO entry = zip.findEntryByIndex(i);  
  60.         //读取压缩包中的文件名称,所在目录的路径  
  61.         if (zip.getEntryFileName(entry, name, 256) == 0) {  
  62.             const String8 entryName(name);  
  63.             const String8 path(entryName.getPathDir());  
  64.             const String8 leaf(entryName.getPathLeaf());  
  65.             if (leaf.size() > 0) {  
  66.                 for (int j=0 ; j<pcount ; j++) {  
  67.                     if (path == animation.parts[j].path) {  
  68.                         int method;  
  69.                         //获取文件信息  
  70.                         if (zip.getEntryInfo(entry, &method, 00000)) {  
  71.                             if (method == ZipFileRO::kCompressStored) {  
  72.                                 FileMap* map = zip.createEntryFileMap(entry);  
  73.                                 if (map) {  
  74.                                     Animation::Frame frame;  
  75.                                     frame.name = leaf;  
  76.                                     frame.map = map;  
  77.                                     Animation::Part& part(animation.parts.editItemAt(j));  
  78.                                     part.frames.add(frame);  
  79.                                 }  
  80.                             }  
  81.                         }  
  82.                     }  
  83.                 }  
  84.             }  
  85.         }  
  86.     }  
  87.     // clear screen  
  88.     glShadeModel(GL_FLAT);  
  89.     glDisable(GL_DITHER);  
  90.     glDisable(GL_SCISSOR_TEST);  
  91.     glDisable(GL_BLEND);  
  92.     glClearColor(0,0,0,1);  
  93.     glClear(GL_COLOR_BUFFER_BIT);  
  94.     eglSwapBuffers(mDisplay, mSurface);  
  95.     glBindTexture(GL_TEXTURE_2D, 0);  
  96.     glEnable(GL_TEXTURE_2D);  
  97.     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);  
  98.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);  
  99.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);  
  100.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
  101.     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
  102.     const int xc = (mWidth - animation.width) / 2;  
  103.     const int yc = ((mHeight - animation.height) / 2);  
  104.     nsecs_t lastFrame = systemTime();  
  105.     nsecs_t frameDuration = s2ns(1) / animation.fps;  
  106.     Region clearReg(Rect(mWidth, mHeight));  
  107.     clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));  
  108.     for (int i=0 ; i<pcount ; i++) {  
  109.         const Animation::Part& part(animation.parts[i]);  
  110.         const size_t fcount = part.frames.size();  
  111.         glBindTexture(GL_TEXTURE_2D, 0);  
  112.         //循环显示文件夹下的图片  
  113.         for (int r=0 ; !part.count || r<part.count ; r++) {  
  114.             // Exit any non playuntil complete parts immediately  
  115.             if(exitPending() && !part.playUntilComplete)  
  116.                 break;  
  117.             for (int j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {  
  118.                 const Animation::Frame& frame(part.frames[j]);  
  119.                 nsecs_t lastFrame = systemTime();  
  120.                 if (r > 0) {  
  121.                     glBindTexture(GL_TEXTURE_2D, frame.tid);  
  122.                 } else {  
  123.                     if (part.count != 1) {  
  124.                         glGenTextures(1, &frame.tid);  
  125.                         glBindTexture(GL_TEXTURE_2D, frame.tid);  
  126.                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  
  127.                         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
  128.                     }  
  129.                     initTexture(frame.map->getDataPtr(),frame.map->getDataLength());  
  130.                 }  
  131.                 if (!clearReg.isEmpty()) {  
  132.                     Region::const_iterator head(clearReg.begin());  
  133.                     Region::const_iterator tail(clearReg.end());  
  134.                     glEnable(GL_SCISSOR_TEST);  
  135.                     while (head != tail) {  
  136.                         const Rect& r(*head++);  
  137.                         glScissor(r.left, mHeight - r.bottom,  
  138.                                 r.width(), r.height());  
  139.                         glClear(GL_COLOR_BUFFER_BIT);  
  140.                     }  
  141.                     glDisable(GL_SCISSOR_TEST);  
  142.                 }  
  143.                 glDrawTexiOES(xc, yc, 0, animation.width, animation.height);  
  144.                 eglSwapBuffers(mDisplay, mSurface);  
  145.                 nsecs_t now = systemTime();  
  146.                 nsecs_t delay = frameDuration - (now - lastFrame);  
  147.                 //ALOGD("%lld, %lld", ns2ms(now - lastFrame), ns2ms(delay));  
  148.                 lastFrame = now;  
  149.                 if (delay > 0) {  
  150.                     struct timespec spec;  
  151.                     spec.tv_sec  = (now + delay) / 1000000000;  
  152.                     spec.tv_nsec = (now + delay) % 1000000000;  
  153.                     int err;  
  154.                     do {  
  155.                         err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);  
  156.                     } while (err<0 && errno == EINTR);  
  157.                 }  
  158.                 checkExit();  
  159.             }  
  160.             usleep(part.pause * ns2us(frameDuration));  
  161.             // For infinite parts, we've now played them at least once, so perhaps exit  
  162.             if(exitPending() && !part.count)  
  163.                 break;  
  164.         }  
  165.         // free the textures for this part  
  166.         if (part.count != 1) {  
  167.             for (int j=0 ; j<fcount ; j++) {  
  168.                 const Animation::Frame& frame(part.frames[j]);  
  169.                 glDeleteTextures(1, &frame.tid);  
  170.             }  
  171.         }  
  172.     }  
  173.     //停止播放开机音乐  
  174.     soundstop();  
  175.     return false;  
  176. }  
开机音乐播放过程
  1. bool BootAnimation::soundplay()  
  2. {  
  3.     mp = NULL;  
  4.     if(soundpath.length() == 0){  
  5.         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "sound resource is not right.");  
  6.         return false;  
  7.     }  
  8.     //打开设置的开机音乐文件  
  9.     int fd = open(soundpath.string(), O_RDONLY);  
  10.     if(fd == -1){  
  11.         __android_log_print(ANDROID_LOG_WARN, LOG_TAG, "boot animation play default source.");  
  12.         close(fd);  
  13.         //如果没有设置开机音乐文件路径,则打开默认的开机音乐文件  
  14.         fd = open(sound_default_path.string(),O_RDONLY);  
  15.         if(fd == -1){  
  16.             close(fd);  
  17.             __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "can not find bootanimation resource....");  
  18.             return false;  
  19.         }  
  20.     }  
  21.     mp = new MediaPlayer();  
  22.     mp->setDataSource(fd, 0, 0x7ffffffffffffffLL);  
  23.     mp->setAudioStreamType(/*AUDIO_STREAM_MUSIC*/AUDIO_STREAM_SYSTEM);  
  24.     mp->prepare();  
  25.     mp->start();  
  26.     return false;  
  27. }  


整个开关机动画就完成了,那关机动画是如何启动的呢?下一篇继续介绍Android系统的关机流程!


猜你喜欢

转载自blog.csdn.net/lininglive/article/details/78402319