android:sharedUserId="android.uid.system" 从 SDCard 获取文件

Posted

技术标签:

【中文标题】android:sharedUserId="android.uid.system" 从 SDCard 获取文件【英文标题】:android:sharedUserId="android.uid.system" Obtaining Files from SDCard 【发布时间】:2018-11-08 18:36:24 【问题描述】:

我在 android (SDK 19/KitKat 4.4.2) 中有一个场景,我的应用程序将使用 android:sharedUserId="android.uid 作为系统级应用程序 (App 1) 进行签名.system”在 Manifest.xml 中。这意味着此应用程序无法从 SD 卡写入或读取,无论它们是外部的还是内置于设备中的。

如果我需要从 SDCard 获取一个大文件并将其读入我的应用程序,那么最好的方法是什么?

我的目标只是从 SDCard 获取图像文件。但是,如果是未压缩的位图,即使图像也会相对较大。

我尝试了以下方法:

    创建一个未作为系统用户 (App2) 签名的新应用程序。从App1启动这个App2中存在的服务,然后从这里从SD卡读入文件,然后获取文件的byte[],发送出去通过 AIDL 到 App1 的块。这适用于从 SDCard 读取文件并将其发送过来,但是 AIDL 的每个事务的上限为 1mb,而且速度也非常慢,以至于我可能应该限制允许提供给应用程序的图像大小使此功能可用。在我看来不是最理想的。

    我尝试在 App 2 (UID: 10007) 中使用 FileProvider,但是在这种情况下,我不需要打开任何图形界面来选择我想要的文件和目标应用程序.我需要立即将其发送到 App 1 (UID: 10047) 或立即从 App1 获取。我不确定是否可以在没有这些 gui 步骤的情况下使用 FileProvider。我尝试从 App2 创建 Uri,然后通过 AIDL 将 Uri 发送到 App1,然后通过 context.grantUriPermissions(packageName,uri,READ/WRITE) 授予权限,但总是最终出现安全错误,其中 App1 无权读取 App2 提供的 uri。

java.lang.SecurityException:未找到 UID 10047 和 Uri content://com.test.sdcard/folder/img.png 的权限授予

其中 UID 10047 是 App 1,而 UID 10007 是 App 2

此问题的任何替代解决方案?

【问题讨论】:

【参考方案1】:

系统应用无法从外部存储中读取?这对我来说是个新闻,但无论如何。

您始终可以只创建一个管道并将读取端传递回您选择的 IPC 机制(例如ContentProvider.call())。服务端启动一个线程,将文件写入写端,将读端传回客户端。服务端是这样的:

  ParcelFileDescriptor[] fds;
  try 
    fds = ParcelFileDescriptor.createPipe();
   catch (IOException e) 
    e.printStackTrace();
    return false;
  

  final ParcelFileDescriptor readFd = fds[0];
  final ParcelFileDescriptor writeFd = fds[1];

  // TODO: start a thread to write file to writeFd

  Bundle result = new Bundle();
  extras.putParcelable(EXTRA_READ_FD, readFd);

  return result; // Return from call() to client

显然有很多样板代码留给读者练习。

【讨论】:

正在努力使用这种方法。您能否举例说明如何将数据写入 writeEnd,然后使用 readEnd 读回数据?我正在关注这个***.com/questions/18212152/…,这似乎与您的建议相似,但我遇到了 java.io.IOException 提到的错误:读取失败:EBADF (Bad file number) 没关系,使用 getFileDescriptor(byte[] data) sn-p 从这里设法弄清楚。 ***.com/questions/51902834/… 我担心服务端线程的启动以及客户端对描述符的读取。在您提供的 sn-p 中,客户端似乎可以在实际上有任何要读取的数据之前检索 readEnd,假设您生成了一个线程来写入 writeEnd。我尝试在线程中实现延迟(thread.sleep)以在服务端写入,但我的客户端似乎能够很好地读取数据(尽管延迟),尽管我尽快在客户端开始读取因为这会导致您的 sn-p 返回。为什么会这样? 如果没有写入读端(还),IO 将阻塞。管道仍然打开。把它想象成一个网络请求,服务器还没有返回任何数据。网络请求不会因为没有数据可读取而失败。 这是对我有用的有效方法,谢谢。

以上是关于android:sharedUserId="android.uid.system" 从 SDCard 获取文件的主要内容,如果未能解决你的问题,请参考以下文章

android:sharedUserId作用

让Android Studio支持系统签名

让Android Studio支持系统签名

protected-broadcast 系统应用自定义广播规范

Android 禁用(隐藏)图标

android 系统签名