使用FileProvider共享文件时出现授予权限的SecurityException异常

18

我有两个应用程序。我正在尝试使用FileProvider从应用程序A共享文件到应用程序B。应用程序A调用应用程序B中的ContentProvider上的insert方法以插入记录。插入的数据包括我想要从App A共享的文件的Uri。然后,App B中的ContentProvider将尝试从App A读取共享的文件。 由于我没有使用Intent来共享文件,因此在App A中调用Context.grantUriPermission以允许读取(有时还能写入):

mContext.grantUriPermission(MyPackageName, contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

但是,执行这行代码会给我返回以下结果(名称已更改以保护隐私):

java.lang.SecurityException: Uid 10066 does not have permission to uri content://au.com.example.AppA.fileprovider/MyFolder/MyFileName
at android.os.Parcel.readException(Parcel.java:1322)
at android.os.Parcel.readException(Parcel.java:1276)
at android.app.ActivityManagerProxy.grantUriPermission(ActivityManagerNative.java:2374)
at android.app.ContextImpl.grantUriPermission(ContextImpl.java:1371)
at android.content.ContextWrapper.grantUriPermission(ContextWrapper.java:400)
at etc...

应用程序A在清单文件中具有以下内容:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="au.com.example.AppA.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true"
    android:readPermission="au.com.example.READ_CONTENT"
    android:writePermission="au.com.example.WRITE_CONTENT" >
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>

filepaths.xml 包含:

<paths>
    <files-path
        name="MyFolder"
        path="MyFolder/" />
</paths>

App A和App B都具有以下功能:

<uses-permission android:name="au.com.example.READ_CONTENT" />
<uses-permission android:name="au.com.example.WRITE_CONTENT" />

我已经尝试在两个应用程序中定义权限。它们都使用相同的调试签名:

<permission
    android:name="au.com.example.READ_CONTENT"
    android:permissionGroup="MyGroup"
    android:protectionLevel="signature" >
</permission>
<permission
    android:name="au.com.example.WRITE_CONTENT"
    android:permissionGroup="MyGroup"
    android:protectionLevel="signature" >
</permission>

文件实际存储的路径是:

/data/data/au.com.example.AppA/files/MyFolder

目前我陷入了困境。我不知道为什么无法在同一应用程序中授予刚创建的文件权限。因此,我的问题是:为什么会出现这种异常情况,我该如何成功地向应用程序B授予权限?

2个回答

19

好的,经过一周的尝试和错误,看起来答案是不指定权限。因此,App A清单应该包含:

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="au.com.example.AppA.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true" >
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/filepaths" />
</provider>

我取消了读写权限。最初我的理解,并且找不到说明相反的文档,认为这些权限是必要的以限制访问。然而,我发现它们实际上会干扰并导致Context.grantUriPermission失败。访问已经受到限制。

为了完整地描述情况并回答我的问题的第二部分,我找到了以下内容:

Android Permission denial in Widget RemoteViewsFactory for Content

我不得不添加:

final long token = Binder.clearCallingIdentity();
try {
    [retrieve file here]
} finally {
    Binder.restoreCallingIdentity(token);
}

否则,它也会因安全错误而无法访问App B中的内容提供者。


我也遇到了这个问题,已经从清单中删除了读取权限,但仍然出现“Caused by: java.lang.SecurityException: Permission Denial: opening provider android.support.v4.content.FileProvider from ProcessRecord{40b7b968 7764:com.google.android.gm/10018} (pid=7764, uid=10018) requires null or null”错误。 - StuStirling
@DiscoS2 我也遇到了同样的问题。我发现卸载并重新安装应用程序可以解决它。我没有检查,但我怀疑可能存在某种清单缓存。 - DavidsAlias
2
如果您没有使用签名级别的权限,那么您的应用程序是否会面临外部威胁,可以读取任何具有正确Uri的文件? - Toochka
@Toochka 在非常特定的情况下,临时授权您限制访问权限。请查看有关 FileProvider 的文档。 - DavidsAlias

-4
你代码中的第一个问题是导出属性设置为false。请将其更改为true,如下所示:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="au.com.example.AppA.fileprovider"
android:exported="true"
android:readPermission="au.com.example.READ_CONTENT"
android:writePermission="au.com.example.WRITE_CONTENT" >
</provider>

第二件事情是,如果外部应用程序B正在使用应用程序A中的内容提供程序。那么在应用程序A的清单文件中,必须将权限声明为:
<permission
android:name="au.com.example.READ_CONTENT"
 >
</permission>
<permission
android:name="au.com.example.WRITE_CONTENT"
 >
</permission>

在应用程序B中,将uses-permission声明为:

<uses-permission android:name="au.com.example.READ_CONTENT" />
<uses-permission android:name="au.com.example.WRITE_CONTENT" />

请告诉我您的问题是否已经解决。如果没有,请发送您的全部代码。 我会尝试找到问题。 谢谢。

1
我最终解决了这个问题。请查看被接受的答案。Exported=true将允许访问具有列出权限的任何应用程序。我试图从一个应用程序分享到另一个应用程序,而不是任何应用程序。 - DavidsAlias
你是指临时权限吗? - srikanth kumar
4
FileProvider 会检查 android:exported="true",如果为真则会抛出异常。 - WindRider

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接