稳定性性能系列之九——启动性能优化:Boot、冷启动与热启动

启动速度,是用户对App的第一印象。慢一秒,可能就流失了一个用户。本文将带你系统化地攻克Android三种启动类型的性能优化难题。

引言

启动性能是影响用户体验的关键指标。根据Google的统计,启动时间每增加1秒,用户留存率会下降约5%。在实际项目中,启动耗时超过3秒的应用往往面临用户流失和业务压力。

典型的启动性能问题表现为:

  • 点击图标后出现白屏,持续1秒以上
  • Logo显示阶段耗时过长
  • 首页内容加载缓慢,用户需要等待3秒以上才能看到内容

面对启动性能问题,常见的优化思路包括:

  • Application初始化优化
  • Activity加载流程优化
  • 网络请求异步化
  • 首屏资源加载优化

然而,仅凭经验判断往往无法准确定位性能瓶颈。性能优化必须基于数据驱动,通过专业的性能分析工具定位问题。

本文将系统化地讲解Android三种启动类型的优化方法,帮助你也能实现从3秒到1秒的性能飞跃。

读完本文,你将学会:

  1. ✅ 区分System Boot、冷启动、热启动三种启动类型
  2. ✅ 使用Systrace/Perfetto精确测量启动性能
  3. ✅ 掌握Application、Activity、首屏渲染三阶段的优化技巧
  4. ✅ 学会System Boot的深度优化(内核、Init、Zygote、SystemServer)
  5. ✅ 建立CI/CD自动化启动性能监控体系
  6. ✅ 了解车机场景的特殊优化策略

一、启动类型详解:三种启动,三种策略

很多开发者会把"启动优化"笼统地当成一件事,但实际上Android的启动分为三种完全不同的类型,它们的触发场景、优化策略和性能基准都截然不同。

1.1 三种启动类型全面对比

启动类型 触发场景 进程状态 典型耗时 优化难度 主要优化点 关键指标
System Boot 设备开机 设备重启 系统从零启动 20-60秒 ⭐⭐⭐⭐⭐ BootLoader Kernel Init Zygote SystemServer boot_progress_*事件 ACTION_BOOT_COMPLETED
冷启动 App首次安装后启动 App被系统杀死后启动 设备重启后首次启动App 进程不存在 需要创建进程 1-5秒 ⭐⭐⭐⭐ Application Activity 首屏渲染 reportFullyDrawn() TotalTime指标
热启动 App从后台恢复 按Home后再打开 切换到其他App后返回 进程存在 Activity需重建 0.3-1秒 ⭐⭐⭐ Activity恢复 View状态恢复 数据刷新 onRestart() onResume()耗时

三者的本质区别:

  1. System Boot: 系统级启动,涉及硬件初始化、内核加载、系统服务启动,影响所有应用
  2. 冷启动: 进程级启动,从无到有创建进程、加载代码、初始化应用
  3. 热启动: Activity级启动,进程已存在,只需恢复Activity和UI状态

优化策略的差异:

  • System Boot需要从BootLoader、Kernel、Framework层面优化,需要系统级权限
  • 冷启动需要优化Application、Activity、渲染流程,应用开发者可控
  • 热启动主要优化Activity生命周期和数据恢复,相对简单

1.2 System Boot:系统启动的完整链路

System Boot是用户开机后到看到Launcher桌面的完整过程,涉及从硬件到软件的多个阶段。

启动流程图:

各阶段详解:

1. BootLoader阶段 (2-5秒)

  • 职责: 硬件自检、内存初始化、加载Kernel到内存
  • 关键文件 : aboot.img (Android BootLoader)
  • 优化空间: 有限,主要受硬件限制

2. Kernel阶段 (3-8秒)

  • 职责:

    • 初始化CPU、内存、I/O子系统
    • 加载设备驱动(显示、触摸、音频等)
    • 挂载根文件系统
    • 启动第一个用户空间进程 /init
  • 关键事件:

    bash 复制代码
    [    0.000000] Booting Linux on physical CPU 0x0
    [    1.234567] Freeing unused kernel memory: 1024K
    [    2.345678] init: init first stage started!
  • 优化空间: 中等,可精简驱动、优化挂载

3. Init阶段 (5-10秒)

  • 职责:

    • 解析并执行 init.rc 脚本
    • 创建文件系统挂载点
    • 启动属性服务 property_service
    • 启动守护进程:
      • servicemanager (Binder服务管理)
      • surfaceflinger (显示服务)
      • zygote (进程孵化器)
  • 关键代码:

    cpp 复制代码
    // system/core/init/init.cpp
    int main(int argc, char** argv) {
        // 解析init.rc
        Parser parser;
        parser.ParseConfig("/init.rc");
    
        // 启动服务
        ServiceList& sm = ServiceList::GetInstance();
        sm.StartServices();
    }
  • 优化空间: 大,可并行启动、延迟启动非关键服务

4. Zygote阶段 (2-5秒)

Zygote是所有App进程的"父进程",通过fork()机制快速创建新进程。

  • 职责:

    • 预加载常用类 (约5000个类)
    • 预加载系统资源
    • 创建JVM和ART运行时
    • 等待Socket连接(接收fork请求)
  • 关键代码:

    java 复制代码
    // frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
    public static void main(String argv[]) {
        // 预加载类
        preloadClasses();
    
        // 预加载资源
        preloadResources();
    
        // 预加载共享库
        preloadSharedLibraries();
    
        // 启动SystemServer
        forkSystemServer();
    
        // 进入Loop,等待创建App进程
        runSelectLoop();
    }
    
    private static void preloadClasses() {
        // 加载 /system/etc/preloaded-classes 中的类
        InputStream is = ClassLoader.getSystemResourceAsStream("preloaded-classes");
        // ... 加载约5000个类,耗时2-3秒
    }
  • 优化空间: 大,可精简预加载类列表

5. SystemServer阶段 (5-15秒)

SystemServer是Android系统的核心进程,运行着所有系统服务。

  • 职责:

    • 启动Bootstrap Services (核心服务):
      • ActivityManagerService (AMS)
      • PowerManagerService (PMS)
      • PackageManagerService (PMS)
    • 启动Core Services (必须服务):
      • BatteryService
      • UsageStatsService
    • 启动Other Services (其他服务):
      • WindowManagerService (WMS)
      • InputManagerService (IMS)
      • LocationManagerService
      • ...约80个服务
  • 关键代码:

    java 复制代码
    // frameworks/base/services/java/com/android/server/SystemServer.java
    private void run() {
        // 阶段1: 启动Bootstrap服务
        startBootstrapServices();
    
        // 阶段2: 启动Core服务
        startCoreServices();
    
        // 阶段3: 启动Other服务
        startOtherServices();
    
        // 进入Loop
        Looper.loop();
    }
    
    private void startBootstrapServices() {
        // 启动AMS
        mActivityManagerService = ActivityManagerService.Lifecycle.startService(
            mSystemServiceManager, atm);
    
        // 启动PMS
        mPackageManagerService = PackageManagerService.main(...);
    }
  • 优化空间: 最大,可分阶段启动、延迟启动

6. Launcher阶段 (3-5秒)

  • 职责: 显示桌面图标,响应用户点击
  • 关键指标 : ACTION_BOOT_COMPLETED 广播发送时间

Boot性能基准:

设备类型 优秀 良好 一般 较差
旗舰手机 < 20s 20-30s 30-40s > 40s
中端手机 < 25s 25-35s 35-45s > 45s
车载系统 < 10s 10-15s 15-20s > 20s

1.3 App冷启动:从点击到可见的全过程

冷启动是用户点击App图标后,系统创建进程、加载代码、初始化Application、启动Activity、渲染首屏的完整过程。

启动流程图:

复制代码
用户点击图标
   ↓
Launcher通知ActivityManagerService(AMS)
   ↓
AMS检查进程是否存在
   ↓
进程不存在,通知Zygote fork新进程
   ↓
Zygote fork进程 (100-300ms)
   ↓
新进程启动,加载Application
   ↓
Application.onCreate() 执行 (200-800ms)
   ├─ SDK初始化
   ├─ 数据库初始化
   └─ 配置加载
   ↓
AMS通知启动Activity
   ↓
Activity.onCreate() 执行 (300-1000ms)
   ├─ setContentView()
   ├─ 数据加载
   └─ UI初始化
   ↓
Activity.onStart() / onResume() 执行
   ↓
首帧渲染 (measure → layout → draw) (100-300ms)
   ↓
用户看到首屏!

耗时分布参考 (某电商App实测数据):

阶段 耗时 占比 可优化空间
fork进程 200ms 9% ❌ 系统控制
Application.onCreate() 800ms 38% ✅ 延迟/异步初始化
Activity.onCreate() 800ms 38% ✅ 异步加载/预加载
首屏渲染 300ms 14% ✅ 布局/图片优化
总计 2100ms 100% 优化到950ms

关键时间节点:

kotlin 复制代码
// 测量各阶段耗时
class MyApp : Application() {
    override fun onCreate() {
        val startTime = System.currentTimeMillis()
        super.onCreate()

        // 初始化操作
        initSDKs()

        val appTime = System.currentTimeMillis() - startTime
        Log.d("Performance", "Application耗时: ${appTime}ms")
    }
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val startTime = System.currentTimeMillis()
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 等待首帧渲染
        window.decorView.viewTreeObserver.addOnPreDrawListener(
            object : ViewTreeObserver.OnPreDrawListener {
                override fun onPreDraw(): Boolean {
                    window.decorView.viewTreeObserver.removeOnPreDrawListener(this)
                    val totalTime = System.currentTimeMillis() - startTime
                    Log.d("Performance", "Activity+首屏耗时: ${totalTime}ms")
                    return true
                }
            }
        )
    }
}

冷启动性能基准:

评级 耗时范围 用户体验 建议
✅ 优秀 < 1s 几乎无感知 保持,可作为标杆
⚠️ 良好 1-1.5s 轻微等待感 有优化空间
⚠️ 一般 1.5-2s 明显等待 需要优化
❌ 较差 2-3s 较长等待 必须优化
❌ 很差 > 3s 想关闭App 严重问题

1.4 App热启动:从后台恢复的快速路径

热启动是App进程已存在,只需恢复Activity和UI状态的快速启动方式。

启动流程图:

复制代码
用户从Recent或按返回键
   ↓
ActivityManagerService(AMS)检测到进程存在
   ↓
直接恢复Activity栈
   ↓
Activity.onRestart() 执行 (10-50ms)
   ↓
Activity.onStart() 执行 (10-50ms)
   ↓
Activity.onResume() 执行 (30-100ms)
   ├─ 刷新数据
   └─ 恢复UI状态
   ↓
View重建/更新 (50-150ms)
   ↓
首帧渲染 (50-100ms)
   ↓
用户看到界面!

耗时分布 (某社交App实测数据):

阶段 耗时 占比 可优化空间
onRestart() 20ms 4% ✅ 避免重复操作
onStart() 30ms 6% ✅ 缓存数据
onResume() 150ms 30% ✅ 异步刷新
View重建 200ms 40% ✅ 状态缓存
渲染更新 100ms 20% ✅ 局部刷新
总计 500ms 100% 优化到300ms

热启动性能基准:

评级 耗时范围 用户体验
✅ 优秀 < 300ms 即时响应
⚠️ 良好 300-500ms 轻微延迟
❌ 较差 > 500ms 明显卡顿

二、System Boot启动优化:系统级性能调优

System Boot优化主要针对系统开发者车载系统工程师,需要系统级权限和源码访问。普通App开发者可以跳过此节。

2.1 Boot性能分析方法

方法1: 使用Bootchart分析整体启动时间

Bootchart是Android提供的Boot性能分析工具,生成CPU、I/O、进程的时间图表。

开启Bootchart:

bash 复制代码
# 1. 开启bootchart (重启生效)
adb root
adb shell 'echo 1 > /data/bootchart/enabled'
adb reboot

# 2. 设备启动完成后,获取bootchart数据
adb pull /data/bootchart bootchart/

# 3. 生成PNG图表 (需要bootchart工具)
bootchart bootchart/

# 查看生成的 bootchart.png

Bootchart图表解读:

  • CPU使用率: 哪个进程占用CPU最多
  • I/O等待: 是否有I/O瓶颈
  • 进程启动顺序: 哪些进程启动早,哪些启动晚
  • 关键时间节点 : boot_progress_* 事件
方法2: 使用Systrace分析启动细节

Systrace可以抓取Boot过程的详细trace,分析每个服务的启动耗时。

抓取Boot Trace:

bash 复制代码
# 方法1: 开机时自动抓取 (需要修改init.rc)
# 在 init.rc 中添加:
on boot
    # 开启ftrace
    write /sys/kernel/debug/tracing/tracing_on 1
    write /sys/kernel/debug/tracing/events/sched/enable 1

# 方法2: 手动抓取重启后的trace
adb shell atrace --async_start -b 32768 -c \
    sched freq idle load disk mmc am wm gfx view dalvik

# 重启设备
adb reboot

# 启动完成后停止抓取
adb wait-for-device
adb shell atrace --async_stop -o /data/local/tmp/boot_trace.txt
adb pull /data/local/tmp/boot_trace.txt

# 使用Perfetto UI查看
# 打开 ui.perfetto.dev,上传trace文件

关键指标查看:

sql 复制代码
-- 在Perfetto UI的SQL查询中执行
-- 查看boot_progress事件的时间
SELECT
  ts / 1e9 AS time_sec,
  name,
  CAST(value AS TEXT) AS timestamp_ms
FROM counter
JOIN counter_track ON counter.track_id = counter_track.id
WHERE counter_track.name LIKE 'boot_progress%'
ORDER BY ts;
方法3: 使用logcat分析关键事件
bash 复制代码
# 过滤boot相关日志
adb logcat -d | grep -E "boot_progress|SystemServer"

# 输出示例:
# boot_progress_start: 12345
# boot_progress_preload_start: 15678
# boot_progress_preload_end: 18901
# boot_progress_system_run: 21234
# boot_progress_pms_start: 22345
# boot_progress_pms_ready: 28901
# boot_progress_ams_ready: 32345
# boot_progress_enable_screen: 35678

2.2 Kernel启动优化

优化1: 精简内核配置

移除不需要的功能:

bash 复制代码
# 编辑内核配置 kernel/.config
# 禁用不需要的功能可减少内核大小和启动时间

# 示例:禁用调试功能
CONFIG_DEBUG_KERNEL=n
CONFIG_DEBUG_INFO=n
CONFIG_KALLSYMS=n

# 禁用不需要的文件系统
CONFIG_BTRFS_FS=n
CONFIG_XFS_FS=n

# 禁用不需要的网络协议
CONFIG_NETFILTER=n
CONFIG_IPV6=n

# 重新编译内核
make -j8

实测效果: 节省1-2秒

优化2: 优化文件系统挂载

并行挂载分区:

bash 复制代码
# 修改 init.rc
# 优化前:串行挂载
on fs
    mount ext4 /dev/block/by-name/system /system
    mount ext4 /dev/block/by-name/vendor /vendor
    mount ext4 /dev/block/by-name/userdata /data

# 优化后:并行挂载
on fs
    exec - root -- /system/bin/sh -c "mount ext4 /dev/block/by-name/system /system &"
    exec - root -- /system/bin/sh -c "mount ext4 /dev/block/by-name/vendor /vendor &"
    mount ext4 /dev/block/by-name/userdata /data

使用noatime选项:

bash 复制代码
# 挂载时禁用atime(访问时间)更新,减少I/O
mount ext4 /dev/block/by-name/userdata /data noatime,nosuid,nodev

实测效果: 节省0.5-1秒

优化3: 延迟加载非关键驱动

修改驱动初始化顺序:

c 复制代码
// drivers/video/display_driver.c
// 优化前:device_initcall (启动阶段6)
device_initcall(display_driver_init);

// 优化后:late_initcall (启动阶段7,延后执行)
late_initcall(display_driver_init);

按需加载驱动:

c 复制代码
// 将驱动编译为模块,启动后再加载
// Kconfig
config DISPLAY_DRIVER
    tristate "Display Driver"  # 改为tristate而非bool

实测效果: 节省1-3秒

2.3 Init阶段优化

优化1: 并行启动服务
bash 复制代码
# init.rc
# 优化前:串行启动
on boot
    start serviceA
    start serviceB
    start serviceC

# 优化后:并行启动(使用&后台执行)
on boot
    exec - root -- /system/bin/sh -c "start serviceA &"
    exec - root -- /system/bin/sh -c "start serviceB &"
    exec - root -- /system/bin/sh -c "start serviceC &"
优化2: 延迟启动非关键服务
bash 复制代码
# init.rc
# 优化前:所有服务在boot阶段启动
on boot
    start critical_service
    start non_critical_service_1
    start non_critical_service_2

# 优化后:关键服务立即启动,非关键服务延后
on boot
    start critical_service

# Boot完成后再启动非关键服务
on property:sys.boot_completed=1
    start non_critical_service_1
    start non_critical_service_2
优化3: 精简init.rc
bash 复制代码
# 移除不需要的on触发器和exec命令
# 合并重复的属性设置
# 优化前:
on boot
    setprop prop1 value1
on boot
    setprop prop2 value2

# 优化后:
on boot
    setprop prop1 value1
    setprop prop2 value2

实测效果: Init阶段从10秒优化到6秒

2.4 Zygote启动优化

优化1: 精简预加载类列表
bash 复制代码
# 编辑预加载类列表
# frameworks/base/config/preloaded-classes

# 优化前:约5000个类
# 优化后:移除不常用的类,保留约3500个

# 分析方法:通过Systrace查看哪些类真正被使用
# 移除示例:
# android.bluetooth.*  # 如果设备无蓝牙
# android.nfc.*        # 如果设备无NFC
# com.android.internal.telephony.*  # 如果设备无电话功能

验证脚本:

bash 复制代码
#!/bin/bash
# 统计类的使用频率
adb logcat -c
adb logcat | grep "Class load" > class_usage.log
# 运行一天后分析
awk '{print $NF}' class_usage.log | sort | uniq -c | sort -nr > class_frequency.txt

实测效果: Zygote启动从5秒优化到3秒

优化2: 优化预加载资源
java 复制代码
// frameworks/base/core/java/android/app/ApplicationLoaders.java
private static void preloadResources() {
    // 优化前:预加载所有drawable
    Resources resources = Resources.getSystem();
    resources.preloadDrawables();

    // 优化后:只预加载常用drawable
    int[] commonDrawables = {
        android.R.drawable.ic_menu_add,
        android.R.drawable.ic_menu_delete,
        // ... 只列出最常用的100个
    };
    for (int id : commonDrawables) {
        resources.getDrawable(id, null);
    }
}

实测效果: 节省0.5-1秒

2.5 SystemServer启动优化

SystemServer是优化空间最大的环节,包含约80个系统服务。

优化1: 分阶段、分优先级启动服务
java 复制代码
// frameworks/base/services/java/com/android/server/SystemServer.java
private void run() {
    // 阶段1: Bootstrap Services (必须立即启动)
    startBootstrapServices();
    // AMS, PMS, PowerManager...

    // 阶段2: Core Services (必须服务,但可稍后)
    startCoreServices();
    // BatteryService, UsageStatsService...

    // 阶段3: Other Services (可延后启动)
    startOtherServices();
    // LocationManager, NetworkPolicy, MediaRouter...

    // 阶段4: 延迟服务 (Boot完成后启动)
    mHandler.postDelayed(() -> {
        startDelayedServices();
    }, 5000);
}

private void startDelayedServices() {
    // 非关键服务延后5秒启动
    // 例如:TelephonyRegistry, NetworkTime, Wallpaper...
}
优化2: 并行启动服务
java 复制代码
// SystemServer.java
private void startOtherServices() {
    // 优化前:串行启动
    startService(LocationManagerService.class);
    startService(NetworkPolicyManagerService.class);
    startService(MediaRouterService.class);

    // 优化后:并行启动(使用线程池)
    ExecutorService executor = Executors.newFixedThreadPool(4);

    executor.submit(() -> startService(LocationManagerService.class));
    executor.submit(() -> startService(NetworkPolicyManagerService.class));
    executor.submit(() -> startService(MediaRouterService.class));

    // 等待关键服务启动完成
    executor.shutdown();
    executor.awaitTermination(10, TimeUnit.SECONDS);
}
优化3: 延迟初始化服务内部逻辑
java 复制代码
// 示例: LocationManagerService
public class LocationManagerService extends ILocationManager.Stub {
    @Override
    public void systemReady() {
        // 优化前:systemReady时就加载所有Provider
        loadProviders();

        // 优化后:延迟加载,只加载必须的GPS Provider
        loadGpsProvider();

        // 其他Provider在首次使用时再加载
        mHandler.postDelayed(() -> {
            loadNetworkProvider();
            loadPassiveProvider();
        }, 10000);
    }
}

Boot优化效果总结:

优化项 优化前 优化后 节省时间
Kernel启动 8s 5s 3s ⬇️
Init阶段 10s 6s 4s ⬇️
Zygote启动 5s 3s 2s ⬇️
SystemServer启动 15s 9s 6s ⬇️
总Boot时间 48s 33s 15s ⬇️ (31%)

三、App冷启动优化:从3秒到1秒的实战

App冷启动是用户最常遇到的场景,也是优化效果最明显的领域。本节将提供完整的、可落地的优化方案。

3.1 冷启动性能测量

方法1: 使用adb命令快速测量
bash 复制代码
# 完全冷启动 (清除数据+force-stop)
adb shell am force-stop com.example.myapp
adb shell pm clear com.example.myapp

# 启动并测量时间
adb shell am start-activity -W com.example.myapp/.MainActivity

# 输出:
# Starting: Intent { act=android.intent.action.MAIN ... }
# Status: ok
# Activity: com.example.myapp/.MainActivity
# ThisTime: 1245        ← Activity启动耗时
# TotalTime: 1245       ← 总启动耗时 (这就是冷启动时间)
# WaitTime: 1267        ← 包括系统处理时间
# Complete
方法2: 使用Systrace精确分析
bash 复制代码
# 1. 清除App数据
adb shell am force-stop com.example.myapp
adb shell pm clear com.example.myapp

# 2. 后台启动systrace
python systrace.py -t 10 -o launch.html \
    sched freq gfx view wm am dalvik res \
    -a com.example.myapp &

# 3. 等待2秒让systrace准备好
sleep 2

# 4. 启动App
adb shell am start-activity -W com.example.myapp/.MainActivity

# 5. 打开trace分析
google-chrome launch.html

Trace中查找关键时间点:

  • bindApplication: Application开始创建
  • activityStart: Activity开始启动
  • Choreographer#doFrame: 首帧开始渲染
  • reportFullyDrawn: 应用自己上报的启动完成时间
方法3: 代码中精确计时
kotlin 复制代码
// MyApplication.kt
class MyApp : Application() {
    companion object {
        var appStartTime = 0L
        var appCreateTime = 0L
    }

    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(base)
        appStartTime = System.currentTimeMillis()
    }

    override fun onCreate() {
        super.onCreate()

        // Application初始化操作
        initSDKs()

        appCreateTime = System.currentTimeMillis() - appStartTime
        Log.d("LaunchTime", "Application.onCreate耗时: ${appCreateTime}ms")
    }
}

// MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val activityStartTime = System.currentTimeMillis()
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val activityCreateTime = System.currentTimeMillis() - activityStartTime
        Log.d("LaunchTime", "Activity.onCreate耗时: ${activityCreateTime}ms")

        // 等待首帧渲染完成
        window.decorView.viewTreeObserver.addOnPreDrawListener(
            object : ViewTreeObserver.OnPreDrawListener {
                override fun onPreDraw(): Boolean {
                    window.decorView.viewTreeObserver.removeOnPreDrawListener(this)

                    val totalTime = System.currentTimeMillis() - MyApp.appStartTime
                    val renderTime = System.currentTimeMillis() - activityStartTime

                    Log.d("LaunchTime", """
                        ==== 启动性能统计 ====
                        Application耗时: ${MyApp.appCreateTime}ms
                        Activity耗时: ${activityCreateTime}ms
                        首帧渲染耗时: ${renderTime - activityCreateTime}ms
                        总启动时间: ${totalTime}ms
                        ======================
                    """.trimIndent())

                    // 上报到服务器
                    reportLaunchTime(totalTime)

                    return true
                }
            }
        )
    }

    private fun reportLaunchTime(time: Long) {
        // 上报启动时间到Firebase/自建服务器
        FirebasePerformance.getInstance()
            .newTrace("cold_start")
            .apply {
                putMetric("duration_ms", time)
                start()
                stop()
            }
    }
}

3.2 Application.onCreate()优化

Application.onCreate()是冷启动的第一个瓶颈,很多开发者习惯在这里初始化各种SDK,导致启动缓慢。

反面案例:典型的慢Application
kotlin 复制代码
// ❌ 糟糕的Application实现
class BadApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // 问题1: 同步初始化多个第三方SDK (耗时500ms+)
        BuglySDK.init(this, "app_id", false)  // 180ms
        UmengSDK.init(this, "umeng_key")      // 150ms
        WeChatSDK.registerApp("wx_app_id")    // 200ms

        // 问题2: 同步数据库操作 (耗时150ms)
        DatabaseHelper.getInstance(this).init()

        // 问题3: 同步文件I/O (耗时100ms)
        ConfigManager.loadFromDisk(this)

        // 问题4: 复杂的初始化逻辑 (耗时200ms)
        initGlobalConfig()
        preloadAssets()

        // 总耗时: 1000ms+
        // 用户体验: 白屏1秒,很糟糕
    }
}
优化策略1: 延迟初始化 (Lazy Initialization)
kotlin 复制代码
// ✅ 优化后: 只初始化必须的
class GoodApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // 只初始化崩溃上报 (必须立即初始化,否则捕获不到早期崩溃)
        BuglySDK.init(this, "app_id", false)  // 180ms

        // 其他SDK在主线程空闲时初始化
        Looper.myQueue().addIdleHandler {
            Thread {
                delayedInit()
            }.start()
            false  // 只执行一次
        }

        // Application.onCreate耗时: 180ms (减少82%)
    }

    private fun delayedInit() {
        // 延迟5秒后初始化非关键SDK
        Thread.sleep(5000)
        UmengSDK.init(this, "umeng_key")
        WeChatSDK.registerApp("wx_app_id")
        DatabaseHelper.getInstance(this).init()
        ConfigManager.loadFromDisk(this)
    }
}

IdleHandler原理:

kotlin 复制代码
// Looper.myQueue().addIdleHandler 会在主线程空闲时执行
// 即: MessageQueue中没有消息需要处理时

// 实现原理(简化版):
class MessageQueue {
    fun next(): Message? {
        // ... 获取下一个消息

        // 如果没有消息,执行IdleHandler
        if (message == null && idleHandlers.isNotEmpty()) {
            for (handler in idleHandlers) {
                handler.queueIdle()
            }
        }

        return message
    }
}
优化策略2: 异步初始化 (Async Initialization)
kotlin 复制代码
// ✅ 更好的方案: 并行异步初始化
class BetterApplication : Application() {
    private val initExecutor = Executors.newFixedThreadPool(3)

    override fun onCreate() {
        super.onCreate()

        // 崩溃上报必须同步初始化
        BuglySDK.init(this, "app_id", false)  // 180ms

        // 其他SDK异步并行初始化
        initExecutor.submit { UmengSDK.init(this, "umeng_key") }      // 150ms
        initExecutor.submit { WeChatSDK.registerApp("wx_app_id") }    // 200ms
        initExecutor.submit { DatabaseHelper.getInstance(this).init() }  // 150ms

        // Application.onCreate耗时: 180ms
        // 其他SDK在后台并行初始化,互不阻塞
    }
}
优化策略3: 懒加载 (Lazy Loading)
kotlin 复制代码
// ✅ 最佳方案: 按需加载
class BestApplication : Application() {
    // 使用Kotlin的lazy委托,首次使用时才初始化
    val database by lazy {
        DatabaseHelper.getInstance(this).apply { init() }
    }

    val config by lazy {
        ConfigManager.loadFromDisk(this)
    }

    override fun onCreate() {
        super.onCreate()

        // 只初始化崩溃上报
        BuglySDK.init(this, "app_id", false)  // 180ms

        // Application.onCreate耗时: 180ms (减少82%)
        // database和config只在首次使用时才初始化
    }
}

// 使用示例
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 首次访问时才初始化database
        val app = application as BestApplication
        val user = app.database.getUserInfo()  // 此时才执行数据库初始化
    }
}
优化策略4: 启动器模式 (Startup Library)

使用Google的App Startup库管理初始化流程:

kotlin 复制代码
// build.gradle
dependencies {
    implementation "androidx.startup:startup-runtime:1.1.1"
}
kotlin 复制代码
// 定义初始化器
class UmengInitializer : Initializer<Unit> {
    override fun create(context: Context) {
        UmengSDK.init(context, "umeng_key")
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        // 声明依赖关系
        return emptyList()
    }
}

class DatabaseInitializer : Initializer<Unit> {
    override fun create(context: Context) {
        DatabaseHelper.getInstance(context).init()
    }

    override fun dependencies(): List<Class<out Initializer<*>>> {
        return emptyList()
    }
}
xml 复制代码
<!-- AndroidManifest.xml -->
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false">

    <meta-data
        android:name="com.example.UmengInitializer"
        android:value="androidx.startup" />

    <meta-data
        android:name="com.example.DatabaseInitializer"
        android:value="androidx.startup" />
</provider>
kotlin 复制代码
// Application中不需要手动初始化,Startup库会自动按依赖顺序初始化
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        // 只需要初始化崩溃上报
        BuglySDK.init(this, "app_id", false)
    }
}

Application优化效果对比:

方案 Application耗时 优化幅度 用户体验 实现难度
原始方案 1000ms - 白屏1秒 简单
延迟初始化 180ms ⬇️ 82% 几乎无感知 简单
异步初始化 180ms ⬇️ 82% 几乎无感知 中等
懒加载 180ms ⬇️ 82% 几乎无感知 简单
Startup库 180ms ⬇️ 82% 几乎无感知 中等

3.3 Activity.onCreate()优化

Activity.onCreate()是冷启动的第二个瓶颈,主要耗时在数据加载和UI渲染。

反面案例:典型的慢Activity
kotlin 复制代码
// ❌ 糟糕的Activity实现
class BadActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 问题1: 主线程同步网络请求 (耗时400ms)
        val userInfo = NetworkApi.getUserInfoSync()  // 阻塞主线程!

        // 问题2: 主线程同步数据库查询 (耗时200ms)
        val products = DatabaseHelper.queryProducts()

        // 问题3: 复杂的RecyclerView初始化 (耗时300ms)
        recyclerView.adapter = ComplexAdapter(products)
        recyclerView.layoutManager = GridLayoutManager(this, 2)

        // 问题4: 加载30张大图片 (耗时500ms)
        loadAllImages(products)

        // Activity.onCreate耗时: 1400ms
        // 加上Application 180ms = 总启动时间 1580ms
        // 用户体验: 白屏1.6秒,非常糟糕
    }
}
优化策略1: 异步加载数据
kotlin 复制代码
// ✅ 优化后: 异步加载,先显示占位
class GoodActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 先显示骨架屏/占位UI
        showSkeletonScreen()

        // 异步加载数据
        lifecycleScope.launch {
            try {
                // 在IO线程加载数据
                val userInfo = withContext(Dispatchers.IO) {
                    NetworkApi.getUserInfoSync()
                }

                val products = withContext(Dispatchers.IO) {
                    DatabaseHelper.queryProducts()
                }

                // 切回主线程更新UI
                withContext(Dispatchers.Main) {
                    hideSkeletonScreen()
                    updateUI(userInfo, products)
                }
            } catch (e: Exception) {
                showError(e)
            }
        }

        // Activity.onCreate耗时: 80ms (只渲染骨架屏)
        // 数据在后台加载,不阻塞启动
    }

    private fun showSkeletonScreen() {
        // 显示骨架屏动画
        skeletonView.visibility = View.VISIBLE
        contentView.visibility = View.GONE
    }

    private fun hideSkeletonScreen() {
        skeletonView.visibility = View.GONE
        contentView.visibility = View.VISIBLE
    }
}
优化策略2: 数据预加载
kotlin 复制代码
// 在SplashActivity预加载数据
class SplashActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_splash)

        // 在显示Splash的同时,预加载数据
        lifecycleScope.launch {
            // 并行预加载多个数据源
            val userInfoDeferred = async(Dispatchers.IO) {
                NetworkApi.getUserInfoSync()
            }

            val configDeferred = async(Dispatchers.IO) {
                NetworkApi.getConfig()
            }

            val productsDeferred = async(Dispatchers.IO) {
                DatabaseHelper.queryProducts()
            }

            // 等待所有数据加载完成
            val userInfo = userInfoDeferred.await()
            val config = configDeferred.await()
            val products = productsDeferred.await()

            // 缓存到全局单例
            DataCache.userInfo = userInfo
            DataCache.config = config
            DataCache.products = products

            // 延迟1秒(展示Splash),然后跳转主页
            delay(1000)
            startActivity(Intent(this@SplashActivity, MainActivity::class.java))
            finish()
        }
    }
}

// MainActivity直接使用缓存数据
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 直接使用预加载的数据,无需等待
        val userInfo = DataCache.userInfo
        val products = DataCache.products

        if (userInfo != null && products != null) {
            updateUI(userInfo, products)
        } else {
            // 降级方案:数据未准备好,异步加载
            loadDataAsync()
        }

        // Activity.onCreate耗时: 80ms
        // 总启动时间: 180ms + 80ms = 260ms (优化前1580ms,减少83%)
    }
}
优化策略3: 布局优化

使用ViewStub延迟加载:

xml 复制代码
<!-- activity_main.xml -->
<LinearLayout ...>
    <!-- 首屏可见的内容 -->
    <TextView ... />
    <RecyclerView ... />

    <!-- 非首屏内容使用ViewStub延迟加载 -->
    <ViewStub
        android:id="@+id/stub_detail_panel"
        android:layout="@layout/layout_detail_panel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ViewStub
        android:id="@+id/stub_comment_section"
        android:layout="@layout/layout_comment_section"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>
kotlin 复制代码
// 需要时才加载
findViewById<ViewStub>(R.id.stub_detail_panel).inflate()

使用ConstraintLayout减少层级:

xml 复制代码
<!-- 优化前: 嵌套5层 (measure/layout耗时150ms) -->
<LinearLayout>
    <RelativeLayout>
        <LinearLayout>
            <FrameLayout>
                <TextView />
            </FrameLayout>
        </LinearLayout>
    </RelativeLayout>
</LinearLayout>

<!-- 优化后: 只有2层 (measure/layout耗时50ms) -->
<ConstraintLayout>
    <TextView
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
</ConstraintLayout>

异步Inflate布局:

kotlin 复制代码
// 对于复杂布局,使用AsyncLayoutInflater异步加载
AsyncLayoutInflater(this).inflate(R.layout.complex_layout, container) { view, resid, parent ->
    // 在主线程回调,添加到容器
    parent?.addView(view)
}
优化策略4: 图片优化

懒加载图片:

kotlin 复制代码
// 使用Coil/Glide的占位符和懒加载
imageView.load("https://example.com/image.jpg") {
    placeholder(R.drawable.placeholder)  // 先显示占位图
    crossfade(true)  // 淡入淡出
    memoryCacheKey("user_avatar_${userId}")  // 内存缓存
}

只加载可见区域的图片:

kotlin 复制代码
// RecyclerView只加载可见Item的图片
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
        when (newState) {
            RecyclerView.SCROLL_STATE_IDLE -> {
                // 停止滚动时才加载图片
                Glide.with(context).resumeRequests()
            }
            else -> {
                // 滚动中暂停加载
                Glide.with(context).pauseRequests()
            }
        }
    }
})

使用WebP格式:

bash 复制代码
# 将PNG/JPG转换为WebP (减小30-50%文件大小)
cwebp input.png -q 80 -o output.webp

3.4 首屏渲染优化

首屏渲染是用户感知启动完成的关键时刻。

测量首屏渲染时间
kotlin 复制代码
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val startTime = System.currentTimeMillis()
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 监听首帧绘制完成
        window.decorView.post {
            val renderTime = System.currentTimeMillis() - startTime
            Log.d("Performance", "首屏渲染耗时: ${renderTime}ms")

            // 上报给分析平台
            Analytics.track("first_screen_render", mapOf("duration" to renderTime))
        }
    }
}
优化RecyclerView首屏加载
kotlin 复制代码
// 优化RecyclerView性能
recyclerView.apply {
    // 1. 设置固定大小 (跳过measure)
    setHasFixedSize(true)

    // 2. 增加View缓存
    setItemViewCacheSize(20)  // 默认2,增加到20
    recycledViewPool.setMaxRecycledViews(0, 20)

    // 3. 预取 (prefetch)
    (layoutManager as? LinearLayoutManager)?.apply {
        isItemPrefetchEnabled = true
        initialPrefetchItemCount = 4
    }

    // 4. 使用DiffUtil增量更新
    adapter = MyAdapter().apply {
        submitList(dataList)
    }
}
使用启动窗口 (SplashScreen API)
xml 复制代码
<!-- themes.xml -->
<!-- 定义启动主题,显示自定义背景 -->
<style name="AppTheme.Launcher" parent="Theme.SplashScreen">
    <item name="windowSplashScreenBackground">@color/splash_background</item>
    <item name="windowSplashScreenAnimatedIcon">@drawable/ic_launcher</item>
    <item name="postSplashScreenTheme">@style/AppTheme</item>
</style>
xml 复制代码
<!-- AndroidManifest.xml -->
<activity
    android:name=".MainActivity"
    android:theme="@style/AppTheme.Launcher"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
kotlin 复制代码
// MainActivity.kt
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        // 安装SplashScreen
        val splashScreen = installSplashScreen()

        // 保持SplashScreen直到数据准备好
        var isReady = false
        splashScreen.setKeepOnScreenCondition { !isReady }

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 异步加载数据
        lifecycleScope.launch {
            loadData()
            isReady = true  // 数据准备好,移除SplashScreen
        }
    }
}

Activity优化效果对比:

方案 Activity+渲染耗时 总启动时间 优化幅度
原始方案 1400ms 1580ms -
异步加载 80ms 260ms ⬇️ 84%
数据预加载 80ms 260ms ⬇️ 84%
布局优化 50ms 230ms ⬇️ 85%
图片优化 80ms 260ms ⬇️ 84%
综合优化 50ms 230ms ⬇️ 85%

四、App热启动优化:毫秒级的用户体验

热启动是App从后台恢复的场景,虽然比冷启动快,但优化不当仍会让用户感到卡顿。

4.1 热启动性能测量

bash 复制代码
# 测量热启动时间
# 1. 启动App
adb shell am start-activity com.example.myapp/.MainActivity

# 2. 按Home键(App进入后台)
adb shell input keyevent KEYCODE_HOME

# 3. 等待2秒

# 4. 重新启动App并测量
adb shell am start-activity -W com.example.myapp/.MainActivity

# 输出:
# TotalTime: 450ms  ← 这就是热启动时间

4.2 热启动优化策略

策略1: 避免onResume()中的重复操作
kotlin 复制代码
// ❌ 不好的做法
class MainActivity : AppCompatActivity() {
    override fun onResume() {
        super.onResume()

        // 每次onResume都执行,包括热启动
        loadUserInfo()       // 400ms
        loadProductList()    // 300ms
        updateUI()          // 100ms

        // 热启动耗时: 800ms (太慢!)
    }
}
kotlin 复制代码
// ✅ 好的做法: 区分首次和后续Resume
class MainActivity : AppCompatActivity() {
    private var isFirstResume = true

    override fun onResume() {
        super.onResume()

        if (isFirstResume) {
            // 首次Resume: 加载所有数据
            loadUserInfo()
            loadProductList()
            updateUI()
            isFirstResume = false
        } else {
            // 热启动: 只刷新必要数据
            refreshData()  // 只刷新时间敏感的数据,如消息数、通知等
        }
    }

    private fun refreshData() {
        // 只刷新增量数据,耗时50ms
        lifecycleScope.launch {
            val newMessages = withContext(Dispatchers.IO) {
                MessageApi.getNewMessages()
            }
            updateMessageBadge(newMessages)
        }
    }
}
策略2: 缓存View状态
kotlin 复制代码
// 保存和恢复滚动位置
class MainActivity : AppCompatActivity() {
    private var scrollPosition = 0

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        // 保存滚动位置
        scrollPosition = recyclerView.computeVerticalScrollOffset()
        outState.putInt("scroll_position", scrollPosition)
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        super.onRestoreInstanceState(savedInstanceState)
        // 恢复滚动位置
        scrollPosition = savedInstanceState.getInt("scroll_position", 0)
        recyclerView.post {
            recyclerView.scrollBy(0, scrollPosition)
        }
    }
}
策略3: 使用Fragment缓存
kotlin 复制代码
// ViewPager2缓存Fragment,避免重复创建
viewPager.offscreenPageLimit = 2  // 缓存左右各2页

// FragmentManager复用Fragment
supportFragmentManager.beginTransaction()
    .replace(R.id.container, fragment, "tag")
    .commit()

// 下次使用时先查找缓存
val cachedFragment = supportFragmentManager.findFragmentByTag("tag")
if (cachedFragment != null) {
    // 复用缓存的Fragment
    supportFragmentManager.beginTransaction()
        .show(cachedFragment)
        .commit()
} else {
    // 创建新Fragment
}

热启动优化效果:

方案 热启动耗时 优化幅度 用户体验
原始方案 800ms - 明显卡顿
避免重复操作 300ms ⬇️ 62.5% 轻微延迟
缓存View状态 250ms ⬇️ 68.75% 几乎无感知
Fragment缓存 200ms ⬇️ 75% 即时响应

五、车机场景特殊优化

车载系统对启动性能要求更高,同时有特殊的约束条件。

5.1 车机Boot优化特点

挑战:

  • 启动时间要求更严格 (< 10秒到Launcher,< 5秒到倒车影像)
  • 硬件资源相对受限 (CPU、RAM比旗舰手机低)
  • 安全关键功能必须快速可用 (倒车影像、胎压监测)

优化策略:

bash 复制代码
# init.rc: 关键服务优先启动
on boot
    # 优先级1: 倒车影像相关 (必须3秒内可用)
    start camera_hal
    start rvc_service  # Rear View Camera

    # 优先级2: 仪表显示
    start instrument_cluster

    # 优先级3: 其他功能 (延后启动)
    exec - root -- /system/bin/sh -c "start media_service &"
    exec - root -- /system/bin/sh -c "start navi_service &"

5.2 车机App启动优化

Launcher预加载常用App:

kotlin 复制代码
class CarLauncher : Activity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_launcher)

        // 在Launcher显示后,后台预加载导航和音乐App
        window.decorView.post {
            preloadApp("com.example.navi")
            preloadApp("com.example.music")
        }
    }

    private fun preloadApp(packageName: String) {
        Thread {
            try {
                // 启动App但不显示
                val intent = packageManager.getLaunchIntentForPackage(packageName)
                intent?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                startActivity(intent)

                // 延迟1秒后移到后台 (进程已创建,下次启动更快)
                Thread.sleep(1000)

                val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
                am.moveTaskToBack(true)
            } catch (e: Exception) {
                Log.e("Preload", "预加载失败: $packageName", e)
            }
        }.start()
    }
}

六、总结与最佳实践

6.1 启动优化方法论

1. 测量优先,数据驱动

  • 不要凭感觉优化,先用Systrace/Perfetto精确测量
  • 找到真正的瓶颈,而非想象中的瓶颈
  • 优化前后都要测量,验证效果

2. 分阶段优化

  • Application阶段: 延迟初始化、异步初始化、懒加载
  • Activity阶段: 异步加载数据、预加载、骨架屏
  • 首屏渲染: 布局优化、图片懒加载、RecyclerView优化

3. 异步为王

  • 能异步的坚决不同步
  • 主线程只做UI相关操作
  • 使用Coroutines/RxJava管理异步任务

4. 延迟加载

  • 非必须的功能延后初始化
  • 非首屏的内容延后加载
  • 使用IdleHandler、postDelayed、lazy等机制

5. 持续监控

  • 建立CI/CD自动化测试
  • 线上监控启动性能
  • 设置性能阈值,防止倒退

6.2 避坑指南

不要在Application中做太多事情

  • Application.onCreate()只初始化崩溃上报等必须的服务
  • 其他SDK异步或延迟初始化

不要在主线程做网络请求和数据库操作

不要过早初始化不需要的SDK

  • 很多SDK支持延迟初始化
  • 懒加载:用到时再初始化

不要在首屏加载所有数据

  • 先显示骨架屏,给用户即时反馈
  • 数据异步加载,分批渲染

不要忽略启动窗口的体验

  • 使用SplashScreen API提供平滑过渡
  • 避免白屏

6.3 性能基准参考

冷启动性能基准:

应用类型 优秀 良好 需优化
社交类 < 0.8s 0.8-1.5s > 1.5s
电商类 < 1s 1-1.8s > 1.8s
工具类 < 0.5s 0.5-1s > 1s
游戏类 < 2s 2-3s > 3s
车机应用 < 0.8s 0.8-1.2s > 1.2s

热启动性能基准:

应用类型 优秀 良好 需优化
所有类型 < 300ms 300-500ms > 500ms

6.4 参考资源

官方文档:

源码参考:

工具链:


作者简介: 多年Android系统开发经验,专注于系统稳定性与性能优化领域。欢迎关注本系列,一起深入Android系统的精彩世界!


🎉 感谢关注,让我们一起深入Android系统的精彩世界!

找到我 : 个人主页

相关推荐
冰_河5 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化
阿巴斯甜16 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker16 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952717 小时前
Andorid Google 登录接入文档
android
黄林晴19 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android