I have been asked to write a small simple app for an Android-based product. The device comes with two Android system images with different features. The app I'm writing is just a proof of concept where when you click on a button, it uses the Recovery System to replace the current OS with one of the images.
The device is rooted and the application runs as a system app.
I use
RecoverySystem.installPackage(context, packageFile);
(see here for reference) to replace the OS with one of the images. This should reboot the system and initialize the recovery system to install the image.
The problem that I have is that this call fails because the RecoverySystem.installPackage method can't seem to access the /cache/recovery/command file. I guess it tries to write some commands for the recovery system to be executed on reboot, but fails. Here is the exception I am getting:
02-27 16:44:39.463: E/BroadSign Resolution Switcher(4439): java.io.FileNotFoundException: /cache/recovery/command: open failed: EACCES (Permission denied)
02-27 16:44:39.463: E/BroadSign Resolution Switcher(4439): at libcore.io.IoBridge.open(IoBridge.java:416)
02-27 16:44:39.463: E/BroadSign Resolution Switcher(4439): at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
02-27 16:44:39.463: E/BroadSign Resolution Switcher(4439): at java.io.FileOutputStream.<init>(FileOutputStream.java:73)
02-27 16:44:39.463: E/BroadSign Resolution Switcher(4439): at java.io.FileWriter.<init>(FileWriter.java:42)
02-27 16:44:39.463: E/BroadSign Resolution Switcher(4439): at android.os.RecoverySystem.bootCommand(RecoverySystem.java:381)
02-27 16:44:39.463: E/BroadSign Resolution Switcher(4439): at android.os.RecoverySystem.installPackage(RecoverySystem.java:330)
So, I am assuming that I don't have the proper permission to access this file. Though here are the permission that I have set in my manifest:
<uses-permission android:name="android.permission.REBOOT" />
<uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
I know I need the REBOOT permission for the RecoverySystem. However, I don't know if the other two are relevant. I don't even know if I need some other permission to create/write to files in the /cache partition.
Does anybody know what I could be missing?
UPDATE:
Well, it looks like I figured it out. The permissions were right after all. Everything was right.
When I was setting up the app as a system app by moving the apk file to /system/app I hadn't put all the permissions in yet. When I ran the latest code on my device, it installed it in /data/app and recognized it as an update to the system app. Because of that, only the permissions of the original system app were recognized.
After I re-set up my latest code to run from /system/app directly, it worked.
Now the only issue I have is that when it reboots it doesn't install the image and I end up with a dead green robot with an exclamation mark. I'll keep investigating.
I hope this post helps anyone with the same issue. I'll be happy to answer any questions as well.
System apps (apps with shared user ID set to android.uid.system) cannot install system updates on Android 5 and newer - it's forbidden by a SELinux policy. To be specific writing to /cache is forbidden for system apps. In other words:
/cache is owned by system user so your app running under system UID can write to it. But only if SELinux is disabled/permissive.
android.permission.ACCESS_CACHE_FILESYSTEM platform signature permission, you can write to /cache.You'll need to remove the shared user ID. You still have to sign the app with platform signature and ensure you have the following permissions:
android.permission.REBOOTandroid.permission.ACCESS_CACHE_FILESYSTEM - to write to /cache
android.permission.RECOVERY - required on API 21 to reboot to recoveryThis will work on Kitkat and Lollipop+ alike.
Before when my app was installed in /system/app I was getting below error:
07-20 10:52:46.512 933-951/? W/RecoverySystem﹕ !!! REBOOTING TO INSTALL /storage/emulated/legacy/Download/Update.zip !!!
07-20 10:52:46.512 933-951/? W/System.err﹕ java.io.FileNotFoundException: /cache/recovery/command: open failed: EACCES (Permission denied)
07-20 10:52:46.512 933-951/? W/System.err﹕ at libcore.io.IoBridge.open(IoBridge.java:409)
07-20 10:52:46.512 933-951/? W/System.err﹕ at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
07-20 10:52:46.512 933-951/? W/System.err﹕ at java.io.FileOutputStream.<init>(FileOutputStream.java:73)
07-20 10:52:46.512 933-951/? W/System.err﹕ at java.io.FileWriter.<init>(FileWriter.java:42)
07-20 10:52:46.512 933-951/? W/System.err﹕ at android.os.RecoverySystem.bootCommand(RecoverySystem.java:389)
07-20 10:52:46.522 933-951/? W/System.err﹕ at android.os.RecoverySystem.installPackage(RecoverySystem.java:337)
I had tried all permissions that were required but I couldn't proceed.
So then since I was using API above 4.2 I tried to put my app into /system/priv-app and it worked for me.
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