I have a system-privileged app with android:persistent=true in < application>. When I update it (via ADB or any other way), it fails to update properly and crashes.
What I'm seeing is that the system installs the update while the current (system-installed) version is still running. During the update the system does not stop the process (either attempts to stop and fails or doesn't try at all). After the update completes, the app seems to undergo a "restart" - I'm seeing components being initialized such as Application::onCreate() being called. But this is happening on same process as before the update!
Consequently (upon launching some activity of the app), the app crashes with "weird" exceptions such as failing to cast class to itself:
Caused by: java.lang.ClassCastException: com.XX.YY.ZZ.ClassName cannot be cast to com.XX.YY.ZZ.ClassName
While investigating, I saw that the ClassLoader used after the update does not refer to the the path of the updated APK, but remains pointing to the path of the original version:
Expected 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]]]
Actual 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]]]
I'm assuming this is a result of not restarting the process during update.
Is there a way to update an app with persistent=true? Or is it an expected behavior, such app cannot be updated by the common update procedure (e.g. posting newer version on Google Play)?
Android apps that run continuously in the background are called persistent apps. This ensures that the application is always running and receives and notifies you of messages when they come in.
An Android app crashes whenever there's an unexpected exit caused by an unhandled exception or signal. An app that is written using Java or Kotlin crashes if it throws an unhandled exception, represented by the Throwable class.
Apps on Android can crash because of low storage space, too many apps running simultaneously, a weak internet connection, or not having the proper app updates installed.
You cannot use adb install
when working with apps that are in the system image, and apps that are persistent must be in the system image. What version of Android are you developing for? On recent versions of android I use one of methods described below. Before each you must run adb remount
at least once.
Method 1: Works for code changes only, does not work for resource changes or manifest changes
Temporarily add this to your Android.mk
:
LOCAL_DEX_PREOPT := false # Do not commit
Then perform a build with mm
or the like.
Run the appropriate push command like so:
adb push $OUT/system/priv-app/MyApp/MyApp.apk /system/priv-app/MyApp/
Because the app is persistent you must kill the app process with the following command for it to pick up the changes:
adb shell ps | grep com.my.app | awk '{print $2}' | xargs adb shell kill
Do not forget to remove or comment out the change made to Android.mk
before committing or making full builds.
Method 2: Necessary for anything other than simple java code changes
Perform a build with mm
or the like.
Run the following commands:
adb sync
adb shell stop
adb shell start
Method 3
Just for completeness you could just build the entire tree and either flash the system or apply an OTA from the result.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With