Android VirtualBox 下的应用权限问题运行

Android app permission problem running under VirtualBox

我正在尝试 运行 使用安装在 VirtualBox 上的 Android ISO 为我的应用程序进行连接测试。我从 http://www.android-x86.org/ 获得了 Android 7.1 ISO。它安装在 VirtualBox 下,似乎工作正常。

我们的应用程序使用 PocketSphinx 创建一些目录并在其中存储一些文件。该应用程序可在某些 Android 7.0 平板电脑和 Android Studio 附带的模拟器下正常运行。有时,它在 VirtualBox 下可以正常工作,但它会进入某种奇怪的状态,无法读取或写入所需的目录。

Android清单包含此权限(以及其他权限):

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

权限在设置=>应用程序=>[我们的应用程序]=>权限中显示为已启用。

这是实际的错误消息:

W/System.err: java.io.FileNotFoundException: /storage/emulated/0/Android/data/com.hcs.android.orconnect/files/sync/cmudict-en-us.dict (No such file or directory)
                  at java.io.FileOutputStream.open(Native Method)
                  at java.io.FileOutputStream.<init>(FileOutputStream.java:221)
                  at java.io.FileOutputStream.<init>(FileOutputStream.java:169)
                  at edu.cmu.pocketsphinx.Assets.copy(Assets.java:224)
                  at edu.cmu.pocketsphinx.Assets.syncAssets(Assets.java:269)

如果我在这个调用之前设置断点,我可以看到所有这些 return false:

new File("/storage/emulated/0/Android/data/").canRead()
new File("/storage/emulated/0/Android/data/").canWrite()
new File("/storage/emulated/0/Android/data/com.hcs.android.orconnect").canRead()
new File("/storage/emulated/0/Android/data/com.hcs.android.orconnect").canWrite()

但是,某些东西创建了 /storage/emulated/0/Android/data/com.hcs.android.orconnect/files 文件夹。如果我从 adb shell 提示中手动删除此文件夹,它将在我的应用程序测试的下一个 运行 中重新创建,但该应用程序仍然存在相同的问题。

我真的不知道为什么我会遇到这些权限问题。关于正在发生的事情以及如何修复权限有什么想法吗?

(注意:我不想使用Android模拟器,因为我们运行宁VirtualBox出于其他原因,两者不会互相玩。)

(注意:不出所料,从调试器 运行 运行应用程序显示的问题与我 运行 连接测试时遇到的问题相同。)

重现步骤:

  1. 设置并启动 VirtualBox 映像 运行使用 Android 7.1 ISO。
  2. 运行 adb connect <ip address>
  3. 运行 ./gradlew connectAndroidTest
  4. 测试将通过
  5. 运行 ./gradlew connectAndroidTest
  6. 测试将失败并且所有未来的 运行s 也会失败。

解决方法:

  1. 安装应用程序(如果当前未安装)
  2. 在设置 => 应用 => [我的应用]
  3. 中调整 "Storage" 权限

将问题追踪到 Android 对权限的处理不一致。

我们应用程序的清单包含:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

这导致 /data/system/users/0/runtime-permissions.xml 包含:

<item name="android.permission.READ_EXTERNAL_STORAGE" granted="true" flags="0" />^M     
<item name="android.permission.WRITE_EXTERNAL_STORAGE" granted="true" flags="0" />^M

读取是隐式 g运行ted。但是,在编写连接测试时,我使用了 g运行t 权限规则:

@Rule public GrantPermissionRule permissionRule2 = GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);

然而,这 不是 隐含 g运行t 读取权限。因此,当应用程序首次在 VM 上 运行 时,它被 g运行ted 显式 WRITE 和隐式 READ。但是,gradlew 运行 第一次测试后,它会卸载应用程序。然后下一个测试 运行 将重新安装该应用程序,但根据规则只授予它 WRITE 权限。然后如上所述测试失败。

所以,解决方法是在测试中请求读写权限:

@Rule public GrantPermissionRule permissionRule2 = GrantPermissionRule.grant(android.Manifest.permission.READ_EXTERNAL_STORAGE);
@Rule public GrantPermissionRule permissionRule25 = GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);

没关系,这与我的 AndroidManifest.xml 文件不匹配。 Google的左手和右手从未见过面,所以行为不同。

谢谢,Google! /s