BootAnimation使用surfaceflinger分析

本文详细解析了Android系统中BootAnimation的启动流程,包括通过init.rc配置启动BootAnimation服务、创建Surface并设置图层,以及如何初始化OpenGL进行渲染。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


首先,从BootAnimation开始分析,BootAnimation在启动脚本init。Rc被配置成一个服务

  1. 1.service bootanim /system/bin/bootanimation    
  2. 2.    class main    
  3. 3.    user graphics    
  4. 4.    group system audio graphics cw_access    
  5. 5.    disabled    
  6. 6.    oneshot    

而其代码在 frameworks/cmds/bootanimation

int main(int argc, char** argv)

{

#if defined(HAVE_PTHREADS)

    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);

#endif

 

    char value[PROPERTY_VALUE_MAX];

    property_get("debug.sf.nobootanimation", value, "0");

    int noBootAnimation = atoi(value);

    ALOGI_IF(noBootAnimation,  "boot animation disabled");

    if (!noBootAnimation) {

 

        sp<ProcessState> proc(ProcessState::self());

        ProcessState::self()->startThreadPool();

 

        // create the boot animation object

        sp<BootAnimation> boot new BootAnimation();

 

        IPCThreadState::self()->joinThreadPool();

 

    }

    return 0;

}


从代码可以看出,bootanimation的启动是通过new一个BootAnimation



  1. BootAnimation::BootAnimation() : Thread(false)  
  2. {  
  3.     mSession = new SurfaceComposerClient();  
  4. }  


首先 创建 SurfaceFilinger Client


========================================


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

可以看出BootAnimation最终继承了RefBase在main函数里的boot 是一个sp 的智能指针,

第一次对 BootAnimation 引用调用sp<BootAnimation>时 会调用 BootAnimation 的onFirstRef()方法;

最后 调用run,让BootAnimation线程跑起来,Thread会先跑到readyToRun(),然后再跑:threadLoop()




SurfaceComposerClientlinkToComposerDeath函数获取了SurfaceFlinger服务,

linkTocomposerDeath的作用是 当surfaceflinger死掉时,当前Bootanimation service 就会得到通知,会自动调用 BootAnimation::binderDied。  



  1. tatus_t BootAnimation::readyToRun() {  
  2.     mAssets.addDefaultAssets();  
  3.   
  4.     sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(  
  5.             ISurfaceComposer::eDisplayIdMain));  
  6.     DisplayInfo dinfo;  
  7.     status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);  
  8.     if (status)  
  9.         return -1;  
  10.   
  11.     // create the native surface  
  12.     sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),  
  13.             dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);  
  14.   
  15.     SurfaceComposerClient::openGlobalTransaction();  
  16.     control->setLayer(0x40000000);  //设置图层;
  17.     SurfaceComposerClient::closeGlobalTransaction();  
  18.   
  19.     sp<Surface> s = control->getSurface();  
  20.   
  21.     // initialize opengl and egl  
  22.     const EGLint attribs[] = {  
  23.             EGL_RED_SIZE,   8,  
  24.             EGL_GREEN_SIZE, 8,  
  25.             EGL_BLUE_SIZE,  8,  
  26.             EGL_DEPTH_SIZE, 0,  
  27.             EGL_NONE  
  28.     };  
  29.     EGLint w, h, dummy;  
  30.     EGLint numConfigs;  
  31.     EGLConfig config;  
  32.     EGLSurface surface;  
  33.     EGLContext context;  
  34.   
  35.     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);  
  36.   
  37.     eglInitialize(display, 0, 0);  
  38.     eglChooseConfig(display, attribs, &config, 1, &numConfigs);  
  39.     surface = eglCreateWindowSurface(display, config, s.get(), NULL);  
  40.     context = eglCreateContext(display, config, NULL, NULL);  
  41.     eglQuerySurface(display, surface, EGL_WIDTH, &w);  
  42.     eglQuerySurface(display, surface, EGL_HEIGHT, &h);  
  43.   
  44.     if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)  
  45.         return NO_INIT;  
  46.    mDisplay = display;  
  47.     mContext = context;  
  48.     mSurface = surface;  
  49.     mWidth = w;  
  50.     mHeight = h;  
  51.     mFlingerSurfaceControl = control;  
  52.     mFlingerSurface = s;  
  53.   
  54.     mAndroidAnimation = true;  
  55.   
  56.     // If the device has encryption turned on or is in process   
  57.     // of being encrypted we show the encrypted boot animation.  
  58.     char decrypt[PROPERTY_VALUE_MAX];  
  59.     property_get("vold.decrypt", decrypt, "");  
  60.   
  61.     bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);  
  62.   
  63.     if ((encryptedAnimation &&  
  64.             (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&  
  65.             (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||  
  66.   
  67.             ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&  
  68.             (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||  
  69.   
  70.             ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&  
  71.             (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {  
  72.         mAndroidAnimation = false;  
  73.     }  
  74.   
  75.     return NO_ERROR;  
  76. }  

首先,通过向surfaceflinger service发送

  1. sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(  
  2.             ISurfaceComposer::eDisplayIdMain));  

告诉surfaceflinger service 获取DisplayIdBinder

rameworks/native/libs/gui/ISurfaceComposer.cpp

  1. class BpSurfaceComposer : public BpInterface<ISurfaceComposer>  
  2. {  
  3.    ...  
  4. virtual sp<IBinder> getBuiltInDisplay(int32_t id)  
  5.     {  
  6.         Parcel data, reply;  
  7.         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());  
  8.         data.writeInt32(id);  
  9.         remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply);  
  10.         return reply.readStrongBinder();  
  11.     }  
  12.  ....  
  13. };  
  14.   
  15. status_t BnSurfaceComposer::onTransact(  
  16.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  17. {  
  18. switch(code) {  
  19. case GET_BUILT_IN_DISPLAY: {  
  20.             CHECK_INTERFACE(ISurfaceComposer, data, reply);  
  21.             int32_t id = data.readInt32();  
  22.             sp<IBinder> display(getBuiltInDisplay(id));  
  23.             reply->writeStrongBinder(display);  
  24.             return NO_ERROR;  
  25.         } break;  
  26. }  
  27. }  

接着获取一个 DisplayInfo dinfo;

  1. status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);  

同样看SurfaceFlinger.cpp

  1. status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info)  
  2. {  
  3.     int32_t type = NAME_NOT_FOUND;  
  4.     for (int i=0 ; i<DisplayDevice::NUM_DISPLAY_TYPES ; i++) {  
  5.         if (display == mBuiltinDisplays[i]) {  
  6.             type = i;  
  7.             break;  
  8.         }  
  9.     }  
  10.   
  11.     if (type < 0) {  
  12.         return type;  
  13.     }  
  14.   
  15.     const HWComposer& hwc(getHwComposer());  
  16.     float xdpi = hwc.getDpiX(type);  
  17.     float ydpi = hwc.getDpiY(type);  
  18.   
  19.     // TODO: Not sure if display density should handled by SF any longer  
  20.     class Density {  
  21.         static int getDensityFromProperty(char const* propName) {  
  22.             char property[PROPERTY_VALUE_MAX];  
  23.             int density = 0;  
  24.             if (property_get(propName, property, NULL) > 0) {  
  25.                 density = atoi(property);  
  26.             }  
  27.             return density;  
  28.         }  
  29.     public:  
  30.         static int getEmuDensity() {  
  31.             return getDensityFromProperty("qemu.sf.lcd_density"); }  
  32.         static int getBuildDensity()  {  
  33.             return getDensityFromProperty("ro.sf.lcd_density"); }  
  34.     };  
  35.   
  36.     if (type == DisplayDevice::DISPLAY_PRIMARY) {  
  37.         // The density of the device is provided by a build property  
  38.         float density = Density::getBuildDensity() / 160.0f;  
  39.         if (density == 0) {  
  40.             // the build doesn't provide a density -- this is wrong!  
  41.             // use xdpi instead  
  42.             ALOGE("ro.sf.lcd_density must be defined as a build property");  
  43.             density = xdpi / 160.0f;  
  44.         }  
  45.         if (Density::getEmuDensity()) {  
  46.             // if "qemu.sf.lcd_density" is specified, it overrides everything  
  47.             xdpi = ydpi = density = Density::getEmuDensity();  
  48.             density /= 160.0f;  
  49.         }  
  50.         info->density = density;  
  51.   
  52.         // TODO: this needs to go away (currently needed only by webkit)  
  53.         sp<const DisplayDevice> hw(getDefaultDisplayDevice());  
  54.         info->orientation = hw->getOrientation();  
  55.         getPixelFormatInfo(hw->getFormat(), &info->pixelFormatInfo);  
  56.     } else {  
  57.         // TODO: where should this value come from?  
  58.         static const int TV_DENSITY = 213;  
  59.         info->density = TV_DENSITY / 160.0f;  
  60.         info->orientation = 0;  
  61.     }  
  62.   
  63.     info->w = hwc.getWidth(type);  
  64.     info->h = hwc.getHeight(type);  
  65.     info->xdpi = xdpi;  
  66.     info->ydpi = ydpi;  
  67.     info->fps = float(1e9 / hwc.getRefreshPeriod(type));  
  68.   
  69.     // All non-virtual displays are currently considered secure.  
  70.     info->secure = true;  
  71.   
  72.     return NO_ERROR;  
  73. }  

接着,按返回的DisplayInfo创建一个native surface

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

接着

  1. SurfaceComposerClient::openGlobalTransaction();  //增加一个 全局Transaction计数
  2.     control->setLayer(0x40000000);  //设置图层;
  3. SurfaceComposerClient::closeGlobalTransaction();  //减少一个全局Transaction计数,当这个全局Transaction计数减少至0的时候,把mStates发送给SurfaceFlinger处理

setLayer从代码里看是设置z-order,层级越高越接近客户

设置完Z-order

  1. sp<Surface> s = control->getSurface();  

  1. 通过SurfaceControl获取了一个Surface  

  1. sp<Surface> SurfaceControl::getSurface() const  
  2. {  
  3.     Mutex::Autolock _l(mLock);  
  4.     if (mSurfaceData == 0) {  
  5.         mSurfaceData = new Surface(mGraphicBufferProducer);  
  6.     }  
  7.     return mSurfaceData;  
  8. }  

Surface的创建则通过createsurface时创建的mGraphicBufferProducer(SurfaceTextureLayer)来初始化

  1. Surface::Surface(  
  2.         const sp<IGraphicBufferProducer>& bufferProducer)  
  3.     : mGraphicBufferProducer(bufferProducer)  
  4. {  
  5.     // Initialize the ANativeWindow function pointers.  
  6.     ANativeWindow::setSwapInterval  = hook_setSwapInterval;  
  7.     ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;  
  8.     ANativeWindow::cancelBuffer     = hook_cancelBuffer;  
  9.     ANativeWindow::queueBuffer      = hook_queueBuffer;  
  10.     ANativeWindow::query            = hook_query;  
  11.     ANativeWindow::perform          = hook_perform;  
  12.   
  13.     ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;  
  14.     ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;  
  15.     ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;  
  16.     ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;  
  17.   
  18.     const_cast<int&>(ANativeWindow::minSwapInterval) = 0;  
  19.     const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;  
  20.   
  21.     mReqWidth = 0;  
  22.     mReqHeight = 0;  
  23.     mReqFormat = 0;  
  24.     mReqUsage = 0;  
  25.     mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;  
  26.     mCrop.clear();  
  27.     mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;  
  28.     mTransform = 0;  
  29.     mDefaultWidth = 0;  
  30.     mDefaultHeight = 0;  
  31.     mUserWidth = 0;  
  32.     mUserHeight = 0;  
  33.     mTransformHint = 0;  
  34.     mConsumerRunningBehind = false;  
  35.     mConnectedToCpu = false;  
  36. }  

  1. 接着通过这个surface对象初始化egl  

surface = eglCreateWindowSurface(display, config, s.get(), NULL);

其他都是走egl流程

然后,继续分析BootAnimation,跑完systemReadyRun,则会跑threadloop循环

  1. bool BootAnimation::threadLoop()  
  2. {  
  3.     bool r;  
  4.     if (mAndroidAnimation) {  
  5.         r = android();  
  6.     } else {  
  7.         r = movie();  
  8.     }  
  9.   
  10.     // No need to force exit anymore  
  11.     property_set(EXIT_PROP_NAME, "0");  
  12.   
  13.     eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);  
  14.     eglDestroyContext(mDisplay, mContext);  
  15.     eglDestroySurface(mDisplay, mSurface);  
  16.     mFlingerSurface.clear();  
  17.     mFlingerSurfaceControl.clear();  
  18.     eglTerminate(mDisplay);  
  19.     IPCThreadState::self()->stopProcess();  
  20.     return r;  
  21. }  


可以看出,如果mAndroidAnimationtrue则跑Android,不成功则跑movie


















<think>好的,我现在需要回答用户的问题:“BootAnimation::onFirstRef() 什么时候调用”。首先,我需要理解这个问题的背景。用户提到的是Android系统中的BootAnimation类的onFirstRef方法,这通常与系统启动动画相关。用户可能是在研究Android系统源码,或者在调试启动动画相关的问题,比如启动动画不显示或崩溃的情况。 首先,我应该回忆Android系统启动流程。BootAnimation是Android系统启动时显示开机动画的服务,它属于系统服务的一部分,通常由init进程启动。onFirstRef()方法属于RefBase类(或其子类),在对象被首次引用时调用。因此,用户的问题实际上是询问在系统启动过程中,BootAnimation实例的onFirstRef()方法的触发时机。 接下来,我需要确认BootAnimation的创建和初始化流程。根据Android源码,BootAnimation服务通常在系统服务进程(如system_server)启动时被创建。具体来说,可能是在SurfaceFlinger或某个系统服务初始化时实例化BootAnimation对象。当这个对象被创建时,由于RefBase的机制,onFirstRef()会被调用。 然后,我需要考虑用户可能的实际需求。用户可能想知道这个方法的调用时机,以便在启动动画初始化时执行某些操作,或者调试为什么启动动画没有按预期运行。例如,如果onFirstRef()没有被正确调用,可能导致动画资源未加载,进而导致黑屏或动画不显示的问题。 此外,用户可能对Android的底层机制有一定了解,但需要更详细的代码路径或调用栈信息。因此,在回答时需要提供具体的源码位置或调用流程,例如指出在系统启动的不同阶段,BootAnimation如何被实例化,以及RefBase的onFirstRef()如何被触发。 还需要考虑可能的版本差异。不同Android版本中BootAnimation的实现可能有所不同,但基本原理相似。因此,在回答时应保持通用性,同时指出可能的差异,或建议用户参考特定版本的源码。 最后,确保回答结构清晰,分步骤解释调用时机,并提供示例代码或流程说明,帮助用户理解。同时,按照用户的要求,生成相关问题,覆盖常见疑问,如调用堆栈分析、自定义动画、资源加载失败排查等。</think>`BootAnimation::onFirstRef()` 是 Android 系统中与启动动画相关的生命周期方法,其调用时机与系统启动流程密切相关。以下是详细分析: --- ### **1. 调用时机** `onFirstRef()` 是 `RefBase` 类的虚函数,在对象首次被强引用(`sp` 智能指针引用)时自动调用。对于 `BootAnimation` 类,其调用流程如下: 1. **系统服务初始化阶段**: - 在 `SurfaceFlinger` 进程启动时,`BootAnimation` 实例被创建: ```cpp // frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp void SurfaceFlinger::init() { if (mBootAnimationEnabled) { mBootAnimation = new BootAnimation(); // 创建实例 } } ``` - 当 `new BootAnimation()` 被调用时,`onFirstRef()` 会被触发。 2. **RefBase 机制触发**: - `BootAnimation` 继承自 `RefBase`,首次通过 `sp<BootAnimation>` 强引用时触发: ```cpp sp<BootAnimation> bootAnim = new BootAnimation(); // 触发 onFirstRef() ``` 3. **启动动画线程启动**: - `onFirstRef()` 内部会初始化动画资源并启动线程: ```cpp void BootAnimation::onFirstRef() { // 加载动画资源(如 splashscreen.zip) mZipFileName = getBootAnimationFileName(); // 启动动画线程 run("BootAnimation", PRIORITY_DISPLAY); } ``` --- ### **2. 调用堆栈示例** 通过调试工具(如 GDB 或日志)可观察到以下调用栈: ```cpp BootAnimation::onFirstRef() → BootAnimation::getBootAnimationFileName() // 获取动画路径 → BootAnimation::run() // 启动线程 → BootAnimation::playAnimation() // 播放动画 → BootAnimation::drawFrame() // 绘制帧 ``` --- ### **3. 关键代码路径** - **Android 12+ 源码位置**: - `frameworks/native/services/bootanimation/BootAnimation.cpp` - `frameworks/native/libs/nativewindow/RefBase.cpp` - **核心逻辑**: ```cpp // frameworks/native/services/bootanimation/BootAnimation.cpp BootAnimation::BootAnimation() : Thread(false), mZipFileName("/system/media/bootanimation.zip") { // 构造函数中设置默认动画路径 } void BootAnimation::onFirstRef() { // 首次强引用时加载动画资源 if (!mZipFileName.empty()) { mZip = new ZipFileRO(mZipFileName.string()); } // 启动线程播放动画 run("BootAnimation", PRIORITY_DISPLAY); } ``` --- ### **4. 常见问题排查** #### **(1) 动画未触发?** - **原因**:`BootAnimation` 实例未被强引用(如 `sp` 未持有) - **验证方法**: ```cpp // 检查 SurfaceFlinger 是否启用动画 bool SurfaceFlinger::mBootAnimationEnabled = true; // 默认为 true ``` #### **(2) 资源加载失败?** - **日志检查**: ```bash logcat -s BootAnimation # 观察 "Failed to open zip file" 错误 ``` --- ### **5. 自定义启动动画** 若需修改动画行为,可在 `onFirstRef()` 中调整: ```cpp void MyBootAnimation::onFirstRef() { // 自定义逻辑:加载特定分辨率动画 mZipFileName = "/system/media/bootanimation_1080p.zip"; // 调用父类方法 BootAnimation::onFirstRef(); } ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值