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 之后发生的情况,但这不会发生在这里。这个过程应该如何触发?
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"文件中找到。所以你可以检查是否是问题所在。
我正在开发基于 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 之后发生的情况,但这不会发生在这里。这个过程应该如何触发?
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"文件中找到。所以你可以检查是否是问题所在。