android OTA升级之后,apk崩溃无法启动

硬件平台:QCS6125

软件平台:Android 11

  问题背景:系统版本从低版本升级到高版本后,apk崩溃启动失败。启动失败的activity为apk新增加的组件,报错的信息为:

ActivityNotFoundException: Unable to find explicit activity class {com.yuanfudao.android.megrez.system.settings/com.yuanfudao.android.megrez.launcher.upgrade.activity.AutoUpgradeActivity}; have you declared this activity in your AndroidManifest.xml? - sentry - megrez-app-s2-launcher

表面意思是找不到这个新添加的activity,但是从系统升级之后的apk源文件dump信息看,apk文件是升级成功的,而且如果不是最新的话就不会启动这个新添加的activity,怀疑是此apk的数据缓存未更新,导致系统不识别新增的组件;

  1、在PKMS和PackageParser、PackageCacher等类加日志,发现在复现问题的场景下,data分区下apk对应的cache缓存是不更新的,日志线索:

18:33:04.661990  1402  1402 D PackageManager: Keeping known cache f440076f74442ad4fdc9b67da03a644a795c4079

这行日志之所以打印出来,从代码上下文来看,就是升级之后系统fingerprint的hash值较之前旧版本无变化所致,正常情况下,Android每个版本都会对应唯一的fingerprint,不会有高低版本的fingerprint 哈希值一样的情况,即都会打印上述日志的else情况:

08:05:39.665153  1241  1241 D PackageManager: Destroying unknown cache e0ba64a1887994e81e808eab35d295e97ea17523

这样的话系统应用在data分区创建的cache目录就会被删除而从新创建,那新增的组件就会解析成功并写入新的缓存文件,就不会报错;

缓存目录:/data/system/package_cache/指纹哈希值/

也就是说,我们这个高低版本是fingerprint相同的情况,这个问题追述到jenkins编译,启动job时会初始化一个BUILD_NUMBER值,这个值正好跟Android的build系统的名称重复,这就导致Android build系统那一套拼接时间戳的值不会走,因为jenkins一启动就会定义该值,而我们jenkins服务器迁移过,这个值又会从1开始累计,导致前后版本都是16,从而导致fingerprint一致。

2、还有一种情况是,这个问题并不是必现,比如A、B、C从低到高依次三个版本,B、C的fingerprint一致,那么1说的情况就是A->B->C必现更新失败,如果直接刷B,升级C却没有问题,那么这个原因是什么呢?这种情况理论上并不会删除cache跟目录,通过加日志,跟代码,发现fingerprint只是第一道关卡,后边即使cache目录不重建,apk也会逐个比对apk源文件和当前cache文件的时间戳先后,如果源文件更新则更新cache,因此这种情况就解释了为什么fingerprint一致,但也会apk更新成功的问题。

添加调试日志的相关改动:

涉及三个FW的文件:

PackageManagerService.java、PackageCacher.java、PackageParser2.java

具体改动如下:

diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 5d98de184e2..0f17297352f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -472,7 +472,7 @@ import java.util.function.Supplier;
  */
 public class PackageManagerService extends IPackageManager.Stub
         implements PackageSender {
-    static final String TAG = "PackageManager";
+    static final String TAG = "====== YfdPackageManager ======";
     public static final boolean DEBUG_SETTINGS = false;
     static final boolean DEBUG_PREFERRED = false;
     static final boolean DEBUG_UPGRADE = false;
@@ -3049,7 +3049,8 @@ public class PackageManagerService extends IPackageManager.Stub
             File frameworkDir = new File(Environment.getRootDirectory(), "framework");
 
             final VersionInfo ver = mSettings.getInternalVersion();
-            mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
+            //mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
+            mIsUpgrade = false;
             if (mIsUpgrade) {
                 logCriticalInfo(Log.INFO,
                         "Upgrading from " + ver.fingerprint + " to " + Build.FINGERPRINT);
@@ -3512,6 +3513,7 @@ public class PackageManagerService extends IPackageManager.Stub
                 for (int i = 0; i < mSettings.mPackages.size(); i++) {
                     final PackageSetting ps = mSettings.mPackages.valueAt(i);
                     if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
+                        Slog.e(TAG, "Will clear AppData for pkg: " + ps.name);
                         // No apps are running this early, so no need to freeze
                         clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
                                 FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
@@ -3783,6 +3785,7 @@ public class PackageManagerService extends IPackageManager.Stub
                 }
                 return false;
             }
+            Slog.e(TAG, "enableCompressedPackage() Will clear AppData for pkg: " + pkg.getPackageName());
             clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                     | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
             mDexManager.notifyPackageUpdated(pkg.getPackageName(),
@@ -3918,12 +3921,13 @@ public class PackageManagerService extends IPackageManager.Stub
         // There are several items that need to be combined together to safely
         // identify cached items. In particular, changing the value of certain
         // feature flags should cause us to invalidate any caches.
-        final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
+        /*final String cacheName = FORCE_PACKAGE_PARSED_CACHE_ENABLED ? "debug"
                 : SystemProperties.digestOf(
                         "ro.build.fingerprint",
                         StorageManager.PROP_ISOLATED_STORAGE,
                         StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT
-                );
+                );*/
+        final String cacheName = "57d69787bf7ff84e4c8c6a80ee77ed6533e0010f";
 
         // Reconcile cache directories, keeping only what we'd actually use.
         for (File cacheDir : FileUtils.listFilesOrEmpty(cacheBaseDir)) {
@@ -10415,9 +10419,11 @@ public class PackageManagerService extends IPackageManager.Stub
             Slog.wtf(TAG, "Package was null!", new Throwable());
             return;
         }
+        Slog.e(TAG, "111111 clear AppDataLIF() Will clear AppData for pkg: " + pkg.getPackageName());
         clearAppDataLeafLIF(pkg, userId, flags);
 
         if ((flags & Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES) == 0) {
+            Slog.e(TAG, "222222 clear AppDataLIF() Will clear AppData for pkg: " + pkg.getPackageName());
             clearAppProfilesLIF(pkg, UserHandle.USER_ALL);
         }
     }
@@ -17086,6 +17092,7 @@ public class PackageManagerService extends IPackageManager.Stub
             }
             prepareAppDataAfterInstallLIF(pkg);
             if (reconciledPkg.prepareResult.clearCodeCache) {
+                Slog.e(TAG, "executePostCommitSteps() Will clear AppData for pkg: " + pkg.getPackageName());
                 clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                         | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
             }
@@ -19602,6 +19609,7 @@ public class PackageManagerService extends IPackageManager.Stub
         }
         mPermissionManager.resetRuntimePermissions(pkg, userId);
 
+        Slog.e(TAG, "clearApplicationUserDataLIF() Will clear AppData for pkg: " + pkg.getPackageName());
         clearAppDataLIF(pkg, userId,
                 FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL);
 
@@ -19702,6 +19710,7 @@ public class PackageManagerService extends IPackageManager.Stub
                     final int flags = FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL;
                     // We're only clearing cache files, so we don't care if the
                     // app is unfrozen and still able to run
+                    Slog.e(TAG, "deleteApplicationCacheFilesAsUser() Will clear AppData for pkg: " + pkg.getPackageName());
                     clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CACHE_ONLY);
                     clearAppDataLIF(pkg, userId, flags | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
                 }
@@ -22659,6 +22668,7 @@ public class PackageManagerService extends IPackageManager.Stub
                 }
 
                 if (!Build.FINGERPRINT.equals(ver.fingerprint)) {
+                    Slog.e(TAG, "loadPrivatePackagesInner() Will clear AppData for pkg: " + ps.name);
                     clearAppDataLIF(ps.pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
                             | FLAG_STORAGE_EXTERNAL | Installer.FLAG_CLEAR_CODE_CACHE_ONLY
                             | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
diff --git a/services/core/java/com/android/server/pm/parsing/PackageCacher.java b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
index 99c6dd1f031..16b9f531cb0 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageCacher.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageCacher.java
@@ -176,6 +176,7 @@ public class PackageCacher {
             final String cacheKey = getCacheKey(packageFile, flags);
             final File cacheFile = new File(mCacheDir, cacheKey);
 
+            Slog.e(TAG, "====== cache file: " + cacheFile);
             if (cacheFile.exists()) {
                 if (!cacheFile.delete()) {
                     Slog.e(TAG, "Unable to delete cache file: " + cacheFile);
@@ -209,7 +210,8 @@ public class PackageCacher {
         for (File file : files) {
             if (!file.delete()) {
                 Slog.e(TAG, "Unable to clean cache file: " + file);
-            }
+            } else 
+               Slog.e(TAG, "====== clean cache file: " + file);
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index 1145057452c..9263d8c0179 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -35,6 +35,7 @@ import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.Slog;
+import android.util.Log;
 
 import com.android.internal.compat.IPlatformCompat;
 import com.android.server.pm.PackageManagerService;
@@ -140,6 +141,7 @@ public class PackageParser2 implements AutoCloseable {
     @AnyThread
     public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
             throws PackageParserException {
+               Slog.e(TAG, Log.getStackTraceString(new Exception()));
         if (useCaches && mCacher != null) {
             ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
             if (parsed != null) {
@@ -161,14 +163,14 @@ public class PackageParser2 implements AutoCloseable {
         if (mCacher != null) {
             mCacher.cacheResult(packageFile, flags, parsed);
         }
-        if (LOG_PARSE_TIMINGS) {
+        //if (LOG_PARSE_TIMINGS) {
             parseTime = cacheTime - parseTime;
             cacheTime = SystemClock.uptimeMillis() - cacheTime;
-            if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
-                Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
+          //  if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
+                Slog.e(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
                         + "ms, update_cache=" + cacheTime + " ms");
-            }
-        }
+            //}
+        //}
 
         return parsed;
     }

Mark it~~~~

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值