BootAnimation使用surfaceflinger分析

本文深入解析了Android系统中BootAnimation的启动过程,包括其在init.rc中的配置、启动脚本的执行、SurfaceFlinger服务的交互及OpenGL ES的初始化。

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

<span style="font-family: Arial, Helvetica, sans-serif;">详细,可参照</span>

http://www.360doc.com/content/14/0329/23/10366845_364802340.shtml

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

1.service bootanim /system/bin/bootanimation  
2.    class main  
3.    user graphics  
4.    group system audio graphics cw_access  
5.    disabled  
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


可以看出BootAnimation最终继承了RefBase

所以会执行了onFirstRef()

BootAnimation::BootAnimation() : Thread(false)
{
    mSession = new SurfaceComposerClient();
}

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

SurfaceComposerClientlinkToComposerDeath函数获取了SurfaceFlinger服务,成功获取了之后

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


tatus_t BootAnimation::readyToRun() {
    mAssets.addDefaultAssets();

    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
            ISurfaceComposer::eDisplayIdMain));
    DisplayInfo dinfo;
    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
    if (status)
        return -1;

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

    SurfaceComposerClient::openGlobalTransaction();
    control->setLayer(0x40000000);
    SurfaceComposerClient::closeGlobalTransaction();

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

    // initialize opengl and egl
    const EGLint attribs[] = {
            EGL_RED_SIZE,   8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE,  8,
            EGL_DEPTH_SIZE, 0,
            EGL_NONE
    };
    EGLint w, h, dummy;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(display, 0, 0);
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
    surface = eglCreateWindowSurface(display, config, s.get(), NULL);
    context = eglCreateContext(display, config, NULL, NULL);
    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);

    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
        return NO_INIT;
   mDisplay = display;
    mContext = context;
    mSurface = surface;
    mWidth = w;
    mHeight = h;
    mFlingerSurfaceControl = control;
    mFlingerSurface = s;

    mAndroidAnimation = true;

    // If the device has encryption turned on or is in process 
    // of being encrypted we show the encrypted boot animation.
    char decrypt[PROPERTY_VALUE_MAX];
    property_get("vold.decrypt", decrypt, "");

    bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);

    if ((encryptedAnimation &&
            (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
            (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||

            ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
            (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||

            ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
            (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
        mAndroidAnimation = false;
    }

    return NO_ERROR;
}

首先,通过向surfaceflinger service发送

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

告诉surfaceflinger service 获取DisplayIdBinder

rameworks/native/libs/gui/ISurfaceComposer.cpp

class BpSurfaceComposer : public BpInterface<ISurfaceComposer>
{
   ...
virtual sp<IBinder> getBuiltInDisplay(int32_t id)
    {
        Parcel data, reply;
        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
        data.writeInt32(id);
        remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply);
        return reply.readStrongBinder();
    }
 ....
};

status_t BnSurfaceComposer::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case GET_BUILT_IN_DISPLAY: {
            CHECK_INTERFACE(ISurfaceComposer, data, reply);
            int32_t id = data.readInt32();
            sp<IBinder> display(getBuiltInDisplay(id));
            reply->writeStrongBinder(display);
            return NO_ERROR;
        } break;
}
}

接着获取一个 DisplayInfo dinfo;

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

同样看SurfaceFlinger.cpp

status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info)
{
    int32_t type = NAME_NOT_FOUND;
    for (int i=0 ; i<DisplayDevice::NUM_DISPLAY_TYPES ; i++) {
        if (display == mBuiltinDisplays[i]) {
            type = i;
            break;
        }
    }

    if (type < 0) {
        return type;
    }

    const HWComposer& hwc(getHwComposer());
    float xdpi = hwc.getDpiX(type);
    float ydpi = hwc.getDpiY(type);

    // TODO: Not sure if display density should handled by SF any longer
    class Density {
        static int getDensityFromProperty(char const* propName) {
            char property[PROPERTY_VALUE_MAX];
            int density = 0;
            if (property_get(propName, property, NULL) > 0) {
                density = atoi(property);
            }
            return density;
        }
    public:
        static int getEmuDensity() {
            return getDensityFromProperty("qemu.sf.lcd_density"); }
        static int getBuildDensity()  {
            return getDensityFromProperty("ro.sf.lcd_density"); }
    };

    if (type == DisplayDevice::DISPLAY_PRIMARY) {
        // The density of the device is provided by a build property
        float density = Density::getBuildDensity() / 160.0f;
        if (density == 0) {
            // the build doesn't provide a density -- this is wrong!
            // use xdpi instead
            ALOGE("ro.sf.lcd_density must be defined as a build property");
            density = xdpi / 160.0f;
        }
        if (Density::getEmuDensity()) {
            // if "qemu.sf.lcd_density" is specified, it overrides everything
            xdpi = ydpi = density = Density::getEmuDensity();
            density /= 160.0f;
        }
        info->density = density;

        // TODO: this needs to go away (currently needed only by webkit)
        sp<const DisplayDevice> hw(getDefaultDisplayDevice());
        info->orientation = hw->getOrientation();
        getPixelFormatInfo(hw->getFormat(), &info->pixelFormatInfo);
    } else {
        // TODO: where should this value come from?
        static const int TV_DENSITY = 213;
        info->density = TV_DENSITY / 160.0f;
        info->orientation = 0;
    }

    info->w = hwc.getWidth(type);
    info->h = hwc.getHeight(type);
    info->xdpi = xdpi;
    info->ydpi = ydpi;
    info->fps = float(1e9 / hwc.getRefreshPeriod(type));

    // All non-virtual displays are currently considered secure.
    info->secure = true;

    return NO_ERROR;
}

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

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

接着

SurfaceComposerClient::openGlobalTransaction();
    control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();

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

设置完Z-order

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

通过SurfaceControl获取了一个Surface

sp<Surface> SurfaceControl::getSurface() const
{
    Mutex::Autolock _l(mLock);
    if (mSurfaceData == 0) {
        mSurfaceData = new Surface(mGraphicBufferProducer);
    }
    return mSurfaceData;
}

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

Surface::Surface(
        const sp<IGraphicBufferProducer>& bufferProducer)
    : mGraphicBufferProducer(bufferProducer)
{
    // Initialize the ANativeWindow function pointers.
    ANativeWindow::setSwapInterval  = hook_setSwapInterval;
    ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
    ANativeWindow::cancelBuffer     = hook_cancelBuffer;
    ANativeWindow::queueBuffer      = hook_queueBuffer;
    ANativeWindow::query            = hook_query;
    ANativeWindow::perform          = hook_perform;

    ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
    ANativeWindow::cancelBuffer_DEPRECATED  = hook_cancelBuffer_DEPRECATED;
    ANativeWindow::lockBuffer_DEPRECATED    = hook_lockBuffer_DEPRECATED;
    ANativeWindow::queueBuffer_DEPRECATED   = hook_queueBuffer_DEPRECATED;

    const_cast<int&>(ANativeWindow::minSwapInterval) = 0;
    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;

    mReqWidth = 0;
    mReqHeight = 0;
    mReqFormat = 0;
    mReqUsage = 0;
    mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
    mCrop.clear();
    mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
    mTransform = 0;
    mDefaultWidth = 0;
    mDefaultHeight = 0;
    mUserWidth = 0;
    mUserHeight = 0;
    mTransformHint = 0;
    mConsumerRunningBehind = false;
    mConnectedToCpu = false;
}

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

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

其他都是走egl流程

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

bool BootAnimation::threadLoop()
{
    bool r;
    if (mAndroidAnimation) {
        r = android();
    } else {
        r = movie();
    }

    // No need to force exit anymore
    property_set(EXIT_PROP_NAME, "0");

    eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroyContext(mDisplay, mContext);
    eglDestroySurface(mDisplay, mSurface);
    mFlingerSurface.clear();
    mFlingerSurfaceControl.clear();
    eglTerminate(mDisplay);
    IPCThreadState::self()->stopProcess();
    return r;
}


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




<think>好的,我现在需要回答用户的问题:“BootAnimation::onFirstRef() 什么时候调用”。首先,我需要理解这个问题的背景。用户提到的是Android系统中的BootAnimation类的onFirstRef方法,这通常与系统启动动画相关。用户可能是在研究Android系统源码,或者在调试启动动画相关的问题,比如启动动画不显示或崩溃的情况。 首先,我应该回忆Android系统启动流程。BootAnimationAndroid系统启动时显示开机动画的服务,它属于系统服务的一部分,通常由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(); } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值