web-dev-qa-db-fra.com

Android KitKat securityException lors d'une tentative de lecture à partir de MediaStore

Java.lang.SecurityException: refus d'autorisation: ouverture du fournisseur com.Android.providers.media.MediaDocumentsProvider de ProcessRecord {430b1748 29271: com.xxx/u0a88} (pid = 29271, uid = 10088) nécessite Android.permission.DEMUMENTS ou Android. permission.MANAGE_DOCUMENTS 

J'ai ajouté les autorisations MANAGE_DOCUMENTS et READ_EXTERNAL_STORAGE mais je reçois toujours cette erreur. Le code incriminé:

 public static String getImagePath(HailoDriverApplication app, Uri uri) {
    Cursor cursor = null;
    if (uri == null) {
        return null;
    }
    try {
        cursor = app.getContentResolver().query(uri, new String[] {
            MediaStore.Images.Media.DATA
        }, null, null, null);
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        if (cursor.moveToFirst()) {
            return cursor.getString(column_index);
        }
    } finally {
        if (cursor != null) {
            cursor.close();
        }
    }
    return null;
}

Comme demandé extrait du manifeste:

<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
package="com.x.x.x" >

<uses-sdk
    Android:minSdkVersion="8"
    Android:targetSdkVersion="16" />

<uses-permission Android:name="Android.permission.INTERNET" />
<uses-permission Android:name="Android.permission.VIBRATE" />
<uses-permission Android:name="Android.permission.ACCESS_NETWORK_STATE" />
<uses-permission Android:name="Android.permission.ACCESS_COURSE_LOCATION" />
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION" />
<uses-permission Android:name="Android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission Android:name="Android.permission.WAKE_LOCK" />
<uses-permission Android:name="Android.permission.READ_LOGS" />
<uses-permission Android:name="Android.permission.READ_PHONE_STATE" />
<uses-permission Android:name="Android.permission.READ_CONTACTS" />
<uses-permission Android:name="Android.permission.CHANGE_WIFI_STATE" />
<uses-permission Android:name="Android.permission.ACCESS_WIFI_STATE" />
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission Android:name="Android.permission.MANAGE_DOCUMENTS" />
<uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission Android:name="com.google.Android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission
    Android:name="Android.permission.UPDATE_DEVICE_STATS"
    tools:ignore="ProtectedPermissions" />
<uses-permission Android:name="Android.permission.WRITE_SETTINGS" />
<uses-permission Android:name="Android.intent.action.BATTERY_CHANGED" />
<uses-permission
    Android:name="Android.permission.INSTALL_PACKAGES"
    tools:ignore="ProtectedPermissions" />
<uses-permission Android:name="Android.permission.GET_ACCOUNTS" />
<uses-permission Android:name="com.google.Android.c2dm.permission.RECEIVE" />
45
serenskye

A eu le même problème pour les deux derniers jours. J'ai essayé quelques solutions, mais pour une raison quelconque, je obtenais un refus de permission sur le fournisseur de contenu Uri pour certaines images, même si j'avais l'autorisation Android.permission.MANAGE_DOCUMENTS ajoutée à mon manifeste.

Voici une solution de contournement, pour le moment:

i = new Intent(Intent.ACTION_PICK, Android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i, CHOOSE_IMAGE);

Cela force l’ancienne galerie d’images à s’ouvrir à la place de la nouvelle vue Documents KitKat.

Maintenant, vous pouvez obtenir l’Uri en appelant ce qui suit dans votre onActivityResult:

Uri selectedImageURI = data.getData();

J'espère que cela t'aides.

45
rahulritesh

Dans l'intention utilisée pour inviter l'utilisateur à ajouter un fichier, utilisez Intent.ACTION_OPEN_DOCUMENT (sur KitKat API 19 ou supérieure) au lieu de Intent.ACTION_GET_CONTENT ou Intent.ACTION_PICK. Ensuite, lorsque vous souhaitez utiliser l'URI, utilisez les autorisations persistantes précédentes définies par Intent.ACTION_OPEN_DOCUMENT comme décrit dans le lien de @feri ( https://developer.Android.com/guide/topics/providers/document-provider .html # permissions ):

final int takeFlags = data.getFlags()
        & (Intent.FLAG_GRANT_READ_URI_PERMISSION
        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
// Check for the freshest data.
getContentResolver().takePersistableUriPermission(originalUri, takeFlags);

Pour plus d'informations sur les différences entre Intent.ACTION_GET_CONTENT, Intent.ACTION_PICK et Intent.ACTION_OPEN_DOCUMENT, cliquez ici: http://developer.Android.com/reference/Android/content/Intent.html#ACTION_OPEN_DOCUMENT

12
Tony Wickham

OK, j'ai trouvé un exemple de travail qui résout le problème:

            intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
            intent.addCategory(Intent.CATEGORY_OPENABLE);
            intent.setType("image/*");
            startActivityForResult(intent, myClassConstant.SELECT_PICTURE);

Voici ce que j'ai appris ... Il s'agit d'un changement de KitKat et ce code ne fonctionne que sur les API 19 et supérieures. Cela ne fonctionnera pas pour les versions plus anciennes, vous devez donc également disposer de méthodes pour pré-KitKat. Une fois que vous obtenez le fichier en utilisant l’argument Category_Openable, dans mon cas une image, vous pouvez l’utiliser en le référençant en tant qu’URI. Dans mon cas, je stocke l'URIString (chemin du fichier) et je peux en faire ce que je veux après l'ouverture.

Le problème que j'essaie maintenant de comprendre est la durée pendant laquelle les autorisations de fichiers sont conservées. Il semble qu’il ait expiré depuis hier, alors que mon code cherche UriString, puis tente d’ouvrir le fichier. Si j’utilise le code ci-dessus pour sélectionner l’image, cela fonctionne - il enregistre le nom, et j’ai pu quitter le programme, y retourner et cela fonctionnait toujours ... cependant, ma première exécution du programme ce matin (après pas plus de 12 heures), il agissait comme s'il ne pouvait pas trouver le fichier (et je suis sûr que si vous regardez à travers le débogueur, je verrais l'erreur non critique réapparaître. 

Alors maintenant, la question est la suivante: comment conserver les autorisations une fois que je connais le fichier (nom)?

11
user1082348

Je suppose que l'Uri que vous voulez montrer fait référence à une image d'un fournisseur qui implémente le nouveau Storage Access Framework introduit avec Android 4.4 KitKat . Cela peut être aussi bien la Galerie que Google-Drive . Les documents semblent utiliser le sélecteur de fichiers système . Si l'utilisateur sélectionne les fichiers à ouvrir, le système accorde l'autorisation à l'application, ce qui a ouvert la boîte de dialogue d'ouverture de fichier. Ces autorisations sont valables tant que le périphérique n'est pas redémarré. Les autres images ne sont pas accessibles et mènent à l'exception de sécurité.

Si l’Uri est maintenu, les droits accordés pour accéder à l’Uri doivent également être préservés. Pour plus de détails, regardez ici: https://developer.Android.com/guide/topics/providers/document-provider.html#permissions

3
feri

La permission MANAGE_DOCUMENTS ne peut être conservée que par le système:

L'autorisation MANAGE_DOCUMENTS. Par défaut, un fournisseur est disponible pour tout le monde. L'ajout de cette autorisation restreint votre fournisseur au système. Cette restriction est importante pour la sécurité.

(extrait de Storage Access Framework )

Donc, en utilisant cette autorisation dans votre DocumentProvider, vous limitez l'accès à votre fournisseur au seul système. Cela signifie que seul le System UI picker pourra accéder à vos fichiers. Ainsi, pour qu'une application choisisse un fichier dans votre Provider, elle devra lancer une Intent avec ACTION_OPEN_DOCUMENT, qui lancera en fait le System UI picker, l'utilisateur choisira un fichier à partir de là, puis la URI vous sera renvoyée.

3
Ovidiu Latcu

La solution semble utiliser http://developer.Android.com/guide/topics/providers/document-provider.html#client à la place pour accéder aux images de la galerie.

Je ne sais pas pourquoi l'autre approche ne fonctionne pas. Mais c'est une solution à court terme pour le moment. 

0
serenskye