Android系统优化--开机时间优化

实际生活当中,针对某些应用场景,对Android启动时间要求比较严格,比如车载,车都开出去几公里了,IVI系统还没起来,这就比较尴尬,所以,优化Android启动时间是一项非常重要的工作。本文将根据本人实际工作经验,详细讲述Android开机时间相关的内容,基于Android13。

主要内容

  • 开机时间检测方法

  • 影响开机时间的Android启动流程

  • 开机时间优化方案

开机时间检测方法

logcat

长按power键开机,等待adb进程启动后(一般出现Android字样后),执行如下命令抓取开机logcat

shell 复制代码
adb logcat -b all > logcat.txt

打开logcat.txt,搜索logcat关键字"boot_progress"、"sf_stop_bootanim"、"wm_boot_animation_done"

或者直接执行以下命令过滤logcat

shell 复制代码
adb logcat -b events | grep -E "boot_progress|sf_stop_bootanim|wm_boot_animation_done"

以上是Android系统启动的各个阶段耗时,可以看到,整个开机过程耗时23.283秒,其中从按下power键到zygote启动,耗时7.646秒。各阶段的解释如下:

启动阶段 说明
boot_progress_start Linux kernel启动到Zygote进程启动的时间,包含从kernel启动到Init启动Zygote的时间
boot_progress_preload_start ART虚拟机启动耗时/Zygote开始启动
boot_progress_preload_end 虚拟机资源装载耗时/Zygote启动结束
boot_progress_system_run System Server进程启动耗时
boot_progress_pms_start Android一些在PMS前需要启动服务的启动耗时,package scan开始
boot_progress_pms_system_scan_start system目录开始scan时间点
boot_progress_pms_data_scan_start data目录开始scan时间点/system目录扫描耗时
boot_progress_pms_scan_end 扫描结束时间点/data目录扫描耗时
boot_progress_pms_ready PMS启动扫描包耗时
boot_progress_ams_ready PMS后的系统服务启动时间
boot_progress_enable_screen AMS启动完成后开始激活屏幕
sf_stop_bootanim surfaceflinger结束开机动画
wm_boot_animation_done 从enable_screen到animation_done包含壁纸和keyguard的绘制时间

注意,logcat只能看到上层启动后的log,即zygote启动后,开机期间kernel层的耗时无法通过logcat观察。
*

串口log和kernel log

  • 串口log可以使用串口线连接Android设备和PC,使用串口工具抓取log,常用的串口工具有很多,xshell、MobaXterm等。

  • kernel log是在开机后执行如下命令抓取:

shell 复制代码
adb shell dmesg > dmesg.txt

log里面搜关键字 "KPI" 、"first stage" 、"second stage",此关键字为kernel的各个启动阶段。

uart log和kernel log都可以显示整个开机过程时间。

左侧为启动时间轴,右侧为启动log。
*

bootchart

bootchart 是一个用于 linux 启动过程性能分析的开源工具软件,在系统启动过程中自动收集 CPU 占用率、磁盘吞吐率、进程等信息,并以图形方式显示分析结果,可用作指导优化系统启动过程。

bootchart 让用户可以很直观的查看系统启动的过程和各个过程耗费的时间,以便让用户能够分析启动过程,从而进行优化以提高启动时间。

  • 安装bootchart

    Ubuntu16.04和18.04可通过一下命令安装

    shell 复制代码
    sudo apt-get install bootchart
    sudo apt-get install pybootchartgui 

    Ubuntu20.04上无法定位pybootchartgui

    这时可以手动下载,然后放到python编译器搜寻的目录下。

    下载地址:github.com/xrmx/bootch...

    下载好后解压

    shell 复制代码
    tar -zxvf bootchart-0.14.9.tar.gz

    得到目录bootchart-0.14.9,进入到该目录

    将图中的pybootchartgui目录复制到/usr/lib/python3.8/目录下

    shell 复制代码
    sudo cp -r /usr/lib/python3.8/bootchart-0.14.9/pybootchartgui/ /usr/lib/python3.8/

    /usr/lib/python3.8/是python编译器搜寻的目录之一,完整的搜寻目录列表可通过以下命令查看

    shell 复制代码
    python3 -c "import sys;print(sys.path)"

    所以,我们可以将pybootchartgui目录复制到以上任意目录中,只要能被python编译器搜寻到即可。

    最后还需要注意一下,复制完后需要将main.py.in重命名为main.py,否者会报如下错误,此问题在github的issue中有提到

    重命名命令

    shell 复制代码
    sudo mv /usr/lib/python3.8/pybootchartgui/main.py.in /usr/lib/python3.8/pybootchartgui/main.py

    最后我们将bootchartpybootchartgui这两个文件复制到/usr/bin/目录下(文件附文末)。

    这两个文件是一样的,也就意味着你可以通过bootchart或者pybootchartgui来生成bootchart.png

  • 生成bootchart.png开机图

    • 准备userdebug或者userroot设备

    • 开启bootchart

      shell 复制代码
      adb root 
      adb shell
      touch /data/bootchart/ enabled
    • 检查是否生成了enabled

      shell 复制代码
      # ls /data/bootchart/
      enabled
    • 重启设备

      shell 复制代码
      adb reboot
    • 等待开机进入Launcher,查看 /data/bootchart/ 下是否有生成header文件,即bootchart日志是否生成

      shell 复制代码
      adb root
      adb shell
      ls /data/bootchart/
    • 拷贝 /data/bootchart/ 下的 4 个文件到本地

      c 复制代码
      proc_diskstats.log
      proc_ps.log
      proc_stat.log
      header
       
      # Pull指令:
      adb pull /data/bootchart/
    • 进入到 bootchart 目录(刚刚 pull 的文件夹),执行指令将这 4 个文件打包起来(在 bootchart 目录中打开终端)

      shell 复制代码
      tar -czf bootchart.tgz *
    • 执行指令,生成 bootchart.png 文件(./指代当前目录)

      shell 复制代码
      bootchart ./ bootchart.tgz
    • 拷贝 bootchart.png 到你需要的地方,双击查看

  • bootchart.png示例图

    bootchart图可以很直观的看到整个开机过程的时间节点以及CPU、磁盘的使用情况

    • bootchart.png讲解

      第一行:时间

      第二行:Linux版本

      第三行:odm release fingerprint

      第三行:cpu架构

      第四行:kernel配置选项

      第五行:开机耗时

      开机过程中,CPU的使用率、I/O状态、磁盘吞吐量、磁盘使用率

      第一行:代表整个机器开机的时间,每一格代表1秒 第二行:代表init从长格子开始的位置开始启动 最后一行:开始zygote的启动,后面就是java 世界:system_server及app进程

      kernel相关的启动部分,启动时间看下init什么时候启动的就知道了。

影响开机时间的Android启动流程

开机框架

​ 引用Gityuan大佬的一张开机流程图

Android启动流程大体为:BootRom -> BootLoader -> Kernel -> Init -> Zygote -> SystemServer ->Launcher

Loader层

  • Boot ROM

    电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行,加载引导程序到RAM,然后执行。

  • Boot Loader

    这是Android系统系统之前的引导程序,主要用来检测外部的RAM以及设置网络、内存、初始化硬件参数等。

Kernel层

Kernel层是指Android内核层,到这里才刚刚开始进入Android系统。

  • 启动swapper进程(pid=0),该进程又称为idle进程,,系统初始化过程Kernel由无到有开创的第一个进程,,用于初始化进程管理、内存管理,加载Display、Camera Driver、Binder Driver等相关工作(图中kernel层蓝色区块)。
  • 启动kthreadd进程(pid=2),是Linux系统的内核进程,会创建内核工作线程kworkder,软中断线程ksoftirqd,thermal等一系列内核守护进程。kthreadd进程是所有内核进程的父进程。

Linux内核加载主要包括初始化kernel核心(内存初始化,打开中断,初始化进程表等)、初始化驱动、启动内核后台(daemons)线程、安装根(root)文件系统等。后续启动第一个用户级进程init(pid=1)。

Native层

Native层主要包括启动init进程(Android的第一个用户空间进程)、HAL层(硬件抽象层)以及开机动画等。init进程是所有用户进程的鼻祖。同时init进程也会孵化一系列用户进程,还会启动关键的服务以及孵化Zygote进程。

  • init进程会孵化出ueventd、logd、healthd、installd、adbd、lmkd等用户守护进程。
  • init进程还启动servicemanager(binder服务管家)、bootanim(开机动画)等重要服务。
  • init进程孵化出Zygote进程,Zygote进程是Android系统的第一个Java进程,Zygote是所有Java进程的父进程,Zygote进程本身是由init进程孵化而来的。

Framework层

Framework层分为Java frameword和C++ framework,分别由system_server进程和media_server进程负责启动和管理。

zygote本身是一个native的应用程序,刚开始的名字为"app_process",运行过程中,通过系统调用将自己名字改为zygote。在上图中的红色线,便是zygote fork出来的进程,所有的app进程都是由zygote fork产生的。

下面列举Zygote进程孵化的部分子进程:

进程名 解释
system_server Java framework的各种service都依赖此进程
com.android.phone 电话应用进程
android.process.acore 通讯录进程
android.process.media 多媒体应用进程
com.android.settings 设置进程
com.android.wifi wifi应用进程
  • zygote进程

    由init进程通过解析init.rc文件后fork生成的,Zygote进程主要包含:

    • 加载ZygoteInit类,注册Zygote Socket服务端套接字
    • 加载虚拟机
    • preloadClasses
    • preloadResouces
  • system_server进程

    由zygote进程fork而来,system_server是zygote孵化的第一个进程,system_server负责启动和管理整个java framework,包含ActivityManager、PowerManager等服务。

  • media_server进程

    由init进程fork而来,负责启动和管理整个C++ framework,包含SurfaceFlinger、AudioFlinger、Camera Service等服务。

app层

  • zygote进程孵化出的第一个app进程是Launcher,这是用户看到的桌面app。
  • zygote进程还会创建Browser,Phone,Email等app进程,每个app至少运行在一个进程上。
  • 所有的app进程都是由zygote进程fork生成的。

具体的启动过程,此文不便详述,都是代码分析,复杂且枯燥。

开机时间优化方案

以下均为framework层的优化,kernel层优化不在研究范围。

精简方向

精简初始化脚本:减少开机时的初始化时间。

高通平台关注以下.rc & .sh文件:

csharp 复制代码
init.rc  
init.target.rc  
init.qcom.rc  
init.sh
init.qcom.sh  
init.qcom.post_boot.sh

裁剪方向

移除非必须Apks、Features、Sensor等,减少PackageScan时间。

  • 裁剪预置APK

    针对具体应用场景,可以将没用的apk裁剪掉,比如automotive可以裁掉Launcher,因为automotive自带CarLauncher。

    可通过如下命令查看设备中所有的apk:

    shell 复制代码
    adb shell pm list package -f

    Android中的内置APK介绍见:Android主要应用和进程说明

    裁剪方法:

    diff 复制代码
    diff --git /build/make/core/main.mk /build/make/core/main.mk
    index a8f46c1..d9d507b 100644
    --- a/core/main.mk
    +++ b/core/main.mk
    @@ -1267,6 +1267,7 @@ define product-installed-files
       $(eval ### Filter out the overridden packages and executables before doing expansion) \
       $(eval _pif_overrides := $(call module-overrides,$(_pif_modules))) \
       $(eval _pif_modules := $(filter-out $(_pif_overrides), $(_pif_modules))) \
    +  $(eval _pif_modules := $(filter-out $(modules_product_packages_remove), $(_pif_modules))) \
       $(eval _pif_modules := $(filter-out $(PRODUCT_PACKAGES_DEL), $(_pif_modules))) \
       $(eval ### Resolve the :32 :64 module name) \
       $(eval _pif_modules := $(sort $(call resolve-bitness-for-modules,TARGET,$(_pif_modules)))) \
    @@ -1363,6 +1364,9 @@ else ifdef FULL_BUILD
         endif
       endif
     
    +  # App removal list
    +  modules_product_packages_remove := $(PRODUCT_PACKAGES_REMOVE)
    diff 复制代码
    diff --git /device/qcom/{product}/{product}.mk /device/qcom/{product}/{product}.mk
    index 163cac2..89a3078 100755
    --- a/{product}.mk
    +++ b/{product}.mk
    @@ -60,6 +60,8 @@ PRODUCT_BUILD_USERDATA_IMAGE := true
    +# App removal list
    +PRODUCT_PACKAGES_REMOVE += \
    +	Calendar \
    +	Email \
    +	SnapdragonMusic \
    +	DeskClock \

    注意:/device/qcom/{product}/{product}.mk取决于厂商的产品名称

  • 移除不需要的Features

    针对具体应用场景,可以将没用的Features裁剪掉,比如automotive可以裁掉<feature name="android.software.print" />

    可通过如下命令查看设备中所有的Features:

    shell 复制代码
    adb shell pm list features

    裁剪方法:

    diff 复制代码
    diff --git /frameworks/native/data/etc/android.software.print.xml /frameworks/native/data/etc/android.software.print.xml
    index 713a7f7..e76bb88 100644
    --- /frameworks/native/data/etc/android.software.print.xml
    +++ /frameworks/native/data/etc/android.software.print.xml
    @@ -15,5 +15,5 @@
     -->
     
     <permissions>
    -    <feature name="android.software.print" />
    +<!--    <feature name="android.software.print" />-->
     </permissions>
  • 禁用不需要的Sensors

    针对具体应用场景,可以将没用的Features裁剪掉。

    可通过如下命令查看设备中所有支持的Sensor:

    shell 复制代码
    adb shell dumpsys sensorservice

配置优化方向

  • 优化PinnerService配置

    PinnerService是用于锁定某些模块在内存中,避免这些模块被移出\移入内存从而提高程序的运行效率。

    优化目的是减少非首次开机启动Service的时间。

    修改/frameworks/base/core/res/res/values/config.xml,添加如下配置:

    xml 复制代码
    <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    ... ...
       <!-- Default files to pin via Pinner Service -->
        <string-array translatable="false" name="config_defaultPinnerServiceFiles">
         <item>"/system/framework/arm/boot-framework.art"</item>
         <item>"/system/lib/libjavacrypto.so"</item>
         <item>"/system/lib/libhidltransport.so"</item>
         <item>"/system/framework/arm/boot-core-libart.oat"</item>
         <item>"/system/framework/arm/boot-conscrypt.oat"</item>
         <item>"/system/framework/arm/boot-core-libart.art"</item>
         <item>"/system/framework/arm/boot-ext.art"</item>
         <item>"/system/framework/arm/boot.art"</item>
         <item>"/system/framework/arm/boot-framework.art"</item>
        </string-array>
    ... ...
     </resources>

    注意:芯片商(例如高通)的代码可能会存在客制化,AOSP的位置可能会被覆盖,如果有,则以芯片商的代码为准。

  • 使用32Bit程序

    定义了32Bit的程序,机器在apk的使用及服务的申明都会有略微的精简,在设备启动时加载的资源会少,故加载时间会少。

    修改方式:

    /device/qcom/{product}/BoardConfig.mk

    makefile 复制代码
    TARGET_ARCH := arm
    TARGET_ARCH_VARIANT := armv8-2a
    TARGET_CPU_ABI := armeabi-v7a
    TARGET_CPU_ABI2 := armeabi
    TARGET_CPU_VARIANT := cortex-a9
    
    #TARGET_2ND_ARCH := arm
    #TARGET_2ND_ARCH_VARIANT := armv8-2a
    #TARGET_2ND_CPU_ABI := armeabi-v7a
    #TARGET_2ND_CPU_ABI2 := armeabi
    #TARGET_2ND_CPU_VARIANT := cortex-a9

    device/generic/art/armv8/armv8.mk

    makefile 复制代码
    # Force 32bits executables.
    PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote32
  • 关闭默认开关

    默认关闭功能开关,开启期间不再自动开启,加快开机进度。

    主要修改/frameworks/base/packages/SettingsProvider/res/values/defaults.xml

    • 关闭锁屏显示通知

      xml 复制代码
           <!-- Default for Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1==on -->
      -    <integer name="def_lock_screen_show_notifications">1</integer>
      +    <integer name="def_lock_screen_show_notifications">0</integer>
    • 关闭手势唤醒

      xml 复制代码
           <!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED -->
      -    <bool name="def_wake_gesture_enabled">true</bool>
      +    <bool name="def_wake_gesture_enabled">false</bool>
    • 关闭双击唤醒

      xml 复制代码
           <!-- Default state of tap to wake -->
      -    <bool name="def_double_tap_to_wake">true</bool>
      +    <bool name="def_double_tap_to_wake">false</bool>
    • 关闭充电振动

      xml 复制代码
           <!-- Default for Settings.Secure.CHARGING_VIBRATION_ENABLED -->
      -    <bool name="def_charging_vibration_enabled">true</bool>
      +    <bool name="def_charging_vibration_enabled">false</bool>
    • 关闭充电提示音

      xml 复制代码
           <!-- Default for Settings.Secure.CHARGING_SOUNDS_ENABLED -->
      -    <bool name="def_charging_sounds_enabled">true</bool>
      +    <bool name="def_charging_sounds_enabled">false</bool>
    • 关闭蓝牙和wifi

      xml 复制代码
      <bool name="def_bluetooth_on">false</bool>
      <bool name="def_wifi_display_on">false</bool>
    • 关闭自动旋转

      xml 复制代码
      <bool name="def_accelerometer_rotation">false</bool>
    • 关闭Wifi Debugging

      xml 复制代码
          <!-- Disable WiFi Debugging -->
          <bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">false</bool>

删除开机动画

Animation的资源大小和播放时长一直是影响开机时间的重要因素之一,移除开机动画将有效地加快开机速度。

frameworks/base/cmds/bootanimation/BootAnimationUtil.cpp

cpp 复制代码
bool bootAnimationDisabled() {
    char value[PROPERTY_VALUE_MAX];
    //将获取结果改为1,则无法进入到开机动画流程中
    //property_get("debug.sf.nobootanimation", value, "0");
    property_get("debug.sf.nobootanimation", value, "1");
    if (atoi(value) > 0) {
        return true;
    }

    property_get("ro.boot.quiescent", value, "0");
    if (atoi(value) > 0) {
        // Only show the bootanimation for quiescent boots if this system property is set to enabled
        if (!property_get_bool("ro.bootanim.quiescent.enabled", false)) {
            return true;
        }
    }

    return false;
}

开机过程CPU满载

开机过程中让CPU火力全开,能有效减少开机时间

/device/qcom/common/rootdir/etc/init.qcom.rc

yaml 复制代码
 on early-init
+    write /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu4/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu5/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu6/cpufreq/scaling_governor performance
+    write /sys/devices/system/cpu/cpu7/cpufreq/scaling_governor performance

注意:

  • init.qcom.rc是高通定制的init脚本,是开机时必然执行的。
  • 如果CPU原本就已经满载了,那么此修改则无效果。
  • 不同平台CPU的配置不尽相同。

移除SystemService

SystemServer进程启动后,会启动很多SystemService,根据实际场景,裁剪非必要的Service

frameworks/base/services/java/com/android/server/SystemServer.java

java 复制代码
        // Start services.
        try {
            t.traceBegin("StartServices");
            startBootstrapServices(t);
            startCoreServices(t);
            startOtherServices(t);
            startApexServices(t);
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            t.traceEnd(); // StartServices
        }

可裁剪的Service如下,仅供参考

复制代码
  1.VibratorService          震动器服务  
  2.ClipboardService         粘贴板服务  
  3.FingerprintService       指纹  

  4.BatteryService           电池服务,当电量不足时发广播  
  5.AlarmManagerService      闹钟服务   
  6.WallpaperManagerService  壁纸管理服务  
  7.StatusBarManagerService  状态栏管理服务  

注意:

  • 从framework层的角度去看问题,我们会发现功能及服务的裁剪,是最直接、最有效地时间及空间优化方法,它可以做到时间与空间的两者兼顾。

  • 注意app与Service,Service与Service之间的耦合性,避免引起机器的异常,无法开机;

移除app源码

修改下面文件中的 PRODUCT_PACKAGES 字段的内容,将不需要的内置应用的名称删除,这样可以缩短 scan packages 的过程。

bash 复制代码
1.build/target/product/core.mk  
2.build/target/product/full_base.mk  
3.build/target/product/full_base_telephony.mk  
4.build/target/product/generic_no_telephony.mk  

同时,可以删除 /packages/apps/ 路径下不必要的 app 源码,这样可以缩短编译时间。
*

apk odex

apk odex优化就是以空间换时间,加快apk启动速度,缺点是会消耗内存。

/device/qcom/{product}/{product}.mk加入WITH_DEXPREOPT=true, 打开odex优化

Android.bp中添加

makefile 复制代码
   android_app {
    dex_preopt: {
        enabled: true,
    },
  }

Android.mk中添加

makefile 复制代码
LOCAL_DEX_PREOPT := true

PMS优化

Apk的扫描安装耗时是大头。通常采用多线程方案,针对Dir或者Dir中的package进行多线程扫描.

PMS多线程扫描apk,4线程改成8线程,注意,如果客户做了CPU绑核, Android所分配的CPU资源受到限制,导致改成8线程之后反向优化了。

frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java

java 复制代码
class ParallelPackageParser {

    private static final int QUEUE_CAPACITY = 30;
//    private static final int MAX_THREADS = 4;
    private static final int MAX_THREADS = 8;
    
    //省略部分代码
}

Zygote优化

Zygote主要是优化class和resource的预加载,可以减少部分不需要预加载的class和resource,具体优化哪些,根据实际需求来添加。

注意:并不是预加载越少越好,如果开机必须启动的进程所需要的class和resource在zygote阶段被优化了,那么也会在该进程自启动时也会去加载,这样优化就是无效的。

diff 复制代码
diff --git /frameworks/base/config/preloaded-classes /frameworks/base/config/preloaded-classes
index f2530519247..d6ac1e22e3f 100644
--- /frameworks/base/config/preloaded-classes
+++ /frameworks/base/config/preloaded-classes
@@ -806,7 +806,6 @@ android.app.VoiceInteractor$Request
 android.app.VoiceInteractor
 android.app.Vr2dDisplayProperties$1
 android.app.Vr2dDisplayProperties
-android.app.VrManager
 android.app.WaitResult$1
 android.app.WaitResult
 android.app.WallpaperColors$1
@@ -2471,12 +2470,6 @@ android.hardware.display.Time$1
 android.hardware.display.Time
 android.hardware.display.VirtualDisplayConfig$1
 android.hardware.display.VirtualDisplayConfig
-android.hardware.display.WifiDisplay$1
-android.hardware.display.WifiDisplay
-android.hardware.display.WifiDisplaySessionInfo$1
-android.hardware.display.WifiDisplaySessionInfo
-android.hardware.display.WifiDisplayStatus$1
-android.hardware.display.WifiDisplayStatus
 android.hardware.face.Face$1
 android.hardware.face.Face
 android.hardware.face.FaceManager$1

移除手势导航

diff 复制代码
diff --git /frameworks/base/packages/overlays/Android.mk /frameworks/base/packages/overlays/Android.mk
index 69641e69a9f..71f5fd00520 100644
--- /frameworks/base/packages/overlays/Android.mk
+++ /frameworks/base/packages/overlays/Android.mk
@@ -20,17 +20,8 @@ LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../NOTICE
 LOCAL_REQUIRED_MODULES := \
-	DisplayCutoutEmulationCornerOverlay \
-	DisplayCutoutEmulationDoubleOverlay \
-    DisplayCutoutEmulationHoleOverlay \
-	DisplayCutoutEmulationTallOverlay \
-	DisplayCutoutEmulationWaterfallOverlay \
 	FontNotoSerifSourceOverlay \
 	NavigationBarMode3ButtonOverlay \
-	NavigationBarModeGesturalOverlay \
-	NavigationBarModeGesturalOverlayNarrowBack \
-	NavigationBarModeGesturalOverlayWideBack \
-	NavigationBarModeGesturalOverlayExtraWideBack \
 	preinstalled-packages-platform-overlays.xml
 
 include $(BUILD_PHONY_PACKAGE)

关闭壁纸服务

frameworks/base/core/res/res/values/config.xml

xml 复制代码
    <!-- True if WallpaperService is enabled -->
    <bool name="config_enableWallpaperService">true</bool>

调整窗口动画渲染

frameworks/base/packages/SettingsProvider/res/values/defaults.xml

diff 复制代码
-    <fraction name="def_window_animation_scale">100%</fraction>
-    <fraction name="def_window_transition_scale">100%</fraction>
+    <fraction name="def_window_animation_scale">25%</fraction>
+    <fraction name="def_window_transition_scale">25%</fraction>

如果想关闭animaton,直接将数值改为0即可。

注意:芯片商可能会定制defaults.xml,所以在修改时请留意是否改全。
*

专项优化

针对实际项目,如果加了自定义的开机自启动项,那么可以抓trace,看看整个开机过程哪个启动项耗时较长

例如:

上图可以看到 avm_worker 存在耗时异常, 该进程为 android 侧的 360 环视功能, 可以找对应开发确认是否需要开机启动。
*

Google优化方案

详见:source.android.google.cn/docs/core/p...

实战总结

对于Android开机时间优化,framework层可优化的空间较小,通过trace可以看到,一个Service的启动或者众多apk的扫描操作,往往都是在几毫秒或者几十毫秒内完成的,所以,即使关闭某个service的启动或者裁剪部分apk,优化效果也是毫秒级别的,不是很明显,但聚少成多,通过多种优化方案,累加优化时间,最终呈现出来的优化效果就是肉眼可见的。

而Kernel层的优化空间往往是较大的,都是秒级别的优化幅度,通过底层和上层双向优化,最终能达到比较理想的优化效果。

bootchart安装包

链接:pan.baidu.com/s/14odQxa2G... 提取码:x6a8

相关推荐
幻雨様2 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端3 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
Meteors.4 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton5 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
黑客飓风5 小时前
JavaScript 性能优化实战大纲
前端·javascript·性能优化
whysqwhw9 小时前
安卓图片性能优化技巧
android
风往哪边走9 小时前
自定义底部筛选弹框
android
Yyyy48210 小时前
MyCAT基础概念
android
Android轮子哥10 小时前
尝试解决 Android 适配最后一公里
android
雨白11 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android