Разработка Android RecoverySystem.installPackage() не может выполнить запись в /cache/recovery/, команда запрещена

Меня попросили написать небольшое простое приложение для продукта на базе Android. Устройство поставляется с двумя образами системы Android с различными функциями. Приложение, которое я пишу, является лишь подтверждением концепции, где, когда вы нажимаете кнопку, оно использует систему восстановления, чтобы заменить текущую ОС одним из образов.

Устройство рутировано, и приложение запускается как системное приложение.

я использую

RecoverySystem.installPackage(context, packageFile);

( см. здесь для справки) заменить ОС на один из образов. Это должно перезагрузить систему и инициализировать систему восстановления для установки образа.

Проблема, которая у меня есть, заключается в том, что этот вызов не удается, потому что RecoverySystem.installPackage Кажется, что метод не может получить доступ к / cache / recovery / command file. Я думаю, что он пытается написать некоторые команды для системы восстановления, которые будут выполняться при перезагрузке, но не удается. Вот исключение, которое я получаю:

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)

Итак, я предполагаю, что у меня нет необходимых прав доступа к этому файлу. Хотя вот разрешение, которое я установил в своем манифесте:

<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" />

Я знаю, что мне нужно разрешение REBOOT для RecoverySystem, Тем не менее, я не знаю, актуальны ли другие два. Я даже не знаю, нужно ли мне какое-то другое разрешение для создания / записи в файлы в разделе / ​​cache.

Кто-нибудь знает, чего мне не хватает?


ОБНОВИТЬ:

Ну, похоже, я понял это. Разрешения были правильными в конце концов. Все было правильно.

Когда я настраивал приложение как системное приложение, перемещая файл apk в / system / app, я еще не добавил все разрешения. Когда я запустил последний код на моем устройстве, он установил его в / data / app и распознал как обновление системного приложения. По этой причине распознавались только разрешения исходного системного приложения.

После того, как я заново настроил мой последний код для непосредственного запуска из / system / app, он заработал.

Теперь единственная проблема, с которой я столкнулся, это то, что когда он перезагружается, он не устанавливает образ, и я получаю мертвого зеленого робота с восклицательным знаком. Я буду продолжать расследование.

Я надеюсь, что этот пост поможет любому с той же проблемой. Я также буду рад ответить на любые вопросы.

3 ответа

До того, как мое приложение было установлено в /system/app, я получал сообщение об ошибке ниже:

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)

Я перепробовал все необходимые разрешения, но не смог продолжить.

Итак, так как я использовал API выше 4.2, я попытался поместить свое приложение в/system/priv-app и это сработало для меня.

Системные приложения (приложения с общим идентификатором пользователя, установленным на android.uid.system) не может устанавливать системные обновления на Android 5 и новее - это запрещено политикой SELinux. Конкретно писать в /cache запрещено для системных приложений. Другими словами:

  • /cache принадлежит system пользователь, так что ваше приложение работает под system UID может написать в него. Но только если SELinux отключен / разрешен.
  • Если у вас есть android.permission.ACCESS_CACHE_FILESYSTEM разрешение подписи платформы, вы можете написать /cache,

Вам нужно будет удалить общий идентификатор пользователя. Вы все еще должны подписать приложение подписью платформы и убедиться, что у вас есть следующие разрешения:

  • android.permission.REBOOT
  • android.permission.ACCESS_CACHE_FILESYSTEM - написать /cache
  • android.permission.RECOVERY - требуется API 21 для перезагрузки для восстановления

Это будет работать как на Kitkat, так и на Lollipop+.

У меня такая же проблема с вами, когда вы создаете пользовательское приложение OtaUpdate в Android 5.0.2, и я решил ее. Я поделюсь с вами 2 шагами ниже:

  1. Добавить Android:sharedUserId="com.google.uid.shared" в AndroidManifest.xml
  2. Вставьте свой apk в систему / приложение или систему /priv-app

Для Android 4.1.2:

  1. Добавьте android:sharedUserId="android.uid.system" в AndroidManifest.xml
  2. Вставьте свой апк в систему / приложение

Для Android 5.1.0

  1. добавлять android:sharedUserId="android.uid.system" в AndroidManifest.xml
  2. Нажмите на свой апк system/priv-app
  3. а потом

    adb root
    adb shell setenforce 0
    

Я встретил ту же проблему в Android 8.
Если вы добавите android:sharedUserId="android.uid.system" в AndroidManifest.xml, он должен работать.

Другие вопросы по тегам