Android 尝试在 OTA 应用更新后引用广播接收器的旧包名称

Android tries to reference an old package name of a Broadcast receiver after OTA app update

我正在开发基于 OS 的自定义 AOSP 8.1。我有一个带有导出广播接收器的系统应用程序(在 /system/priv-app 中)。这意味着它可以接受来自应用程序外部的 Intent。如果我重构广播接收器,例如更改其包位置或 class 名称并使用 "adb install -r ..." 安装更新的 APK,一切正常,广播接收器接收到意图。

但是,如果我使用新应用程序 (APK + VDEX + ODEX) 生成 OTP 图像并从恢复中刷新它,应用程序会崩溃,因为 Android 仍在尝试引用旧的广播接收器 class:

AndroidRuntime: java.lang.RuntimeException: Unable to instantiate receiver com.example.app.receiver.ExampleReceiver: java.lang.ClassNotFoundException: Didn't find class "com.example.app.receiver.ExampleReceiver" on path: DexPathList[[zip file "/system/priv-app/ExampleApp/ExampleApp.apk"],nativeLibraryDirectories=[/system/priv-app/ExampleApp/lib/arm, /system/lib, /vendor/lib, /system/lib, /vendor/lib]]

它试图引用 com.example.app.receiver.ExampleReceiver,但新的 class 是 com.example.app.receiver.NewReceiver。旧的在"cached"某处。

我可以通过重新挂载 /system 分区 RW 并使用 adb push ... 替换新的 APK、ODEX 和 VDEX 文件来模拟同样的问题。如果我从 /system 删除 ODEX 和 VDEX 文件就够奇怪了,一切都很好,因为显然这个行为迫使 Android 再次解析 APK。

据我了解,PackageManager 系统应用程序应该能够检测应用程序何时更新并解析导出的部分(例如 classes 用于广播接收器和活动)。不幸的是,这不会发生。

我也猜想这就是当 Android 显示 "Optimizing app xxx/xxx" 时 OTA 之后发生的情况,但这不会发生在这里。这个过程应该如何触发?

相关信息:http://www.programmersought.com/article/8031444654/

Android sourcecode for PackageManagerService 有以下几行:

mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
... some other code

if (mIsUpgrade && !onlyCore) {
                Slog.i(TAG, "Build fingerprint changed; clearing code caches");
                ... cache clearing logic
                ver.fingerprint = Build.FINGERPRINT;
}

也就是说,如果更改构建指纹,代码缓存将被清除。出现此问题可能是因为您的 OTA 软件包与安装它的系统具有相同的指纹。

检查您的 makefile 并确保为每个构建生成唯一的指纹。

指纹值可以在"system/buildprops"文件中找到。所以你可以检查是否是问题所在。