Android13 开机时间优化

前言

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

开机时间检测方法

logcat

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

adb logcat -b all > logcat.txt

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

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

adb logcat -b events | grep -E "boot_progress|sf_stop_bootanim|wm_boot_animation_done"

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

启动阶段说明
boot_progress_startLinux kernel启动到Zygote进程启动的时间,包含从kernel启动到Init启动Zygote的时间
boot_progress_preload_startART虚拟机启动耗时/Zygote开始启动
boot_progress_preload_end虚拟机资源装载耗时/Zygote启动结束
boot_progress_system_runSystem Server进程启动耗时
boot_progress_pms_startAndroid一些在PMS前需要启动服务的启动耗时,package scan开始
boot_progress_pms_system_scan_startsystem目录开始scan时间点
boot_progress_pms_data_scan_startdata目录开始scan时间点/system目录扫描耗时
boot_progress_pms_scan_end扫描结束时间点/data目录扫描耗时
boot_progress_pms_readyPMS启动扫描包耗时
boot_progress_ams_readyPMS后的系统服务启动时间
boot_progress_enable_screenAMS启动完成后开始激活屏幕
sf_stop_bootanimsurfaceflinger结束开机动画
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是在开机后执行如下命令抓取:
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可通过一下命令安装

sudo apt-get install bootchart
sudo apt-get install pybootchartgui 

Ubuntu20.04上无法定位pybootchartgui

这时可以手动下载,然后放到python编译器搜寻的目录下。
下载地址:github.com/xrmx/bootchart/releases
下载好后解压

tar -zxvf bootchart-0.14.9.tar.gz

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

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

sudo cp -r /usr/lib/python3.8/bootchart-0.14.9/pybootchartgui/ /usr/lib/python3.8/

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

python3 -c "import sys;print(sys.path)"

所以,我们可以将pybootchartgui目录复制到以上任意目录中,只要能被python编译器搜寻到即可。
最后还需要注意一下,复制完后需要将 main.py.in 重命名为 main.py ,否者会报如下错误,此问题在github的issue中有提到

重命名命令

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
adb root 
adb shell
touch /data/bootchart/ enabled
  • 检查是否生成了enabled
# ls /data/bootchart/
enabled
  • 重启设备
adb reboot
  • 等待开机进入Launcher,查看 /data/bootchart/ 下是否有生成header文件,即bootchart日志是否生成
adb root
adb shell
ls /data/bootchart/
  • 拷贝 /data/bootchart/ 下的 4 个文件到本地
proc_diskstats.log
proc_ps.log
proc_stat.log
header
 
# Pull指令:
adb pull /data/bootchart/
  • 进入到 bootchart 目录(刚刚 pull 的文件夹),执行指令将这 4 个文件打包起来(在 bootchart 目录中打开终端)
tar -czf bootchart.tgz *
  • 执行指令,生成 bootchart.png 文件(./指代当前目录)
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_serverJava framework的各种service都依赖此进程
com.android.phone电话应用进程
android.process.acore通讯录进程
android.process.media多媒体应用进程
com.android.settings设置进程
com.android.wifiwifi应用进程
  • 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文件:

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:

adb shell pm list package -f

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

裁剪方法:

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 --git /build/make/core/product.mk /build/make/core/product.mk
index 90e960b..c556037 100644
--- a/core/product.mk
+++ b/core/product.mk
@@ -40,6 +40,9 @@ _product_list_vars += PRODUCT_PACKAGES_ENG
 _product_list_vars += PRODUCT_PACKAGES_TESTS
 _product_var_list += PRODUCT_PACKAGES_DEL
 
+# App removal list
+_product_list_vars+= PRODUCT_PACKAGES_REMOVE
+
 # The device that this product maps to.
 _product_single_value_vars += PRODUCT_DEVICE
 _product_single_value_vars += PRODUCT_MANUFACTURER
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可以裁掉

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

adb shell pm list features

裁剪方法:

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

针对具体应用场景,可以将没用的Sensor裁剪掉。
可通过如下命令查看设备中所有支持的Sensor:

adb shell dumpsys sensorservice
配置优化方向
  • 优化PinnerService配置

PinnerService是用于锁定某些模块在内存中,避免这些模块被移出\移入内存从而提高程序的运行效率。优化目的是减少非首次开机启动Service的时间。

修改 /frameworks/base/core/res/res/values/config.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

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

# Force 32bits executables.
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote32
  • 关闭默认开关

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

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

  • 1.关闭锁屏显示通知
     <!-- 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>
  • 2.关闭手势唤醒
     <!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED -->
-    <bool name="def_wake_gesture_enabled">true</bool>
+    <bool name="def_wake_gesture_enabled">false</bool>
  • 3.关闭双击唤醒
     <!-- Default state of tap to wake -->
-    <bool name="def_double_tap_to_wake">true</bool>
+    <bool name="def_double_tap_to_wake">false</bool>
  • 4.关闭充电振动
     <!-- Default for Settings.Secure.CHARGING_VIBRATION_ENABLED -->
-    <bool name="def_charging_vibration_enabled">true</bool>
+    <bool name="def_charging_vibration_enabled">false</bool>
  • 5.关闭充电提示音
     <!-- Default for Settings.Secure.CHARGING_SOUNDS_ENABLED -->
-    <bool name="def_charging_sounds_enabled">true</bool>
+    <bool name="def_charging_sounds_enabled">false</bool>
  • 6.关闭蓝牙和wifi
<bool name="def_bluetooth_on">false</bool>
<bool name="def_wifi_display_on">false</bool>
  • 7.关闭自动旋转
<bool name="def_accelerometer_rotation">false</bool>
  • 8.关闭Wifi Debugging
<!-- Disable WiFi Debugging -->
<bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">false</bool>
  • 删除开机动画

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

frameworks/base/cmds/bootanimation/BootAnimationUtil.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

 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

// 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 的过程。

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中添加

android_app {
	dex_preopt: {
        enabled: true,
	},
}

Android.mk中添加

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

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 --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 --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

<!-- True if WallpaperService is enabled -->
<bool name="config_enableWallpaperService">true</bool>
  • 调整窗口动画渲染

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

-    <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/perf/boot-times?hl=zh-cn

实战总结

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

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

bootchart安装包

链接: pan.baidu.com/s/1BKVd348fZV8xkYLj9hfTzA?pwd=253x 提取码: 253x

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/547861.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

windows Nginx上部署若依后台管理登录界面之验证码不显示

大多数情况都是本地电脑Nginx部署正常&#xff0c;服务器Nginx部署验证码不显示。如下图 其实是Nginx配置有问题 server {listen 80;//监听端口server_name 域名或者公网ip等;location / {root D:/dist;//前端包文件路径需要修改index index.html; //不用管try_files …

k8s的service为什么不能ping通?——所有的service都不能ping通吗

点击阅读原文 前提&#xff1a;kube-proxy使用iptables模式 Q service能不能ping通&#xff1f; A: 不能&#xff0c;因为k8s的service禁止了icmp协议 B: 不能&#xff0c;因为clusterIP是一个虚拟IP&#xff0c;只是用于配置netfilter规则&#xff0c;不会实际绑定设备&…

深入理解 C++ 中的 KeyFrame 和 KeyFrame*:对象与指针的选择与管理

本文详细讨论了在 C 编程中 KeyFrame 类及其指针 KeyFrame* 的用法、区别与联系。通过探索两者的内存管理、生命周期及使用场景&#xff0c;本文旨在帮助开发者更好地理解何时以及如何选择使用对象或指针&#xff0c;从而提高代码的效率和安全性。 在 C 中&#xff0c;KeyFrame…

求1000以内正整数的平方根(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h> # include <math.h>int main() {//初始化变量值&#xff1b;int number 0;int result 0;//提示用户&#xff1b;printf("请输入1000以内求平方根的…

Python 版分布式消息队列 Kafka 实现图片数据传输

1、Kafka 介绍 在使用 Kafka 之前&#xff0c;通常需要先安装和配置 ZooKeeper。ZooKeeper 是 Kafka 的依赖项之一&#xff0c;它用于协调和管理 Kafka 集群的状态。 ZooKeeper 是一个开源的分布式协调服务&#xff0c;它提供了可靠的数据存储和协调机制&#xff0c;用于协调…

超越GPT-4V!马斯克发布Grok-1.5 With Vision

在 Grok-1 开源后不到一个月&#xff0c;xAI 的首个多模态模型就问世了。Grok-1.5V是XAI的第一代多模态模型&#xff0c;除了其强大的文本处理能力之外&#xff0c;Grok现在还能够处理包括文档、图表、图形、屏幕截图和照片在内的各种视觉信息。相信Grok-1.5V将很快提供给现有的…

基于ssm的社区再就业培训管理系统的设计与实现论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本社区再就业培训管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数…

【Spring】依赖注入(DI)时常用的注解@Autowired和@Value

目录 1、Autowired 自动装配 1.1、要实现自动装配不是一定要使用Autowired 1.2、Autowired的特性 &#xff08;1&#xff09;首先会根据类型去spring容器中找(bytype),如果有多个类型&#xff0c;会根据名字再去spring容器中找(byname) &#xff08;2&#xff09;如果根据名…

Sony Camera Remote SDK在Windows上的使用

Sony官方提供了相机遥控软件开发包&#xff0c;允许用户自行开发应用软件&#xff0c;实现对相机的远程控制&#xff0c;包括拍摄、监看和文件传输等。截至目前最新的版本是2024.4.12发布的1.12.00版本&#xff0c;下载链接如下&#xff1a;Camera Remote SDK | LICENSE AGREEM…

温湿度传感器(DHT11)以及光照强度传感器(BH1750)的使用

前言 对于一些单片机类的环境检测或者智能家居小项目中&#xff0c;温湿度传感器&#xff08;DHT11&#xff09;以及光照强度传感器&#xff08;BH1750&#xff09;往往是必不可少的两个外设&#xff0c;下面我们来剖析这两个外设的原理&#xff0c;以及使用。 1. 温湿度传感…

elasticsearch 下载、启动和账号密码登录

因为我的电脑是 window&#xff0c;以下都是以 window 环境举例。 一、下载 Elasticsearch 是使用 java 开发的&#xff0c;且 7.8 版本的 ES 需要 JDK 版本 1.8 以上&#xff0c;安装前注意java环境的准备。 官网地址&#xff1a;https://www.elastic.co/cn/ 下载地址&#xf…

云安全与网络安全:有什么区别?

云计算已经存在了一段时间&#xff0c;但某些术语的正确含义仍然存在混乱。一个例子是区分云安全与网络安全。 首先&#xff0c;让我们看一下网络安全一词 &#xff0c;以了解它的含义。然后&#xff0c;我们将将该术语与云安全进行比较&#xff0c;以了解两者在几个关键领域的…

OpenHarmony实战开发-如何使用AKI轻松实现跨语言调用。

介绍 针对JS与C/C跨语言访问场景&#xff0c;NAPI使用比较繁琐。而AKI提供了极简语法糖使用方式&#xff0c;一行代码完成JS与C/C的无障碍跨语言互调&#xff0c;使用方便。本示例将介绍使用AKI编写C跨线程调用JS函数场景。通过调用C全局函数&#xff0c;创建子线程来调用JS函…

DaVinci Fusion Studio:专业影视后期特效合成的得力助手

在当今影视制作领域&#xff0c;后期特效合成是不可或缺的一环。而DaVinci Fusion Studio作为一款功能强大的影视后期特效合成软件&#xff0c;以其出色的性能、直观的操作界面和丰富的特效库&#xff0c;受到了广大影视制作人员的喜爱。 首先&#xff0c;DaVinci Fusion Stud…

使用python在本地指定的目录临时模拟服务器(3),2024年最新网易 面经

先自我介绍一下&#xff0c;小编浙江大学毕业&#xff0c;去过华为、字节跳动等大厂&#xff0c;目前阿里P7 深知大多数程序员&#xff0c;想要提升技能&#xff0c;往往是自己摸索成长&#xff0c;但自己不成体系的自学效果低效又漫长&#xff0c;而且极易碰到天花板技术停滞…

NodeJS特点

NodeJS特点 web服务器的主要特点是&#xff1a;事件驱动&#xff0c;非阻塞I/O&#xff0c;单线程&#xff0c;跨平台自身非常简单&#xff0c;通过通信协议来组织许多node&#xff0c;通过拓展来达成构建大型网络应用的目的。每一个node进程都构成这个网络的一个节点适用于io…

4个步骤:如何使用 SwiftSoup 和爬虫代理获取网站视频

摘要/导言 在本文中&#xff0c;我们将探讨如何使用 SwiftSoup 库和爬虫代理技术来获取网站上的视频资源。我们将介绍一种简洁、可靠的方法&#xff0c;以及实现这一目标所需的步骤。 背景/引言 随着互联网的迅速发展&#xff0c;爬虫技术在今天的数字世界中扮演着越来越重要…

微信小程序wx.getLocation 真机调试不出现隐私弹窗

在小程序的开发过程中&#xff0c;首页中包含要获取用户地理位置的功能&#xff0c;所以在这里的onLoad&#xff08;&#xff09;中调用了wx.getLocation()&#xff0c;模拟调试时一切正常&#xff0c;但到了真机环境中就隐私框就不再弹出&#xff0c;并且出现了报错&#xff0…

浏览器跨标签页通信的方式都有哪些

跨标签页的实际应用场景&#xff1a; 1. 共享登录状态&#xff1a; 用户登录后&#xff0c;多个标签页中需要及时获取到登录状态&#xff0c;以保持一致的用户信息。这种情况&#xff0c;可以使用浏览器的 localStorage 或者 sessionStorage 来存储登录状态&#xff0c;并通过…

无线测温技术在高炉炉壳温度检测中的应用/无线测温监控系统

安科瑞薛瑶瑶18701709087 摘要:应用方便灵活的无线测温和热成像技术对高炉炉壳进行检测&#xff0c;利用热成像进行检测&#xff0c;发现了温度异常区域后对关注部位进行点的检测&#xff0c;预防炉壳的烧穿&#xff0c;对温度数据采集及存储&#xff0c;通过查看历史趋势来对…
最新文章