【问题标题】:What options are available to solve an intermittent Permission Denial SecurityException?有哪些选项可用于解决间歇性 Permission Denial SecurityException?
【发布时间】:2014-09-26 16:42:33
【问题描述】:

我设置了一个ContentProvider,仅供我的应用内部使用,以响应带有流的 URI,通过该流我构造并提供一个 zip 文件。

Uri 作为额外的 (Intent.EXTRA_STREAM) 传递给 Intent (Intent.ACTION_SEND) 以便发送。但是,这样做时,它会间歇性地失败并出现以下异常:

E/DatabaseUtils(26058): java.lang.SecurityException: Permission Denial: reading MyContentProvider uri content://spinner.myapp.db/file/stream/zip/1 from pid=26141, uid=10038 requires the provider be exported, or grantUriPermission()

我尝试通过intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 授予权限,但没有成功。我也不明白为什么需要授予权限,因为只有我自己的应用程序在访问ContentProvider

更新:

我现在也尝试使用setClipData(),但没有更多成功。 Gmail 显然忽略了 Uri,Dropbox 崩溃了。

String[] mimeTypes = { "application/x-compressed" };
ClipData clip = new ClipData("zip data", mimeTypes, new ClipData.Item(uri));
intent.setClipData(clip);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

【问题讨论】:

  • 这是您可以重现的东西,还是您至少在测试中看到的东西?或者您是否从生产应用程序中获得这些异常?如果是后者,则可能是某些脚本小子正在尝试访问内容。而且,如果这真的只适用于您自己的应用程序......为什么您首先要使用流媒体ContentProvider
  • @CommonsWare 目前仅限于我的应用程序开发版本。我一直在使用 ContentProvider,因为它似乎是最适合我的应用程序的模式(包括使用 Loaders 等)。
  • 我当然可以看到Loader 用于数据库样式内容的参数,即使我不使用那种特定的方法。不过,我还没有看到通过ContentProvider 进行应用内流式传输的任何价值。话虽这么说,我不明白你是如何得到这个例外的。当它出现时,piduid 是你的吗?还是您不小心尝试将此Uri 传递给第三方应用?
  • @CommonsWare 我不认为piduid 是我的。他们是谁,我不知道。我只是设置一个 Intent 如下:Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("application/x-compressed"); intent.putExtra(Intent.EXTRA_STREAM, Uri.parse(MyContentProvider.CONTENT_URI_FILE_ZIP_STREAM + "/1"); 之后,我使用Intent.createChooser() 选择要发送文件的应用程序(Gmail、Dropbox 等)。
  • “因为只有我自己的应用程序在访问 ContentProvider”——不,不是。您不是 Gmail 的作者,如果您是,那么您也不是 Dropbox 的作者。您也不是许多其他应用程序的作者,这些应用程序会为 ACTION_SEND 提供 application/x-compressed MIME 类型。在较新版本的 Android 上,grantUriPermissions() 应该可以工作,但以前只适用于 Uri,它是 Intent 的“数据”,而不是打包在附加组件中的 Uri

标签: java android android-intent uri android-securityexception


【解决方案1】:

啊,我明白了,所以发送应用程序必须为每个 Uri 授予自己的权限,而不是由调用应用程序的 Intent 隐式提供?

我对你的术语感到困惑,所以让我试试这个方法:

有四种基本方法可以实现ContentProvider

  1. 将其导出且不受任何权限保护。这是愚蠢的。不要这样做。

  2. 已将其导出但受权限保护(例如,android:readPermissionandroid:writePermission 属性)。这很好用,但仅适用于专门编写用于与您的ContentProvider 交谈的应用程序。它不适用于先验了解您的ContentProvider 的应用,例如大多数支持ACTION_SEND 活动的实施者。

  3. 不要将其导出,而是让您为特定请求授予对 Uri 的权限。通常,这是通过将activity flags like FLAG_GRANT_READ_URI_PERMISSION 添加到与startActivity() 一起使用的Intent 来完成的,尽管还有其他方法,例如您自己调用grantUriPermission()。如果您是需要第三方访问您的提供商的发起者,例如使用 ACTION_SEND Intent 启动活动,这非常有用。

  4. 不要将其导出,也不要授予Uri 的权限。在这种情况下,ContentProvider 仅在您自己的应用程序中可用,即使您提出要求(例如,您的 ACTION_SEND 请求),第三方也根本无法访问。

如何为最终被选中执行发送的应用授予权限,还是必须将其授予所有可能的应用?

我的一条评论出现了错误,对此我深表歉意。

FLAG_GRANT_READ_URI_PERMISSION 现在授予对Intent 中的Uri 的读取访问权限,无论UriIntent 的“数据”还是额外的。这将被授予Intent 的最终消费者——换句话说,选择器不会以某种方式使用权限并且选择的活动没有权限。然而,过去FLAG_GRANT_READ_URI_PERMISSION 仅适用于“数据”,而不适用于附加内容中的Uri 值,而且我完全忘记了该缺陷是何时修复的。

grantUriPermission() 要求您知道Intent 的最终消费者是谁,这意味着您需要推出自己的“选择器”,以便找出用户想要处理您提议的实际应用ACTION_SEND 请求。

FWIW,here is a sample app,演示了使用 FLAG_GRANT_READ_URI_PERMISSION 来查看由 FileProvider 提供的 PDF。

【讨论】:

  • 我的目标是 Android 4.3(版本 18)和 minSdkVersion="15",我想我遇到了你提到的问题,FLAG_GRANT_READ_URI_PERMISSION 仅在通过 @ 设置的 Uri 上运行987654356@,而不是putExtra()。不幸的是,将Uri 设置为数据而不是额外的似乎并不适合发送文件,例如附件(Gmail 将Uri 放入 To 字段,并且Dropbox 只是崩溃)。我已查找有关此更改的文档,但尚未找到任何文档。
  • 我发现在documentation for ACTION_SEND 中提到了这种改变的行为,特别提到了setClipData() 的使用。不过,还不能让它工作; Dropbox 仍然只是崩溃,Gmail 没有附加任何文件。
  • @Spinner:我必须为此编写一些示例。 setClipData() 的问题是客户还需要更改为使用ClipData,可能很多人不需要。特别是,如果 Dropbox 因与以前相同的错误而崩溃,他们可能根本没有注意ClipData,而只是使用Uri(并因此失败)。不过,我不知道为什么 Gmail 不会崩溃但不会附加文件,除非整个 Uri 无效。
  • 您是否了解导致FLAG_GRANT_READ_URI_PERMISSION 处理附加组件的确切更改发生时间?由于 setClipData() 更改是在 Jelly Bean 中进行的,所以人们会认为它在那时出现了;但是,由于我在 4.3 上运行,这意味着更改仅在 4.4 中进行。这是假设我的设置运行正常。
  • @Spinner: setClipData() 从 4.1 开始就存在了。话虽如此,我现在很难找到我的参考,如果/当FLAG_GRANT_READ_URI_PERMISSION 与附加功能一起使用。我可能记错了。
猜你喜欢
  • 1970-01-01
  • 2013-09-21
  • 2014-02-22
  • 1970-01-01
  • 2015-07-31
  • 2010-09-29
  • 2016-09-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多