web-dev-qa-db-ja.com

FileProviderでファイルを共有するときに、grantUriPermissionを伴うSecurityException

2つのアプリケーションがあります。 FileProviderを使用して、アプリケーションAからアプリケーションBにファイルを共有しようとしています。アプリケーションAは、アプリケーションBのContentProviderでinsertメソッドを呼び出して、レコードを挿入します。挿入されたデータには、アプリAから共有したいファイルへのURIが含まれています。アプリBのContentProviderは、アプリAから共有ファイルを読み取ろうとします。ファイルを共有するインテントを使用していないため、アプリ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>

アプリAとアプリ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に許可を与えるにはどうすればよいですか。

16
DavidsAlias

1週間と多くの試行錯誤の後、答えはアクセス許可を指定しないことです。そのため、App A Manifestは代わりに以下を含む必要があります:

<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 失敗する。アクセスはすでに制限されています。

絵を完成させ、私の質問の2番目の部分に答えるために、以下を見つけました。

コンテンツのウィジェットRemoteViewsFactoryでのAndroidアクセス許可の拒否

追加する必要がありました:

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

アプリBのコンテンツプロバイダーに送信します。それ以外の場合は、セキュリティエラーも発生します。

17
DavidsAlias