:BootAnimation 启动流程解析——开机动画是如何显示出来的?)
上一篇我们完整梳理了 Launcher3 桌面启动全流程理解系统如何拉起桌面应用并渲染 UI。 但有一个直观问题容易被忽略从按下电源键到 Launcher 完整显示中间长达数秒的时间屏幕并非黑屏而是持续播放厂商定制开机动画完整链路为Google Logo 静态帧 → BootAnimation 逐帧动画 → Launcher 桌面本篇围绕 4 个核心问题结合完整 NativeJava 层源码拆解全链路开机动画进程由谁启动为何 Framework 服务未完全就绪时动画就能正常渲染输出SurfaceFlinger 与 BootAnimation 的依赖、协作关系是什么BootAnimation 如何精准感知退出时机动画结束后 Launcher 如何接管屏幕完整系统启动骨架链路init 进程 → SurfaceFlinger → BootAnimation → WindowManagerService → Launcher一、BootAnimation 进程启动源头init 配置与启动规则1.1 启动配置文件 bootanim.rc路径frameworks/base/cmds/bootanimation/bootanim.rcservice bootanim /system/bin/bootanimation class core animation user graphics group graphics audio disabled oneshot ioprio rt 0 task_profiles MaxPerformance关键配置释义disabled默认不会由 init 自动拉起必须由 SurfaceFlinger 初始化完成后通过属性ctl.start bootanim主动触发启动class core animation归属核心动画进程组系统关机时统一回收user/group graphics赋予图形、音频硬件访问权限保证 OpenGL 渲染、动画音效可用oneshot进程执行完成后自动销毁不会反复重启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.cppint main() { // 提升进程调度优先级为显示级保障动画流畅 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY); // 读取系统属性判断是否禁用开机动画 bool noBootAnimation bootAnimationDisabled(); ALOGI_IF(noBootAnimation, boot animation disabled); if (!noBootAnimation) { // 初始化Binder线程池后续与SF、WMS通信依赖Binder spProcessState proc(ProcessState::self()); ProcessState::self()-startThreadPool(); // 实例化开机动画核心类加载/system/media/bootanimation.zip初始化音频回调 spBootAnimation 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 ()bool bootAnimationDisabled() { 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执行固定两步逻辑优先执行readyToRun()一次性初始化 EGL、多屏幕 Surface、着色器、渲染环境初始化无异常才进入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.cppstatus_t BootAnimation::readyToRun() { ATRACE_CALL(); // 注册系统资源加载路径用于读取zip内图片、字体 mAssets.addDefaultAssets(); // 核心初始化屏幕、EGL渲染上下文、Surface图层 return initDisplaysAndSurfaces(); }核心初始化 initDisplaysAndSurfaces ()status_t BootAnimation::initDisplaysAndSurfaces() { // 1. 通过SurfaceComposerClient获取本机所有物理屏幕ID std::vectorPhysicalDisplayId 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, nullptr, nullptr); 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_uniqueDisplayEventReceiver(); 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; }本段核心价值Frameworksystem_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 动画资源配置渲染参数bool BootAnimation::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((const char*)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 ()逐帧渲染核心逻辑最关键循环bool BootAnimation::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.0f, 1.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 ()void BootAnimation::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 回调上报 activityIdleLauncher 作为系统首个前台 Activity完成 onResume、布局渲染后ActivityThread 消息队列无待处理 UI 任务触发Idler空闲处理器。文件路径frameworks/base/core/java/android/app/ActivityThread.javaprivate 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.javapublic 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.javapublic 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 null) return; // 转发至任务栈调度核心处理空闲逻辑 mTaskSupervisor.activityIdleInternal(r, false, false, config); // 按需关闭性能采样器 if (stopProfiling r.hasProcess()) { r.app.clearProfilerIfNeeded(); } } } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); Binder.restoreCallingIdentity(origCallingId); } }3.4 开机完成判定 ActivityTaskSupervisor.javavoid 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.javavoid 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.javapublic void enableScreenAfterBoot() { synchronized (mGlobalLock) { if (mSystemBooted) return; mSystemBooted true; hideBootMessagesLocked(); mPolicy.systemBooted(); // 执行关闭开机动画核心逻辑 performEnableScreen(); } } private void performEnableScreen() { synchronized (mGlobalLock) { // 省略屏幕亮度、输入设备初始化代码 if (!mBootAnimationStopped) { // 核心写入系统属性通知BootAnimation退出 SystemProperties.set(service.bootanim.exit, 1); mBootAnimationStopped true; } } }3.7 SystemProperties 底层机制Java → JNI → 属性共享内存Java 层接口 SystemProperties.javapublic static void set(NonNull String key, Nullable String 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_ACCESS) onKeyAccess(key); // 调用native底层方法 native_set(key, val); }JNI 层实现 android_os_SystemProperties.cppvoid SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, jstring valJ) { ScopedUtfChars key(env, keyJ); if (!key.c_str()) return; std::optionalScopedUtfChars 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); } } }底层属性系统原理__system_property_set是 Bionic C 库提供接口通过 Unix 域 Socket 向 PID1 的 init 进程发送修改请求init 进程校验权限后修改全局共享内存/dev/__properties__内属性值所有进程包含独立的 bootanimation 进程都会 mmap 这块共享内存property_get()直接内存读取无需跨 Binder读取速度极快适合每帧高频轮询BootAnimation 在checkExit()直接读取共享内存实时感知service.bootanim.exit变更。四、四大核心问题完整解答1. 开机动画是谁启动的init 进程启动 SurfaceFlingerSF 图形服务初始化完成后通过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 是什么关系依赖关系BootAnimation 创建 Surface 图层、EGL 窗口、分配 GraphicBuffer 全部依赖 SurfaceFlinger无 SF 则无法输出画面合成关系BootAnimation 向 SF 提交专属不透明图层 LayerSF 按最高 Z 序合成至屏幕启动时序SF 先启动并初始化硬件再主动拉起 BootAnimation进程隔离两者是独立进程通过 Binder 完成图层管理通信。4. BootAnimation 如何知道什么时候退出Launcher 全部加载、主线程空闲后通过activityIdle上报 ATMSATMS 校验所有前台页面全部空闲判定开机完成WMS 调用SystemProperties.set(service.bootanim.exit, 1)修改全局共享内存属性BootAnimation 每帧渲染末尾调用checkExit()读取该属性检测到 1 后开启淡出动画播放完毕释放全部图形资源进程退出。5. 动画结束后 Launcher 如何接管屏幕BootAnimation 进程销毁对应的 BootAnimation 专属 Layer 从 SurfaceFlinger 移除Launcher 的 Window 由 WMS 管理图层 Z 序低于动画图层动画销毁后 SF 自动合成 Launcher 窗口、状态栏、导航栏图层多图层硬件合成HWC直接输出桌面画面至显示屏无黑屏断层。五、完整全链路时序总表Kernel 启动 → init 进程初始化属性共享内存init 启动 SurfaceFlinger 图形服务SF 初始化 EGL、显示硬件完成设置ctl.start bootaniminit 拉起 bootanimation 二进制进程bootanimation_main 初始化 Binder 线程池阻塞等待 SF 就绪BootAnimation::run 创建子线程先执行 readyToRun 初始化多屏幕、EGL、Surface进入 threadLoop → movie → playAnimation 逐帧循环渲染每帧调用 checkExitinit 启动 Zygotefork system_server启动 AMS/WMS/ATMSAMS 拉起 Launcher 桌面 ActivityLauncher onResume 完成主线程 Idle 上报 activityIdleATMS 判定所有前台页面空闲投递任务至 WMSWMS 设置service.bootanim.exit1BootAnimation 检测到退出标记执行淡出动画播放完毕释放 EGL/Surface 资源bootanimation 进程销毁SF 移除动画图层Launcher 窗口图层正常合成显示桌面。