【问题标题】:Android development RecoverySystem.installPackage() cannot write to /cache/recovery/command permission deniedAndroid 开发 RecoverySystem.installPackage() 无法写入 /cache/recovery/command 权限被拒绝
【发布时间】:2013-02-13 22:44:52
【问题描述】:

我被要求为基于 Android 的产品编写一个简单的小应用程序。该设备带有两个具有不同功能的 Android 系统映像。我正在编写的应用程序只是一个概念验证,当您单击一个按钮时,它会使用恢复系统将当前操作系统替换为其中一个图像。

设备已root,应用程序作为系统应用程序运行。

我用

RecoverySystem.installPackage(context, packageFile);

(see here for reference) 用其中一个图像替换操作系统。这应该重新启动系统并初始化恢复系统以安装映像。

我遇到的问题是此调用失败,因为 RecoverySystem.installPackage 方法似乎无法访问 /cache/recovery/command 文件。我猜它试图为恢复系统编写一些命令,以便在重新启动时执行,但失败了。这是我得到的例外:

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

我知道我需要RecoverySystem 的 REBOOT 权限。但是,我不知道其他两个是否相关。我什至不知道我是否需要其他权限来创建/写入 /cache 分区中的文件。

有人知道我可能会错过什么吗?


更新:

嗯,看来我想通了。毕竟权限是对的。一切正常。

当我通过将 apk 文件移动到 /system/app 来将应用程序设置为系统应用程序时,我还没有放入所有权限。当我在我的设备上运行最新代码时,它会将其安装在 /data/app 中,并将其识别为系统应用程序的更新。因此,只能识别原始系统应用的权限。

在我重新设置我的最新代码以直接从 /system/app 运行后,它工作了。

现在我唯一遇到的问题是,当它重新启动时,它没有安装映像,我最终得到一个带有感叹号的死绿色机器人。我会继续调查的。

我希望这篇文章对遇到同样问题的人有所帮助。我也很乐意回答任何问题。

【问题讨论】:

  • 我也做了同样的事情,我能够运行 FOTA 升级。但我的问题是,我制作的应用程序标签为platform_app,而谷歌用于升级的应用程序属于untrusted_app。有什么方法可以使我的应用程序成为具有上述缓存权限的 untrusted_app 完整的,因为这些权限仅授予我猜的系统应用程序
  • @PankajKushwaha 嗨 pankaj 我也在尝试以编程方式在我的 aap 中实现 FOTA。 link 我找到了一些溶胶,但我不明白如何进一步处理。
  • 我会告诉你我遵循的基本程序 - 1) 运行 make otapackage。让我们将其命名为 update.zip 2) 将 zip 文件复制到 /cache/recovery/update.zip 3) 在 /cache/recovery/command 中写入以下命令“--update_package=/cache/update.zip” 4) 重启设备在恢复模式。 5) 设备将自动升级。您可以在 /frameworks/base/core/java/android/os/RecoverySystem.java 中找到示例代码 我使用的应用程序是系统应用程序(使用平台密钥签名)

标签: android


【解决方案1】:

在 /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)

我已尝试了所有必需的权限,但无法继续。

因此,由于我使用的是 4.2 以上的 API,我尝试将我的应用程序放入 /system/priv-app,它对我有用。

【讨论】:

    【解决方案2】:

    系统应用(共享用户 ID 设置为 android.uid.system 的应用)无法在 Android 5 及更高版本上安装系统更新 - SELinux 政策禁止这样做。具体来说,系统应用程序禁止写入/cache。换句话说:

    • /cachesystem 用户所有,因此您在 system UID 下运行的应用程序可以对其进行写入。 但仅当 SELinux 被禁用/允许时。
    • 如果你有android.permission.ACCESS_CACHE_FILESYSTEM平台签名权限,可以写信给/cache

    您需要删除共享用户 ID。您仍然需要使用平台签名对应用进行签名,并确保您拥有以下权限:

    • android.permission.REBOOT
    • android.permission.ACCESS_CACHE_FILESYSTEM - 写信给/cache
    • android.permission.RECOVERY - API 21 需要重启才能恢复

    这同样适用于 Kitkat 和 Lollipop+。

    【讨论】:

    • 我已经包含了所有三个提到的权限,但仍然无法写信给/cache。 SELinux 是否总是需要允许才能写入 cache 或者这 3 个权限就足够了?
    • 如果是 SELinux 策略问题,您应该在 logcat 中看到 message。您的 /cache 中是否有足够的空间?我见过缓存分区最小的设备,您只能使用 /data 进行更新。
    • 我相信我的/cache 中有足够的空间,因为使用setenforce 0 解决了这个问题,但我不想让 SELinux 允许。我在问是否有必要让 SELinux 变得宽松,或者有其他方法可以在不更改 SELinux 的情况下使其工作。
    • @mahdi 你有没有想过一种方法来完成这项工作?我相信我在 Android 9 系统应用程序更新问题上也遇到了类似的问题,我真的不想完全禁用 SELinux(事实证明,搞清楚自定义策略非常困难......)
    • @GarryMcKee 我无法解决系统应用程序的问题。作为解决方法,如本答案中所述,我从清单中删除了 android.uid.system
    【解决方案3】:

    android 5.0.2 中创建自定义 OtaUpdate 应用程序时,我遇到了同样的问题,我已经解决了。我将通过以下2个步骤与您分享:

    1. 在 AndroidManifest.xml 中添加 android:sharedUserId="com.google.uid.shared"
    2. 将您的 apk 推送到 system/app 或 system/priv-app

    对于android 4.1.2

    1. 在 AndroidManifest.xml 中添加 android:sharedUserId="android.uid.system"
    2. 将您的 apk 推送到系统/应用程序

    【讨论】:

    • > 在 AndroidManifest.xml 中添加 android:sharedUserId="com.google.uid.shared" 如果您安装了 Google 应用程序,这将产生问题。只需确保该应用位于 system/priv-app 中就可以了。
    【解决方案4】:

    适用于 Android 5.1.0

    1. 在AndroidManifest.xml中添加android:sharedUserId="android.uid.system"
    2. 将你的apk推送到system/priv-app
    3. 然后

      adb root
      adb shell setenforce 0
      

    【讨论】:

      【解决方案5】:

      我在 android 8 中遇到了同样的问题。
      如果在AndroidManifest.xml 中添加android:sharedUserId="android.uid.system", 它应该工作。

      【讨论】:

        猜你喜欢
        • 2023-03-03
        • 2014-06-10
        • 2020-05-31
        • 2014-04-29
        • 2017-01-16
        • 1970-01-01
        • 1970-01-01
        • 2015-02-23
        • 2023-04-01
        相关资源
        最近更新 更多