
Android 11 OTA升级后桌面图标未被修改
现象:Android 11 OTA升级后桌面图标未被修改(正常刷机没问题),需要清除launcher数据才正常。
原因:OTA升级机制,一般不会改变用户区(data分区)的数据,launcher3数据库存放路径:/data/data/com.android.launcher3/databases
解决方案一:在升级成功后在 FinishRecovery()中删除此数据便可恢复正常。
--- bootable/recovery/recovery.cpp
+++ bootable/recovery/recovery.cpp
@@ -26,6 +26,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <functional>
@@ -139,6 +140,47 @@
}
+// remove launcher3 databases for reload Workspace
+void remove_launcher3_databases() {
+ printf("in remove launcher3 databasesin");
+ if (ensure_path_mounted("/data")) {
+ printf("mount data partition error !\n");
+ return;
+ }
+ char *srcPath = (char *) malloc(100);
+ strcpy(srcPath, "/data/data/com.android.launcher3/databases");
+ if (access(srcPath, F_OK) != 0) {
+ free(srcPath);
+ return;
+ }
+
+ char *args[4];
+ args[0] = strdup("rm");
+ args[1] = strdup("-rf");
+ args[2] = strdup(srcPath);
+ args[3] = NULL;
+ pid_t child = fork();
+ if (child == 0) {
+ printf("run rm /data/data/com.android.launcher3/databases ...\n");
+ execv(args[0], &args[1]);
+ fprintf(stderr, "run program: execv failed: %s\n", strerror(errno));
+ _exit(1);
+ }
+ int child_status;
+ waitpid(child, &child_status, 0);
+ if (WIFEXITED(child_status)) {
+ if (WEXITSTATUS(child_status) != 0) {
+ fprintf(stderr, "run program: child exited with status %d\n",
+ WEXITSTATUS(child_status));
+ }
+ } else if (WIFSIGNALED(child_status)) {
+ fprintf(stderr, "run program: child terminated by signal %d\n",
+ WTERMSIG(child_status));
+ }
+ free(srcPath);
+ return;
+}
+
// Clear the recovery command and prepare to boot a (hopefully working) system,
// copy our log file to cache as well (for the system to read). This function is
// idempotent: call it as many times as you like.
@@ -179,6 +221,9 @@
bAutoUpdateComplete=false;
}
+ // remove /data/data/com.android.launcher3/databases
+ remove_launcher3_databases(); //在FinishRecovery()中删除launcher数据
+
// Remove the command file, so recovery won't repeat indefinitely.
if (HasCache()) {
if (ensure_path_mounted(COMMAND_FILE) != 0 || (unlink(COMMAND_FILE) && errno != ENOENT)) {
解决方案二:在制作OTA升级包时(脚本路径:build/tools/releasetools/ota_from_target_files.py),清除用户数据(如添加–-wipe_user_data 参数,格式化data分区)。
1、若不想格式化data分区,可以修改 ota_from_target_files.py,从而只删除/data/data/com.android.launcher3/databases,如下[1](未测试,但编译OK):
# build/tools/releasetools/ota_from_target_files.py
# def WriteFullOTAPackage(input_zip, output_file): #此函数是生成 full OTA 包的核心
if OPTIONS.extra_script is not None:
script.AppendExtra(OPTIONS.extra_script)
script.UnmountAll()
if OPTIONS.wipe_user_data:
script.ShowProgress(0.1, 10)
#script.FormatPartition("/data") 若有其它格式化/data的指令,则也需注释掉
# 只删除/data/data/com.android.launcher3/databases
script.AppendExtra('delete_recursive("/data/data/com.android.launcher3/databases");')
if OPTIONS.two_step:
script.AppendExtra("""
set_stage("%(bcb_dev)s", "");
""" % bcb_dev)
script.AppendExtra("else\n")若编译的是差分包,则应该修改def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_file): 函数,修改方式同上。编译好ota包后,可查看包里的META-INF/com/google/android/updater-script脚本文件中是否包含:delete_recursive("/data/data/com.android.launcher3/databases"); ,若包含则证明修改成功合入。
2、或者在生成OTA包时,使用--extra_script参数:(参考deepseek回答,未测试)
1)创建 clean_launcher.edify脚本:
ui_print("执行后期清理脚本...");
# 检查/data是否挂载
if is_mounted("/data") then
# 直接删除
delete_recursive("/data/data/com.android.launcher3/databases");
else
# 尝试挂载再删除
mount("ext4", "EMMC", "/dev/block/platform/soc/by-name/userdata", "/data");
delete_recursive("/data/data/com.android.launcher3/databases");
unmount("/data");
endif;
ui_print("Launcher3清理完成");2)使用以下指令生成OTA包(使用--extra_script参数合入clean_launcher.edify脚本):
./build/tools/releasetools/ota_from_target_files \
--extra_script clean_launcher.edify \
dist_output/target_files.zip \
full_ota.zip3)注意事项:
- 不同设备的
/data分区设备节点路径可能不同; - 如果
/data分区已加密,在恢复模式下无法直接访问,可使用vold解密后再清理; - 先手动在recovery模式下测试Edify命令,确保clean_launcher.edify脚本没问题;
- 需要在
fstab中确认正确的文件系统类型,现代Android设备通常使用ext4或f2fs; - 可先在recovery模式下adb shell,使用以下指令寻找/data分区挂载路径并测试是否能挂载成功:
ls -l /dev/block/platform/*/by-name | grep -i 'user*data' #先寻找可挂载路径
mount -t f2fs /dev/block/platform/fe310000.sdhci/by-name/userdata data #挂载/data分区编辑于 2026-01-25 · 著作权归作者所有