更新后具有android:persistent=true的系统应用程序崩溃了。

16
在<application>中我有一个系统特权应用程序,并且android:persistent=true。当我更新它时(通过ADB或任何其他方式),它无法正确更新并崩溃。

我的发现是,系统在当前(已安装的系统)版本仍在运行时安装更新。在更新期间,系统不会停止进程(要么试图停止但失败,要么根本不尝试)。更新完成后,该应用似乎进行了“重启” - 我看到组件正在初始化,例如调用Application :: onCreate()。但这是在更新之前相同的进程上发生的!

因此(在启动应用程序的某些活动时),应用程序会出现“奇怪”的异常,例如无法将类强制转换为自身:

Caused by: java.lang.ClassCastException: com.XX.YY.ZZ.ClassName 无法转换为 com.XX.YY.ZZ.ClassName

在调查时,我发现更新后使用的ClassLoader不引用更新后APK的路径,而是仍然指向原始版本的路径:

预期的 classloader:

dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.app.package-1/base.apk"],nativeLibraryDirectories=[/data/app/com.app.package-1/lib/x86_64, /data/app/com.app.package-1/base.apk!/lib/x86_64, /system/lib64, /vendor/lib64]]]

实际 classloader:

dalvik.system.PathClassLoader[DexPathList[[zip file "/system/priv-app/Appname.apk"],nativeLibraryDirectories=[/system/lib64/Start, /system/priv-app/Appname.apk!/lib/x86_64, /system/lib64, /vendor/lib64, /system/lib64, /vendor/lib64]]]

我假设这是由于更新期间未重新启动进程而导致的。

有没有一种方法可以使用persistent=true更新应用程序?还是它是预期的行为,这种应用程序无法通过常规更新过程(例如在Google Play上发布新版本)进行更新?


如果您在应用程序更新后重新启动设备,它是否可以从新路径正确运行? - Alex Cohn
1
是的。重新启动设备可以解决这个问题。问题在于在设备被重启之前,应用程序会崩溃并在一个循环中不断崩溃,因为它的进程正在重新启动。 - user3118604
你看过这个技巧吗?https://dev59.com/ploT5IYBdhLWcg3w2CQw#38272684 - Alex Cohn
1
在开发过程中进行命令行更新时,您应该首先执行 adb shell stop,然后再执行 adb shell start。对于最终用户的更新,您可能需要将应用程序拆分为一个真正的系统组件,通过恢复系统在 Android 未运行时应用的 system OTA 机制进行更新,以及一个更常见的应用程序组件,您可以通过 Play 商店进行更新。 - Chris Stratton
只是好奇,新设备上是否有android:persistent=True的系统应用程序正在运行?我该如何检查? - Sunil
显示剩余2条评论
4个回答

4
您不能在使用系统镜像中的应用程序时使用adb install,并且必须将持久性应用程序放在系统镜像中。您正在为哪个版本的Android开发?在最近的Android版本中,我使用下面描述的一种方法之一。在每种方法之前,您必须至少运行一次adb remount

方法1:仅适用于代码更改,不适用于资源更改或清单更改

将以下内容暂时添加到您的Android.mk中:

LOCAL_DEX_PREOPT := false # Do not commit

然后使用mm或类似的工具进行构建。

运行相应的推送命令,如下所示:

adb push $OUT/system/priv-app/MyApp/MyApp.apk /system/priv-app/MyApp/

由于应用程序是持久的,您必须使用以下命令杀死应用程序进程,以便它能够读取更改:

adb shell ps | grep com.my.app | awk '{print $2}' | xargs adb shell kill

不要忘记在提交或进行完整构建之前删除或注释掉对 Android.mk 的更改。

方法2:对于除简单Java代码更改以外的任何内容都是必需的

使用mm或类似工具进行构建。

运行以下命令:

adb sync
adb shell stop
adb shell start

方法三

为了完整起见,您可以构建整个树并从结果中刷入系统或应用OTA。


该问题源于用户手机上的应用程序更新(来自Google Play)。您的建议适用于开发人员的操作,而不是最终用户。 - user3118604

0
发现了一个解决问题的方法。如果新版本更改了其进程名称,则更新将成功。

0

你可以使用一个简单的技巧并注册接收“android.intent.action.PACKAGE_ADDED”意图,以便在设备上安装每个应用程序时都能收到通知。如果添加的应用程序具有您的包ID(表示您的应用程序已更新),您可以尝试强制其结束并等待“persist”机制重新启动它作为新进程。

请注意,我在多个平台上使用持久化应用程序,并从未遇到过您所描述的行为(如果您能提供您使用的平台将会很有帮助)。


我可以在不使用android.intent.action.PACKAGE_ADDED的情况下检测升级情况。 "强制结束"(例如杀死进程或您指的是其他内容?)没有帮助,因为新进程会出现相同的“错误”类加载器。 2. 我怀疑可能涉及MultiDex库。您是否有更新使用multidex编译的持久应用程序的成功经验? - user3118604
没有一个我们开发的应用程序使用MultiDex编译。 - David Lev

0
  <application
        android:name=".xyzApp"
        android:allowBackup="true"
    android:persistent="false">

在AndriodManifest.xml中设置persistent="false"

1
这个不起作用。在更新期间,系统没有停止进程。 - user3118604

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接