首页 > 解决方案 > Android 尝试在 OTA 应用更新后引用广播接收器的旧包名称

问题描述

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

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

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,但新类是com.example.app.receiver.NewReceiver. 旧的被“缓存”在某处。

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

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

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

相关资料: http: //www.programmersought.com/article/8031444654/

标签: javaandroidbroadcastreceiverclassnotfoundexceptionandroid-package-managers

解决方案


PackageManagerService 的 Android 源代码有以下几行:

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”文件中找到。因此,您可以检查是否是问题所在。


推荐阅读