乐于分享
好东西不私藏

Android Framework源码解析(七):BootAnimation 启动流程解析——开机动画是如何显示出来的?

Android Framework源码解析(七):BootAnimation 启动流程解析——开机动画是如何显示出来的?

上一篇我们完整梳理了 Launcher3 桌面启动全流程,理解系统如何拉起桌面应用并渲染 UI。 但有一个直观问题容易被忽略:从按下电源键到 Launcher 完整显示,中间长达数秒的时间屏幕并非黑屏,而是持续播放厂商定制开机动画,完整链路为: Google Logo 静态帧 → BootAnimation 逐帧动画 → Launcher 桌面

本篇围绕 4 个核心问题,结合完整 Native+Java 层源码拆解全链路:

  1. 开机动画进程由谁启动?
  2. 为何 Framework 服务未完全就绪时,动画就能正常渲染输出?
  3. SurfaceFlinger 与 BootAnimation 的依赖、协作关系是什么?
  4. BootAnimation 如何精准感知退出时机,动画结束后 Launcher 如何接管屏幕?

完整系统启动骨架链路: init 进程 → SurfaceFlinger → BootAnimation → WindowManagerService → Launcher

一、BootAnimation 进程启动源头:init 配置与启动规则

1.1 启动配置文件 bootanim.rc

路径:frameworks/base/cmds/bootanimation/bootanim.rc

service bootanim /system/bin/bootanimation    class core animation    user graphics    group graphics audio    disabled    oneshot    ioprio rt 0    task_profiles MaxPerformance

关键配置释义:

  1. disabled
    :默认不会由 init 自动拉起,必须由 SurfaceFlinger 初始化完成后通过属性 ctl.start bootanim 主动触发启动
  2. class core animation
    :归属核心动画进程组,系统关机时统一回收;
  3. user/group graphics
    :赋予图形、音频硬件访问权限,保证 OpenGL 渲染、动画音效可用;
  4. oneshot
    :进程执行完成后自动销毁,不会反复重启;
  5. ioprio rt 0
    :实时 IO 优先级,避免动画加载、解码卡顿。

1.2 启动时序关键:SurfaceFlinger 是前置依赖

内核启动后第一个用户态进程 init,会优先解析 rc 脚本启动 surfaceflinger 图形合成服务。 SurfaceFlinger 完成 EGL、显示硬件、BufferQueue 初始化后,会通过属性线程执行: property_set("ctl.start", "bootanim") 通知 init 拉起 /system/bin/bootanimation 二进制程序。 依赖逻辑:BootAnimation 所有渲染、图层创建都依赖 SurfaceFlinger,因此必须等 SF 就绪后才能启动动画进程。

1.3 程序入口 bootanimation_main.cpp

路径:frameworks/base/cmds/bootanimation/bootanimation_main.cpp

int main(){    // 提升进程调度优先级为显示级,保障动画流畅    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);    // 读取系统属性,判断是否禁用开机动画    bool noBootAnimation = bootAnimationDisabled();    ALOGI_IF(noBootAnimation,  "boot animation disabled");    if(!noBootAnimation) {        // 初始化Binder线程池,后续与SF、WMS通信依赖Binder        sp<ProcessState> proc(ProcessState::self());        ProcessState::self()->startThreadPool();        // 实例化开机动画核心类,加载/system/media/bootanimation.zip,初始化音频回调        sp<BootAnimation> boot = new BootAnimation(audioplay::createAnimationCallbacks());        // 阻塞等待SurfaceFlinger服务Binder通道可用        waitForSurfaceFlinger();        // 启动动画子线程,主线程阻塞等待播放完成        boot->run("BootAnimation", PRIORITY_DISPLAY);        ALOGV("Boot animation set up. Joining binder thread pool.");        // 动画播放结束,主线程进入Binder循环,维持进程不立即销毁        IPCThreadState::self()->joinThreadPool();    }    return 0;}

辅助判断函数 bootAnimationDisabled ()

boolbootAnimationDisabled() {    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");    if (atoi(value) > 0) {        // 静默开机仅在对应开关开启时才显示动画        if (!property_get_bool("ro.bootanim.quiescent.enabled"false)) {            return true;        }    }    return false;}

二、BootAnimation 线程执行时序:readyToRun → threadLoop 完整流程

BootAnimation 继承系统 Thread 基类,boot->run() 内部会创建独立 pthread 子线程,底层静态入口 _threadLoop 执行固定两步逻辑:

  1. 优先执行 readyToRun():一次性初始化 EGL、多屏幕 Surface、着色器、渲染环境;
  2. 初始化无异常才进入 do-while 循环,反复执行 threadLoop() 播放动画。

完整时序图

boot->run("BootAnimation", PRIORITY_DISPLAY);    Thread::run() → pthread_create 创建独立动画子线程        底层静态入口 _threadLoop()            第一步:BootAnimation::readyToRun()                mAssets.addDefaultAssets();                initDisplaysAndSurfaces() // 初始化多屏幕、EGL、图层Surface                返回 NO_ERROR 代表图形环境就绪            第二步:进入 do-while 循环,循环调用 threadLoop()                threadLoop()                    movie() // 加载zip动画资源                        playAnimation() // 逐帧渲染主逻辑                            每帧渲染末尾调用 checkExit() 检测退出属性

2.1 readyToRun ():动画播放前一次性图形环境初始化

路径:frameworks/base/cmds/bootanimation/BootAnimation.cpp

status_t BootAnimation::readyToRun() {    ATRACE_CALL();    // 注册系统资源加载路径,用于读取zip内图片、字体    mAssets.addDefaultAssets();    // 核心:初始化屏幕、EGL渲染上下文、Surface图层    return initDisplaysAndSurfaces();}

核心初始化 initDisplaysAndSurfaces ()

status_tBootAnimation::initDisplaysAndSurfaces(){    // 1. 通过SurfaceComposerClient获取本机所有物理屏幕ID    std::vector<PhysicalDisplayId> displayIds = SurfaceComposerClient::getPhysicalDisplayIds();    if (displayIds.empty()) {        SLOGE("Failed to get ID for any displays");        return NAME_NOT_FOUND;    }    // 多开机动画开关关闭时,只保留主屏,过滤所有外接副屏    if (!com::android::graphics::bootanimation::flags::multidisplay()) {        displayIds.erase(displayIds.begin() + 1, displayIds.end());    }    // 遍历所有有效屏幕,获取屏幕唯一Token保存    for (const auto id : displayIds) {        const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id);        if (!token.isValid()) {            SLOGE("Failed to get display token for display %" PRIu64, id.value);            return NAME_NOT_FOUND;        }        mDisplays.push_back({.displayToken = token});    }    // 全局EGL初始化,创建GLES2.0渲染上下文(所有屏幕共享一套GL上下文)    mEgl = eglGetDisplay(EGL_DEFAULT_DISPLAY);    eglInitialize(mEgl, nullptrnullptr);    EGLConfig config = getEglConfig(mEgl);    EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};    mEglContext = eglCreateContext(mEgl, config, nullptr, contextAttributes);    // 读取系统属性限制图层最大分辨率,防止超大折叠屏显存溢出    mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width"0);    mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height"0);    // 为每一块物理屏幕创建独立Surface图层与EGL渲染窗口    for (size_t displayIdx = 0; displayIdx < mDisplays.size(); displayIdx++) {        auto& display = mDisplays[displayIdx];        DisplayMode displayMode;        // 查询屏幕当前生效分辨率、刷新率        status_t error = SurfaceComposerClient::getActiveDisplayMode(display.displayToken, &displayMode);        if (error != NO_ERROR) return error;        ui::Size resolution = displayMode.resolution;        // 根据全局限制裁剪分辨率        resolution = limitSurfaceSize(resolution.width, resolution.height);        // 向SurfaceFlinger创建专属图层BootAnimation,像素格式RGB565不透明,节省显存        display.surfaceControl = session()->createSurface(                String8("BootAnimation"), resolution.width, resolution.height,                PIXEL_FORMAT_RGB_565, ISurfaceComposerClient::eOpaque);        // 将图层绑定到对应屏幕的LayerStack,输出画面至当前物理屏        configureDisplayAndLayerStack(display, ui::LayerStack::fromValue(displayIdx));        display.surface = display.surfaceControl->getSurface();        // 基于Native窗口创建EGL渲染表面,作为OpenGL绘制目标        display.eglSurface = eglCreateWindowSurface(mEgl, config, display.surface.get(), nullptr);        // 查询EGL表面实际宽高        EGLint w, h;        eglQuerySurface(mEgl, display.eglSurface, EGL_WIDTH, &w);        eglQuerySurface(mEgl, display.eglSurface, EGL_HEIGHT, &h);        // 绑定当前屏幕EGL上下文,后续GL绘制全部输出到此屏幕        if (eglMakeCurrent(mEgl, display.eglSurface, display.eglSurface, mEglContext) == EGL_FALSE) {            return NO_INIT;        }        display.initWidth = display.width = w;        display.initHeight = display.height = h;        mTargetInset = -1;        // 根据系统属性 ro.bootanim.set_orientation_<display_id> 旋转动画画面,适配平板横屏开机        rotateAwayFromNaturalOrientationIfNeeded(display);        // 初始化投影矩阵,用于动画居中、缩放、旋转变换        projectSceneToWindow(display);    }    // 注册屏幕热插拔、分辨率变化监听,动态适配画面    mDisplayEventReceiver = std::make_unique<DisplayEventReceiver>();    status_t status = mDisplayEventReceiver->initCheck();    SLOGE_IF(status != NO_ERROR, "DisplayEventReceiver init failed: %d", status);    // 将事件fd注册到主线程Looper,异步接收屏幕变更    mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT,                   new DisplayEventCallback(this), nullptr);    return NO_ERROR;}

本段核心价值

Framework(system_server、WMS、AMS)尚未启动时,仅依赖 SurfaceFlinger 即可完成图层、EGL 初始化,这也是开机动画能提前渲染的核心原因: BootAnimation 与 SF 均为 Native 独立进程,不依赖 Java 层系统服务。

2.2 threadLoop ():动画主循环入口

bool BootAnimation::threadLoop() {    ATRACE_CALL();    bool result;    // 预编译图片渲染着色器    initShaders();    // 判断是否存在bootanimation.zip资源    if(mZipFileName.empty()) {        ALOGD("No animation zip file, render default Android logo");        // 无自定义动画,渲染原生静态Android文字Logo        result = android(mDisplays.front());    } else {        // 标准流程:加载并播放zip逐帧动画        result = movie();    }    // 动画播放完毕,统一销毁全部图形资源    mCallbacks->shutdown();    // 解绑EGL上下文    eglMakeCurrent(mEgl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);    eglDestroyContext(mEgl, mEglContext);    // 释放所有屏幕EGL窗口与Surface图层    for(auto& display : mDisplays) {        eglDestroySurface(mEgl, display.eglSurface);        display.surface.clear();        display.surfaceControl.clear();    }    eglTerminate(mEgl);    eglReleaseThread();    // 终止Binder通信    IPCThreadState::self()->stopProcess();    return result;}

2.3 movie ():解析 zip 动画资源,配置渲染参数

boolBootAnimation::movie(){    ATRACE_CALL();    // 解析/system/media/bootanimation.zip,加载desc.txt分段配置、所有帧图片    if (mAnimation == nullptr) {        mAnimation = loadAnimation(mZipFileName);    }    if (mAnimation == nullptr)        return false;    // 递归初始化各分段音频播放回调,处理嵌套子动画    for (const Animation::Part& part : mAnimation->parts) {        if (part.animation != nullptr) {            mCallbacks->init(part.animation->parts);        }    }    mCallbacks->init(mAnimation->parts);    // 检测动画分段是否配置右上角时钟,初始化时钟渲染参数    bool anyPartHasClock = false;    for (size_t i = 0; i < mAnimation->parts.size(); i++) {        if (validClock(mAnimation->parts[i])) {            anyPartHasClock = true;            break;        }    }    if (!anyPartHasClock) {        mClockEnabled = false;    } else {        // 读取开关属性,控制时钟是否显示        mClockEnabled = android::base::GetBoolProperty(CLOCK_ENABLED_PROP, false);    }    // 检测GPU是否支持非2次幂纹理,适配各类图片素材    mUseNpotTextures = false;    String8 glExtensions((constchar*)glGetString(GL_EXTENSIONS));    if (glExtensions.contains("GL_OES_texture_npot")) {        mUseNpotTextures = true;    }    // 配置全局OpenGL混合、抗锯齿基础参数    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);    glDisable(GL_DITHER);    glDisable(GL_SCISSOR_TEST);    glEnable(GL_TEXTURE_2D);    glBindTexture(GL_TEXTURE_2D, 0);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);    // 加载时钟、开机进度条字体纹理    bool clockFontOk = false;    if (mClockEnabled) {        clockFontOk = (initFont(&mClockFont, "clockfont") == NO_ERROR);        if (!clockFontOk) mClockEnabled = false;    }    initFont(&mProgressFont, "progressfont");    // 时钟校准子线程,实时更新系统时间用于渲染    if (mClockEnabled && !mTimeIsAccurate) {        mTimeCheckThread = new TimeCheckThread(this);        mTimeCheckThread->run("BootAnimTime", PRIORITY_LOW);    }    // 初始化动态主题渐变着色器    if (mAnimation->dynamicColoringEnabled) {        initDynamicColorShaders();    }    // 核心:阻塞播放完整动画,逐帧渲染逻辑    playAnimation(*mAnimation);    // 动画播放完成,回收时钟校准子线程    if (mTimeCheckThread != nullptr) {        mTimeCheckThread->requestExit();        mTimeCheckThread->join();        mTimeCheckThread = nullptr;    }    // 释放时钟纹理显存    if (clockFontOk) {        glDeleteTextures(1, &mClockFont.textureId);    }    glDeleteTextures(1, &mProgressFont.textureId);    // 释放全部动画帧资源    releaseAnimation(mAnimation);    mAnimation = nullptr;    return false;}

2.4 playAnimation ():逐帧渲染核心逻辑(最关键循环)

boolBootAnimation::playAnimation(const Animation& animation){    ATRACE_CALL();    const size_t totalParts = animation.parts.size();    // 计算单帧标准间隔(纳秒),锁定动画FPS    nsecs_t frameIntervalNs = s2ns(1) / animation.fps;    SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms",          mShuttingDown ? "Shutdown" : "Boot"elapsedRealtime());    int fadeFrameCount = 0// 关机淡出帧计数    int lastProgress = 0;  // 开机进度条缓存值    int colorTransStart = animation.colorTransitionStart;    int colorTransEnd = animation.colorTransitionEnd;    // 第一层循环:遍历desc.txt定义的所有动画分段Part    for (size_t partIdx = 0; partIdx < totalParts; partIdx++) {        const Animation::Part& part = animation.parts[partIdx];        const size_t frameCountInPart = part.frames.size();        glBindTexture(GL_TEXTURE_2D, 0);        // 支持嵌套子zip动画,递归播放        if (part.animation != nullptr) {            playAnimation(*part.animation);            if (exitPending()) break;            continue;        }        // 第二层循环:控制分段循环次数(无限循环/指定次数/淡出收尾)        for (int loopIdx = 0;             part.loopCount == 0 || loopIdx < part.loopCount || fadeFrameCount > 0;             loopIdx++) {            // 检测是否需要终止当前分段            if (shouldStopPart(part, fadeFrameCount, lastProgress)) break;            // 动态主题属性延迟加载重试逻辑            if (animation.dynamicColoringEnabled && !mDynamicColorLoaded                && (part.useDynamicColor || part.postDynamicColor)) {                SLOGD("Reload dynamic color system props");                loadDynamicColors();                if (mDynamicColorLoaded) {                    int transLen = colorTransEnd - colorTransStart;                    if (part.postDynamicColor) {                        colorTransStart = 0;                        colorTransEnd = std::min(transLen, (int)frameCountInPart - 1);                    }                }            }            // 触发当前分段配套音频播放            mCallbacks->playPart(partIdx, part, loopIdx);            // 设置分段背景清屏色            glClearColor(part.bgColor[0], part.bgColor[1], part.bgColor[2], 1.0f);            bool drawProgressBar = animation.progressEnabled                    && partIdx == totalParts - 1                    && android::base::GetIntProperty(PROGRESS_PROP, 0) != 0;            // 第三层循环:遍历当前分段内所有图片帧            for (size_t frameIdx = 0; frameIdx < frameCountInPart; frameIdx++) {                if (shouldStopPart(part, fadeFrameCount, lastProgress)) break;                // 计算动态主题渐变系数 [0 ~ 1]                float colorProgress = part.useDynamicColor                    ? std::clamp(                        ((float)frameIdx - colorTransStart) / std::max(colorTransEnd - colorTransStart, 1.0f),                        0.0f1.0f)                    : (part.postDynamicColor ? 1.0f : 0.0f);                // 处理屏幕分辨率、热插拔事件                processDisplayEvents();                const Animation::Frame& frame = part.frames[frameIdx];                nsecs_t frameBeginTime = systemTime();                // 纹理复用逻辑:首次循环创建纹理,后续直接复用显存,避免重复解码                if (loopIdx > 0) {                    glBindTexture(GL_TEXTURE_2D, frame.textureId);                } else {                    if (part.loopCount != 1) {                        glGenTextures(1, &frame.textureId);                        glBindTexture(GL_TEXTURE_2D, frame.textureId);                    }                    int w, h;                    // 解码图片至纹理,保留原始Alpha通道不预乘                    loadTexture(frame.buffer, &w, &h, false);                }                // 收到退出信号且分段配置淡出动画,计算透明度衰减值                float fadeAlpha = 0.0f;                if (exitPending() && part.enableFadeOut) {                    fadeAlpha = (float)(++fadeFrameCount) / part.fadeTotalFrames;                    if (fadeFrameCount >= part.fadeTotalFrames) {                        fadeFrameCount = MAX_FADE_FRAME;                    }                }                // 多屏幕循环:逐屏绘制当前帧                for (const auto& display : mDisplays) {                    // 切换EGL渲染目标至当前屏幕                    eglMakeCurrent(mEgl, display.eglSurface, display.eglSurface, mEglContext);                    // 计算画面缩放比例,实现居中适配屏幕                    float scaleW = (float)display.width / display.originalWidth;                    float scaleH = (float)display.height / display.originalHeight;                    int animBaseX = (display.width - animation.width * scaleW) / 2;                    int animBaseY = (display.height - animation.height * scaleH) / 2;                    // 帧裁剪坐标缩放换算                    int cropW = frame.cropW * scaleW;                    int cropH = frame.cropH * scaleH;                    int cropX = frame.cropX * scaleW;                    int cropY = frame.cropY * scaleH;                    int drawX = animBaseX + cropX;                    // OpenGL Y轴倒置,修正绘制纵坐标                    int drawY = display.height - (animBaseY + cropY + cropH);                    // 初始化正交投影矩阵                    projectSceneToWindow(display);                    glClear(GL_COLOR_BUFFER_BIT);                    // 绑定图片着色器,传入渐变、淡出透明度参数                    glUseProgram(mImageShaderProgram);                    glUniform1i(mTexLoc, 0);                    glUniform1f(mFadeLoc, fadeAlpha);                    if (animation.dynamicColoringEnabled) {                        glUniform1f(mColorProgressLoc, colorProgress);                    }                    glEnable(GL_BLEND);                    // 绘制带纹理矩形(核心图片渲染)                    drawTexturedRect(drawX, drawY, cropW, cropH, display);                    glDisable(GL_BLEND);                    // 叠加绘制右上角时钟文字                    if (mClockEnabled && mTimeIsAccurate && validClock(part)) {                        drawClockText(mClockFont, part.clockX, part.clockY, display);                    }                    // 叠加绘制底部开机进度百分比                    if (drawProgressBar) {                        int newProgress = android::base::GetIntProperty(PROGRESS_PROP, 0);                        if (lastProgress != 100) {                            usleep(100000); // 放慢进度条刷新速度,避免跳动过快                            if (lastProgress < newProgress) lastProgress++;                        }                        drawProgressText(lastProgress, mProgressFont, TEXT_CENTER, animation.height / 3, display);                    }                    // 交换前后双缓冲,画面输出到物理屏幕                    eglSwapBuffers(mEgl, display.eglSurface);                }                // 帧间隔休眠,锁定FPS,防止动画加速播放                nsecs_t now = systemTime();                nsecs_t sleepNs = frameIntervalNs - (now - frameBeginTime);                if (sleepNs > 0) {                    struct timespec sleepSpec;                    sleepSpec.tv_sec = (now + sleepNs) / 1000000000;                    sleepSpec.tv_nsec = (now + sleepNs) % 1000000000;                    int ret;                    // 绝对单调时钟休眠,被信号中断自动重试                    do {                        ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleepSpec, nullptr);                    } while (ret == EINTR);                }                // 每帧渲染完成,检测是否收到退出指令(核心退出检测入口)                checkExit();            }            // 当前分段所有帧播放完毕,执行分段暂停pause            int pauseUs = part.pauseFrameCount * ns2us(frameIntervalNs);            while (pauseUs > 0 && !exitPending()) {                if (pauseUs > MAX_CHECK_INTERVAL_US) {                    usleep(MAX_CHECK_INTERVAL_US);                    pauseUs -= MAX_CHECK_INTERVAL_US;                } else {                    usleep(pauseUs);                    break;                }                // 休眠中途持续检测退出信号                checkExit();            }            // 收到退出信号,无限循环分段强制置进度100并跳出            if (exitPending() && part.loopCount == 0 && mCurrentInset >= mTargetInset && !part.enableFadeOut) {                if (lastProgress != 0 && lastProgress != 100) {                    android::base::SetProperty(PROGRESS_PROP, "100");                    continue;                }                break;            }        }    }    // 动画全部播放完成,批量释放循环帧纹理,释放GPU显存    for (const Animation::Part& part : animation.parts) {        if (part.loopCount != 1) {            for (const auto& frame : part.frames) {                glDeleteTextures(1, &frame.textureId);            }        }    }    SLOGD("%sAnimationShownTiming end time: %" PRId64 "ms",          mShuttingDown ? "Shutdown" : "Boot"elapsedRealtime());    return true;}

2.5 退出检测核心函数 checkExit ()

voidBootAnimation::checkExit(){    ATRACE_CALL();    char propValue[PROPERTY_VALUE_MAX];    // 读取全局退出标记属性 service.bootanim.exit    property_get("service.bootanim.exit", propValue, "0");    int exitFlag = atoi(propValue);    if (exitFlag != 0) {        // 标记线程需要退出,下一轮循环执行淡出收尾        requestExit();    }}

核心逻辑:每一帧渲染结束都会同步读取共享内存中的系统属性,一旦值为 1,标记线程退出,后续执行淡出过渡动画,不会直接强制杀进程,保证画面过渡顺滑。

三、开机动画退出完整链路:Launcher 就绪 → 设置退出属性

3.1 起点:Launcher 主线程 Idle 回调上报 activityIdle

Launcher 作为系统首个前台 Activity,完成 onResume、布局渲染后,ActivityThread 消息队列无待处理 UI 任务,触发 Idler 空闲处理器。

文件路径:frameworks/base/core/java/android/app/ActivityThread.java

private class Idler implements MessageQueue.IdleHandler {    @Override    public final boolean queueIdle() {        boolean stopProfiling = false;        if (mBoundApplication != null && mProfiler.profileFd != null                && mProfiler.autoStopProfiler) {            stopProfiling = true;        }        final ActivityClient ac = ActivityClient.getInstance();        // 批量上报所有Resume完成的页面空闲状态        while (mNewActivities.size() > 0) {            final ActivityClientRecord record = mNewActivities.remove(0);            if (localLOGV) {                Slog.v(TAG, "Report idle activity " + record                        + " finished=" + (record.activity != null && record.activity.mFinished));            }            // 页面有效则跨Binder通知ATMS页面进入空闲            if (record.activity != null && !record.activity.mFinished) {                ac.activityIdle(record.token, record.createdConfig, stopProfiling);                record.createdConfig = null;            }        }        if (stopProfiling) {            mProfiler.stopProfiling();        }        // 返回false,执行一次后销毁,不重复触发        return false;    }}

触发时机:handleResumeActivity() 末尾通过 Looper.myQueue().addIdleHandler(new Idler()) 注册。

3.2 客户端 Binder 转发 ActivityClient.java

public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {    try {        // 调用IActivityTaskManager Binder接口,转发至系统端ActivityClientController        getActivityTaskManager().activityIdle(token, config, stopProfiling);    } catch (RemoteException e) {        e.rethrowFromSystemServer();    }}

3.3 系统端接收入口 ActivityClientController.java

路径:frameworks/base/services/core/java/com/android/server/wm/ActivityClientController.java

public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {    final long origCallingId = Binder.clearCallingIdentity();    try {        synchronized (mGlobalLock) {            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "activityIdle");            // 根据页面Token查询服务端Activity记录            final ActivityRecord r = ActivityRecord.forTokenLocked(token);            if (r == nullreturn;            // 转发至任务栈调度核心处理空闲逻辑            mTaskSupervisor.activityIdleInternal(r, falsefalse, config);            // 按需关闭性能采样器            if (stopProfiling && r.hasProcess()) {                r.app.clearProfilerIfNeeded();            }        }    } finally {        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);        Binder.restoreCallingIdentity(origCallingId);    }}

3.4 开机完成判定 ActivityTaskSupervisor.java

void activityIdleInternal(ActivityRecord r, boolean fromTimeout,        boolean processPausingActivities, Configuration config) {    // 省略页面暂停、内存回收、栈调度逻辑    // 核心判定:系统仍在开机 且 所有前台Resume页面全部空闲    if ((mService.isBooting() && mRootWindowContainer.allResumedActivitiesIdle())            || fromTimeout) {        checkFinishBootingLocked();    }    // 清除页面重启标记    r.mRelaunchReason = RELAUNCH_REASON_NONE;}private void checkFinishBootingLocked() {    boolean isBooting = mService.isBooting();    boolean enableScreen = false;    mService.setBooting(false);    // 首次完整开机,标记开机完成    if (!mService.isBooted()) {        mService.setBooted(true);        enableScreen = true;    }    if (isBooting || enableScreen) {        // 投递开机收尾任务至ATMS主线程Handler        mService.postFinishBooting(isBooting, enableScreen);    }}

关键判定 mRootWindowContainer.allResumedActivitiesIdle():遍历全局所有前台 Activity,必须全部完成渲染、进入空闲状态,才判定整机开机流程结束,避免动画提前消失导致黑屏。

3.5 ATMS 主线程分发任务 ActivityTaskManagerService.java

void postFinishBooting(boolean finishBooting, boolean enableScreen) {    mH.post(() -> {        if (finishBooting) {            // 通知AMS完成开机,发送BOOT_COMPLETED广播、调度后台进程            mAmInternal.finishBooting();        }        if (enableScreen) {            // 联动WMS执行屏幕启用、关闭开机动画            mInternal.enableScreenAfterBoot(isBooted());        }    });}public void enableScreenAfterBoot(boolean booted) {    writeBootProgressEnableScreen(SystemClock.uptimeMillis());    // 调用WindowManagerService核心方法    mWindowManager.enableScreenAfterBoot();    synchronized (mGlobalLock) {        updateEventDispatchingLocked(booted);    }}

3.6 WMS 设置退出属性 WindowManagerService.java

publicvoidenableScreenAfterBoot() {    synchronized (mGlobalLock) {        if (mSystemBooted) return;        mSystemBooted = true;        hideBootMessagesLocked();        mPolicy.systemBooted();        // 执行关闭开机动画核心逻辑        performEnableScreen();    }}privatevoidperformEnableScreen() {    synchronized (mGlobalLock) {        // 省略屏幕亮度、输入设备初始化代码        if (!mBootAnimationStopped) {            // 核心:写入系统属性,通知BootAnimation退出            SystemProperties.set("service.bootanim.exit""1");            mBootAnimationStopped = true;        }    }}

3.7 SystemProperties 底层机制:Java → JNI → 属性共享内存

Java 层接口 SystemProperties.java

public static void set(@NonNullString key, @NullableString val) {    if (val != null && !key.startsWith("ro.") &&            val.getBytes(StandardCharsets.UTF_8).length > PROP_VALUE_MAX) {        throw new IllegalArgumentException("Property value too long");    }    if (TRACK_KEY_ACCESSonKeyAccess(key);    // 调用native底层方法    native_set(key, val);}

JNI 层实现 android_os_SystemProperties.cpp

voidSystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, jstring valJ){    ScopedUtfChars key(env, keyJ);    if (!key.c_str()) return;    std::optional<ScopedUtfChars> value;    if (valJ != nullptr) {        value.emplace(env, valJ);        if (!value->c_str()) return;    }    const char* valueStr = value ? value->c_str() : "";    errno = 0;    // 调用bionic库底层属性设置函数    bool success = !__system_property_set(key.c_str(), valueStr);    if (!success) {        if (errno != 0) {            jniThrowExceptionFmt(env, "java/lang/RuntimeException",                    "set prop %s=%s failed: %m", key.c_str(), valueStr);        } else {            jniThrowExceptionFmt(env, "java/lang/RuntimeException",                    "set prop %s=%s failed, check logcat", key.c_str(), valueStr);        }    }}

底层属性系统原理

  1. __system_property_set
     是 Bionic C 库提供接口,通过 Unix 域 Socket 向 PID=1 的 init 进程发送修改请求;
  2. init 进程校验权限后,修改全局共享内存 /dev/__properties__ 内属性值;
  3. 所有进程(包含独立的 bootanimation 进程)都会 mmap 这块共享内存,property_get() 直接内存读取,无需跨 Binder,读取速度极快,适合每帧高频轮询;
  4. BootAnimation 在 checkExit() 直接读取共享内存,实时感知 service.bootanim.exit 变更。

四、四大核心问题完整解答

1. 开机动画是谁启动的?

init 进程启动 SurfaceFlinger,SF 图形服务初始化完成后,通过 ctl.start bootanim 属性触发 init 拉起 /system/bin/bootanimation 独立 Native 进程。 进程配置在 bootanim.rc,默认 disabled,无法自启动,完全依赖 SurfaceFlinger 触发。

2. 为什么 Framework 未完全启动,动画就能显示?

BootAnimation、SurfaceFlinger 均为独立 Native 进程,运行在 Linux 用户态,不依赖 system_server、AMS、WMS 等 Java 层 Framework 服务。 仅需依赖底层图形硬件、EGL、BufferQueue 即可创建图层、渲染画面,因此在 Zygote、system_server 启动前就能播放动画。

3. SurfaceFlinger 和 BootAnimation 是什么关系?

  1. 依赖关系
    :BootAnimation 创建 Surface 图层、EGL 窗口、分配 GraphicBuffer 全部依赖 SurfaceFlinger,无 SF 则无法输出画面;
  2. 合成关系
    :BootAnimation 向 SF 提交专属不透明图层 Layer,SF 按最高 Z 序合成至屏幕;
  3. 启动时序
    :SF 先启动并初始化硬件,再主动拉起 BootAnimation;
  4. 进程隔离
    :两者是独立进程,通过 Binder 完成图层管理通信。

4. BootAnimation 如何知道什么时候退出?

  1. Launcher 全部加载、主线程空闲后,通过 activityIdle 上报 ATMS;
  2. ATMS 校验所有前台页面全部空闲,判定开机完成;
  3. WMS 调用 SystemProperties.set("service.bootanim.exit", "1") 修改全局共享内存属性;
  4. BootAnimation 每帧渲染末尾调用 checkExit() 读取该属性,检测到 1 后开启淡出动画,播放完毕释放全部图形资源,进程退出。

5. 动画结束后 Launcher 如何接管屏幕?

  1. BootAnimation 进程销毁,对应的 BootAnimation 专属 Layer 从 SurfaceFlinger 移除;
  2. Launcher 的 Window 由 WMS 管理,图层 Z 序低于动画图层,动画销毁后 SF 自动合成 Launcher 窗口、状态栏、导航栏图层;
  3. 多图层硬件合成(HWC)直接输出桌面画面至显示屏,无黑屏断层。

五、完整全链路时序总表

  1. Kernel 启动 → init 进程初始化属性共享内存;
  2. init 启动 SurfaceFlinger 图形服务;
  3. SF 初始化 EGL、显示硬件完成,设置 ctl.start bootanim
  4. init 拉起 bootanimation 二进制进程;
  5. bootanimation_main 初始化 Binder 线程池,阻塞等待 SF 就绪;
  6. BootAnimation::run 创建子线程,先执行 readyToRun 初始化多屏幕、EGL、Surface;
  7. 进入 threadLoop → movie → playAnimation 逐帧循环渲染,每帧调用 checkExit;
  8. init 启动 Zygote,fork system_server,启动 AMS/WMS/ATMS;
  9. AMS 拉起 Launcher 桌面 Activity;
  10. Launcher onResume 完成,主线程 Idle 上报 activityIdle;
  11. ATMS 判定所有前台页面空闲,投递任务至 WMS;
  12. WMS 设置 service.bootanim.exit=1
  13. BootAnimation 检测到退出标记,执行淡出动画,播放完毕释放 EGL/Surface 资源;
  14. bootanimation 进程销毁,SF 移除动画图层,Launcher 窗口图层正常合成显示桌面。
基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-23 07:05:48 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/864365.html
  2. 运行时间 : 0.389702s [ 吞吐率:2.57req/s ] 内存消耗:4,861.32kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=53d1e3441d6c30263fd751a8de5c6e12
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000887s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001476s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.019993s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000717s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.001605s ]
  6. SELECT * FROM `set` [ RunTime:0.000680s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.001599s ]
  8. SELECT * FROM `article` WHERE `id` = 864365 LIMIT 1 [ RunTime:0.027880s ]
  9. UPDATE `article` SET `lasttime` = 1784761548 WHERE `id` = 864365 [ RunTime:0.027132s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.005063s ]
  11. SELECT * FROM `article` WHERE `id` < 864365 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.012322s ]
  12. SELECT * FROM `article` WHERE `id` > 864365 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.027230s ]
  13. SELECT * FROM `article` WHERE `id` < 864365 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.059598s ]
  14. SELECT * FROM `article` WHERE `id` < 864365 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.068993s ]
  15. SELECT * FROM `article` WHERE `id` < 864365 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.040346s ]
0.391413s