web-dev-qa-db-fra.com

SecurityException avec grantUriPermission lors du partage d'un fichier avec FileProvider

J'ai deux applications. J'essaie de partager un fichier de l'application A vers l'application B à l'aide d'un FileProvider. L'application A appelle la méthode d'insertion sur un ContentProvider dans l'application B pour insérer un enregistrement. Les données insérées incluent l'URI du fichier que je souhaite partager à partir de l'application A. Le ContentProvider de l'application B essaierait alors de lire le fichier partagé à partir de l'application A. Étant donné que je n'utilise pas l'intention de partager le fichier, je suis appelant Context.grantUriPermission dans l'App A pour permettre la lecture (et parfois l'écriture):

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

Cependant, l'exécution de cette ligne me donne (les noms ont été modifiés pour protéger les innocents):

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...

L'application A contient les éléments suivants dans le fichier manifeste:

<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 a:

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

L'App A et l'App B ont les éléments suivants:

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

J'ai essayé de définir les autorisations dans les deux applications. Ils sont tous deux signés avec la même signature de débogage:

<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>

Le chemin d'accès réel du fichier est:

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

À ce stade, je suis perplexe. Je ne sais pas pourquoi je ne peux pas accorder l'autorisation pour un fichier que je viens de créer dans la même application. Mes questions sont donc les suivantes: pourquoi ai-je cette exception et comment puis-je accorder avec succès l'autorisation à l'App B?

16
DavidsAlias

Eh bien, après une semaine et beaucoup d'essais et d'erreurs, il semble que la réponse soit de ne pas spécifier les autorisations. Ainsi, le manifeste App A devrait plutôt contenir:

<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>

c'est-à-dire que j'ai supprimé les autorisations de lecture et d'écriture. Ma compréhension initiale, et le fait de ne pas avoir trouvé de documentation indiquant le contraire, était nécessaire pour restreindre l'accès. Cependant, j'ai découvert qu'ils interfèrent réellement et causent Context.grantUriPermission échouer. L'accès est déjà limité.

Pour compléter le tableau et répondre à la deuxième partie de ma question, j'ai trouvé ce qui suit:

refus d'autorisation Android dans Widget RemoteViewsFactory for Content

J'ai dû ajouter:

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

au fournisseur de contenu dans l'application B. Sinon, cela entraînerait également des erreurs de sécurité.

17
DavidsAlias