从一份 logcat 看懂 B 站冷启动:红米手机上的完整启动链路解析
本文基于一台红米手机(设备代号
rodin,HyperOS,联发科平台)上抓取的真实 logcat,逐步还原哔哩哔哩(tv.danmaku.bili)从进程不存在到首帧上屏、再到各子进程拉起的完整过程。每个阶段都附上原始日志与对应分析,可作为 Android 应用启动分析的参考样例。
一、测试背景与日志说明
- 设备:红米手机,代号
rodin,HyperOS(MIUI 系),MTK 平台,屏幕 1220×2712,density 520。 - 应用:哔哩哔哩
tv.danmaku.bili,uid 10294,targetSdkVersion 35。 - 触发方式:通过 Monkey 发起 Launcher 启动(相当于自动化"点击桌面图标")。
- 日志范围:本次启动发生在
20:03:46 ~ 20:04:02,恰好完整落在 main/system buffer 保留窗口内,因此进程、Application、Activity 的细节日志都在。
为什么能确定是冷启动?两条证据:
- 当天下午 15:52,B 站所有进程被"上滑清理"杀光,此后再无启动记录,直到本次启动:
10-24 15:52:09.535 1883 2003 I am_kill : [0,19408,tv.danmaku.bili:ijkservice,400,stop tv.danmaku.bili due to SwipeUpClean,178428] 10-24 15:52:09.540 1883 2003 I am_kill : [0,10726,tv.danmaku.bili:web,400,stop tv.danmaku.bili due to SwipeUpClean,424060] 10-24 15:52:09.544 1883 2003 I am_kill : [0,26320,tv.danmaku.bili:download,0,stop tv.danmaku.bili due to SwipeUpClean,152848] 10-24 15:52:09.548 1883 2003 I am_kill : [0,28355,tv.danmaku.bili,50,stop tv.danmaku.bili due to SwipeUpClean,756636]- 启动后 B 站自己的埋点也明确上报了冷启动:
10-24 20:03:47.844 16138 16138 E DurationManager: dau reportForeground, isColdStart: true, ascribeCallback: com.bilibili.gripper.container.dau.c$b@484c07c二、启动全流程总览
Monkey(shell) 发起 MAIN/LAUNCHER Intent ↓ ATMS/ActivityStarter:新建 task#316、冷启动加速、暂停 Launcher、显示 Splash 启动窗 ↓ AMS → Zygote fork 主进程 16138(am_proc_start) ↓ attachApplication(am_proc_bound)→ ActivityThread/ClassLoader 初始化 ↓ ContentProvider 安装 + Application 初始化(B站 Gripper 框架分段并行) ↓ MainActivityV2 onCreate(198ms) → onStart(11ms) → onResume(9ms) ↓ 首帧绘制 → Displayed +822ms → 移除 Splash → 获得输入焦点 ↓ 首屏后按需拉起子进程:ijkservice → download → webview sandbox → :web(小程序)三、逐阶段日志解析
1. 启动触发:Monkey 代替手指点击图标
10-24 20:03:46.695 9494 9494 W Monkey : args: [-p, tv.danmaku.bili, -c, android.intent.category.LAUNCHER, 1] 10-24 20:03:47.025 1883 2942 I ActivityTaskManager: setActivityController mController=android.app.IActivityController$Stub$Proxy@cfa0ecc, imAMonkey=true, CallingPid=9494 CallingUid=2000 10-24 20:03:47.104 1883 2644 I ActivityTaskManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=tv.danmaku.bili/.MainActivityV2} with LAUNCH_SINGLE_TOP from uid 2000 from pid 9494 callingPackage com.android.shell (BAL_ALLOW_PERMISSION) result code=0分析:Monkey(pid 9494,shell uid 2000)向 system_server(pid 1883)发起MAIN + LAUNCHER启动请求,目标组件是tv.danmaku.bili/.MainActivityV2——这就是 B 站桌面入口 Activity。result code=0表示启动请求被接受。注意 flag0x10200000(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED),是标准的桌面启动组合。
2. AMS 调度:新建 Task、冷启动加速、准备启动窗
10-24 20:03:47.085 1883 2644 I ActivityStarterImpl: boost cold start activity for tv.danmaku.bili 10-24 20:03:47.088 1883 2644 I wm_task_created: 316 10-24 20:03:47.097 1883 2644 I wm_create_activity: [0,144739032,316,tv.danmaku.bili/.MainActivityV2,android.intent.action.MAIN,NULL,NULL,270532608] 10-24 20:03:47.098 1883 2644 I wm_pause_activity: [0,216153653,com.miui.home/.launcher.Launcher,userLeaving=true,pauseBackTasks] 10-24 20:03:47.097 1883 2644 I WindowManager: Try to add startingWindow type = STARTING_WINDOW_TYPE_SPLASH_SCREEN this = ActivityRecord{144739032 u0 tv.danmaku.bili/.MainActivityV2 t316} ... 10-24 20:03:47.098 1883 2231 D PreStartingManager: Get background color: fff8f8f8 key: tv.danmaku.bili_night containColor: true 10-24 20:03:47.122 1883 2231 D PreStartingManager: The real or pre StartingWindow has been displayed. pkg: tv.danmaku.bili分析:
- HyperOS 识别到冷启动,执行
boost cold start(CPU/IO 等加速策略)。 - 为 B 站新建task#316,并创建 MainActivityV2 的 ActivityRecord。
- 旧前台
com.miui.home(桌面)进入 pause。 - 在应用进程还没创建之前,系统先贴出Splash 启动窗(背景色
fff8f8f8),避免"点击后白屏/无响应"的体感。这一步是系统做的,不依赖应用任何代码。
3. 进程创建:Zygote fork 与 attach 绑定
10-24 20:03:47.131 1883 1988 I am_proc_start: [0,16138,10294,tv.danmaku.bili,next-top-activity,{tv.danmaku.bili/tv.danmaku.bili.MainActivityV2}] 10-24 20:03:47.132 1883 1988 I ActivityManager: Start proc 16138:tv.danmaku.bili/u0a294 for next-top-activity {tv.danmaku.bili/tv.danmaku.bili.MainActivityV2} caller=com.android.shell 10-24 20:03:47.132 16138 16138 E Zygote : process_name_ptr:16138 tv.danmaku.bili 10-24 20:03:47.133 16138 16138 E Zygote : SetMemoryProtected process_name_ptr:16138 tv.danmaku.bili 10-24 20:03:47.137 16138 16138 I tv.danmaku.bili: Using CollectorTypeCC GC. 10-24 20:03:47.140 16138 16138 E tv.danmaku.bili: Not starting debugger since process cannot load the jdwp agent. 10-24 20:03:47.150 1883 3057 I am_proc_bound: [0,16138,tv.danmaku.bili] 10-24 20:03:47.159 16138 9529 D nativeloader: Configuring clns-10 for other apk ... target_sdk_version=35 ... library_path=/data/app/~~<random>/tv.danmaku.bili-<random>/lib/arm64:...分析:
am_proc_start的 hosting type 是next-top-activity,即"为了即将置顶显示的 Activity 而创建进程",是冷启动的典型标志。- AMS 通过 Zygote fork 出 pid16138,新进程立刻设置进程名、GC 类型(CC 并发拷贝回收);release 包不加载 jdwp 调试代理,属正常日志。
- 仅19ms后(47.131→47.150)进程完成
attachApplication,am_proc_bound表示进程与 AMS 绑定成功,随后进入 ActivityThread 初始化:配置 ClassLoader/native 库路径(targetSdk 35)、HWUI 渲染环境等。
4. Application 初始化:B 站 Gripper 启动框架(全程最重的阶段)
bind 之后到 Activity 创建之前,应用要完成自己的 Application 初始化。B 站使用自研的Gripper启动框架,把初始化任务拆成attach和onCreate等阶段,并用协程线程池(DefaultDispatcher-worker-N)并行执行:
10-24 20:03:47.219 16138 16138 W tv.danmaku.bili: Unsupported class loader: java.lang.Class<com.bilibili.lib.tribe.core.internal.loader.DefaultClassLoaderService$PathRootClassLoader> 10-24 20:03:47.430 16138 16138 I FastTriggerStrategy: [main] direTrigger: boot_opt_attach_seg 10-24 20:03:47.430 16138 9557 I FastTriggerStrategy: [DefaultDispatcher-worker-6] trigger: preOnAttach 10-24 20:03:47.430 16138 9555 I FastTriggerStrategy: [DefaultDispatcher-worker-4] trigger: OnAttach 10-24 20:03:47.444 16138 16138 I GripperExecute: direAsyncTrigger boot_opt_onCreate_seg 0 10-24 20:03:47.445 16138 16138 I GripperExecute: [main] onOnContentProviderAttachInfo: com.bilibili.gripper.AppInitProvider@1cd59bf 10-24 20:03:47.445 16138 16138 I GripperExecute: [main] onOnContentProviderAttachInfo: com.huawei.hms.aaid.InitProvider@2f5b178 10-24 20:03:47.446 16138 16138 I GripperExecute: [main] onOnContentProviderAttachInfo: com.bilibili.lib.downloader.p2p.P2PProvider@15f28cb 10-24 20:03:47.553 16138 16138 I GripperExecute: awaitTrigger boot_opt_onCreate_seg 55与此同时,若干基础组件在做预加载,例如配置中心与闪屏(开屏)资源:
10-24 20:03:47.279 16138 9552 I DDLib : [DefaultDispatcher-worker-1] preloadProdData:execute start 10-24 20:03:47.326 16138 9552 I DDLib : [DefaultDispatcher-worker-1] execute DataCenter preloadProdData cost 52 ms 10-24 20:03:47.318 16138 9554 I StartupOptimize: Splash image preloaded successfully 10-24 20:03:47.377 16138 9553 I SplashListResponseKit: readSplashListResponseFromDisk 111分析:
tribe是 B 站的插件化/类加载组件,自定义 ClassLoader 在 Application 最早期就介入。- 大量 ContentProvider 在
attachBaseContext之后被系统自动安装(AppInitProvider、华为 HMS、P2P、免流、下载等),这是冷启动隐藏的耗时来源之一。 - Gripper 的关键分段点:
boot_opt_attach_seg(Application.attach)→preOnAttach/OnAttach(并行任务)→boot_opt_onCreate_seg(Application.onCreate),awaitTrigger ... 55表示主线程等待 onCreate 段并行任务收尾约 55ms。 - 这一大段(47.150 绑定 → 47.574 Activity 开始初始化)约 424ms,占整个启动耗时的一半以上,是冷启动优化最值得关注的部分。
5. MainActivityV2 生命周期:onCreate → onStart → onResume
10-24 20:03:47.574 16138 16138 I GripperExecute: onActivityInit: tv.danmaku.bili.MainActivityV2 10-24 20:03:47.740 16138 16138 I GripperExecute: direTrigger boot_opt_main_bk 121 10-24 20:03:47.762 16138 16138 I SplashListResponseKit: getSplashListResponse 0 10-24 20:03:47.784 16138 16138 I wm_on_create_called: [0,144739032,tv.danmaku.bili.MainActivityV2,performCreate,198] 10-24 20:03:47.796 16138 16138 I wm_on_start_called: [0,144739032,tv.danmaku.bili.MainActivityV2,handleStartActivity,11] 10-24 20:03:47.806 16138 16138 I wm_on_resume_called: [0,144739032,tv.danmaku.bili.MainActivityV2,RESUME_ACTIVITY,9] 10-24 20:03:47.837 16138 16138 I wm_on_top_resumed_gained_called: [144739032,tv.danmaku.bili.MainActivityV2,topStateChangedWhenResumed]分析:
performCreate 198:MainActivityV2 的 onCreate 耗时198ms,其中 B 站自己的boot_opt_main_bk段就占121ms(首页/主界面业务初始化)。- onStart 11ms、onResume 9ms,都很轻。期间读取闪屏配置(
getSplashListResponse),与前面预加载的开屏资源呼应。 wm_on_*_called系列是系统 events buffer 的生命周期打点,最后一个数字就是耗时(ms),做启动分解时非常好用。
6. 首帧上屏:Displayed +822ms,Splash 退场
10-24 20:03:47.892 1883 1970 I WindowManager: onFirstWindowDrawn, try to remove startingWindow. ar: ActivityRecord{144739032 u0 tv.danmaku.bili/.MainActivityV2 t316} ... 10-24 20:03:47.902 1883 1928 I wm_activity_launch_time: [0,144739032,tv.danmaku.bili/.MainActivityV2,822] 10-24 20:03:47.906 1883 1928 I ActivityTaskManager: Displayed tv.danmaku.bili/.MainActivityV2 for user 0: +822ms 10-24 20:03:48.059 1883 1970 I WindowManager: StartingWindow exit animation finished, win = Window{2ba5538 u0 Splash Screen tv.danmaku.bili EXITING} remove = true 10-24 20:03:48.222 16138 16138 I input_focus: handleWindowFocusChanged:tv.danmaku.bili/tv.danmaku.bili.MainActivityV2 mView:com.android.internal.policy.DecorView{16b0a2d V.E...... R.....ID 0,0-1220,27...}分析:
- 47.892 应用首帧绘制完成,系统开始移除 Splash;
wm_activity_launch_time给出官方口径启动耗时822ms(从 startActivity 到首帧)。 - Splash 退出动画在 48.059 结束,48.222 窗口获得输入焦点,至此启动流程在系统层面闭环。
- 注意:Displayed 只代表"第一帧画出来了",不代表首页数据加载完成、可流畅交互。完全绘制应看
reportFullyDrawn(本日志未出现)。
7. 首屏之后:四大子进程陆续拉起
B 站是多进程架构,首帧之后各业务按需拉起独立进程:
10-24 20:03:48.229 1883 1988 I am_proc_start: [0,10109,10294,tv.danmaku.bili:ijkservice,service,{tv.danmaku.bili/tv.danmaku.ijk.media.player.services.IjkMediaPlayerRemoteService}] 10-24 20:03:49.349 1883 1988 I am_proc_start: [0,10576,10294,tv.danmaku.bili:download,service,{tv.danmaku.bili/com.bilibili.game.service.DownloadService}] 10-24 20:03:53.690 1883 1988 I am_proc_start: [0,10821,99150,com.google.android.webview:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:0,,{tv.danmaku.bili/org.chromium.content.app.SandboxedProcessService0:0}] 10-24 20:03:57.845 1883 1988 I am_proc_start: [0,10967,10294,tv.danmaku.bili:web,service,{tv.danmaku.bili/com.bilibili.lib.fasthybrid.SmallAppService}] 10-24 20:04:02.289 1883 1988 I am_proc_start: [0,11261,99151,com.google.android.webview:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:1,,{tv.danmaku.bili/org.chromium.content.app.SandboxedProcessService0:1}]分析:
| 时间 | 进程 | 作用 |
|---|---|---|
| 首帧 +0.3s | :ijkservice | ijkplayer 播放器独立进程,隔离播放崩溃/内存 |
| 首帧 +1.4s | :download | 游戏下载服务 |
| 首帧 +5.8s | WebView 沙箱进程 :0 | Chromium 渲染进程(WebView 初始化) |
| 首帧 +9.9s | :web | fasthybrid 小程序容器(SmallAppService) |
| 首帧 +14.4s | WebView 沙箱进程 :1 | 第二个渲染进程 |
这些进程都由service或 WebView 触发,而不是启动主链路必需,体现了"主进程先出首帧,重业务后置"的策略;但同时也意味着启动后十几秒内系统仍有持续的进程创建开销。
四、822ms 都花在哪了?
以系统Displayed口径(20:03:47.084 → 47.906)拆解:
| 阶段 | 时间段 | 耗时(约) | 占比 |
|---|---|---|---|
| AMS 调度/建 Task/Splash | 47.084 → 47.131 | 47ms | 6% |
| Zygote fork + attach 绑定 | 47.131 → 47.150 | 19ms | 2% |
| Application 初始化(Provider + Gripper) | 47.150 → 47.574 | 424ms | 52% |
| Activity onCreate/onStart/onResume | 47.574 → 47.806 | 232ms(onCreate 198ms,其中业务段 121ms) | 28% |
| 首帧绘制与上屏 | 47.806 → 47.906 | 100ms | 12% |
结论与观察:
- Application 初始化是冷启动最大头(超过一半)。B 站已经用了 Gripper 分段 + 协程并行 + 数据预加载来压缩它,但 Provider 数量、并行任务收尾等待(await 55ms)仍是可观开销。
- Activity 侧耗时集中在
boot_opt_main_bk(121ms)的首页业务初始化。 - 系统侧开销(fork、调度、启动窗)合计不到 70ms,优化空间主要在应用自身。
- 若要做完整体验评估,还需补充
reportFullyDrawn、首页接口耗时与帧率数据,822ms 只是"首帧"而非"可用"。
五、附:日志抓取步骤(手工复现)
不用脚本,直接手工执行。开两个 CMD 窗口:
窗口 1 — 抓取应用启动流程日志
adb logcat -c adb logcat -b all -v threadtime > D:\download\logcat.txt光标会停在这里等待输出,先不要动。
窗口 2 — 冷启动哔哩哔哩
adb shell am force-stop tv.danmaku.bili timeout /t 2 adb shell monkey -p tv.danmaku.bili -c android.intent.category.LAUNCHER 1等手机上哔哩哔哩完全打开(开屏广告放完、首页刷出来,约 20~30 秒)。
回到窗口 1 — 停止抓取
Ctrl + C窗口 2 — 抓内核日志
adb shell dmesg > D:\download\kernel.txt说明:
adb logcat -c先清空环形缓冲区,保证抓到的基本是本次启动的日志;-b all同时抓 main/system/events/radio 等所有 buffer;-v threadtime输出带日期、时间、PID/TID 的格式,即本文分析所用格式。force-stop确保是冷启动,monkey -c LAUNCHER 1模拟点击桌面图标。若 logcat.txt 是 UTF-16 编码,分析前需先转成 UTF-8,由于手机没有root权限无法抓取,在抓取日志的报了Permission denied错误,要抓取内核,得有root权限,所有分析的日志都是红米系统日志,没有内核的日志。
六、附:本次分析用到的检索命令
在日志,检索过滤可用到这些日志,一个是在Linux环境中,另外是在windows环境中,下图是过滤后的样子:
# Linux环境中:# 进程创建/绑定/查杀grep-nE'am_proc_start|am_proc_bound|am_kill'logcat.txt|grepbili# Activity 启动请求与首帧耗时grep-nE'START u0|wm_activity_launch_time|Displayed'logcat.txt|grepbili# Activity 生命周期耗时grep-nE'wm_on_(create|start|resume)_called'logcat.txt|grepMainActivityV2# B站 Gripper 启动框架分段打点grep-nE'FastTriggerStrategy|GripperExecute|GripperTime'logcat.txt# 主进程主线程行为(pid 换成实际的)grep-E' 16138 16138 'logcat.txt# --------------------------------------------# windows环境中:# 进程创建/绑定/查杀findstr /n /i /c:"am_proc_start"/c:"am_proc_bound"/c:"am_kill"logcat.txt|findstr /i"bili"# Activity 启动请求与首帧耗时findstr /n /i /c:"START u0"/c:"wm_activity_launch_time"/c:"Displayed"logcat.txt|findstr /i"bili"# Activity 生命周期耗时findstr /n /i /c:"wm_on_create_called"/c:"wm_on_start_called"/c:"wm_on_resume_called"logcat.txt|findstr /i"MainActivityV2"# B 站 Gripper 启动框架分段打点findstr /n /i /c:"FastTriggerStrategy"/c:"GripperExecute"/c:"GripperTime"logcat.txt# 主进程主线程行为(PID 换成实际的)findstr /n /c:" 16138 16138 "logcat.txt日志来源:红米 rodin / HyperOS,2026-10-24 20:03:46 ~ 20:04:02;全文日志均为原始抓取内容,对超长行做了截断。