Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android development RecoverySystem.installPackage() cannot write to /cache/recovery/command permission denied

Tags:

android

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.

like image 322
Stephane Avatar asked Feb 27 '13 22:02

Stephane


2 Answers

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.
  • If you have 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.REBOOT
  • android.permission.ACCESS_CACHE_FILESYSTEM - to write to /cache
  • android.permission.RECOVERY - required on API 21 to reboot to recovery

This will work on Kitkat and Lollipop+ alike.

like image 76
Eugen Pechanec Avatar answered Nov 12 '22 13:11

Eugen Pechanec


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.

like image 32
Hiten Bahri Avatar answered Nov 12 '22 13:11

Hiten Bahri