java - 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/
解决方案
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”文件中找到。因此,您可以检查是否是问题所在。
推荐阅读
- c++ - 发射信号不起作用
- javascript - Javascript Object delete - 删除另一个对象
- google-analytics - 使用全局站点标签进行跨域跟踪 - 什么去哪里?
- javascript - 两个数组上的 Javascript 映射和过滤器
- c# - ASP.NET Identity UserManager UpdateAsync 删除角色
- visual-studio - 为什么我的文件会以更改的名称进入解决方案资源管理器的底部?
- javascript - 如何检查文档是否存在于mongodb中的特定字段
- android - JAVA_HOME 未设置,在您的 PATH 中找不到“java”命令
- php - CentOS - PHP 从浏览器调用未定义函数 mysql_connect()
- amazon-web-services - Message":"用户:anonymous 无权执行:iam:PassRole