Android 11 OTA升级后桌面图标未被修改

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

3)注意事项:

  • 不同设备的/data分区设备节点路径可能不同;
  • 如果/data分区已加密,在恢复模式下无法直接访问,可使用vold解密后再清理;
  • 先手动在recovery模式下测试Edify命令,确保clean_launcher.edify脚本没问题;
  • 需要在fstab中确认正确的文件系统类型,现代Android设备通常使用ext4f2fs
  • 可先在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 · 著作权归作者所有