46

java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{430b1748 29271:com.x.x.x/u0a88} (pid=29271, uid=10088) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS

I've added the MANAGE_DOCUMENTS and READ_EXTERNAL_STORAGE permissions but I am still getting this error. The offending code:

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

As requested snippet of manifest:

<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" />
Nitesh Verma
  • 2,460
  • 4
  • 20
  • 36
serenskye
  • 3,467
  • 5
  • 35
  • 51
  • 1
    Have you correctly added the permission? perhaps post the manafest? – Broak Nov 07 '13 at 13:38
  • 1
  • 1
  • 1
    you need to post the whole manafest – Broak Nov 07 '13 at 16:04
  • The manifest is fine, its too big to post and I wouldn't want to reveal that much of the codebase - it won't be useful. Those are the permissions I've added above. – serenskye Nov 07 '13 at 16:16
  • 2
    I'm in the same point. Mi app works with < 4.4 android version, but don't work in a Nexus 5 ( 4.4) – Jose Manuel Nov 11 '13 at 15:50
  • @serenskye - it's important that you post the full manifest or otherwise verify it correctly implemented, as adding the permissions in the wrong place in the file is one of the common mistakes people make. Consider creating a minimal example which exercises only this function and reveals nothing proprietary (you must just luck out and find it works, too) Otherwise you are on your own to solve this. – Chris Stratton Nov 11 '13 at 20:24
  • Hi Chris, - its very simple to add a permission, this app has many permissions already - I'm not sure how that could possibly be messed up – serenskye Nov 13 '13 at 10:57
  • Someone has told me "it seems that the application used in Nexus 5 allows only apps with the same signature to pick photos. " – serenskye Nov 13 '13 at 11:03
  • Maybe you have to use [UriPermission](http://developer-android-com-mpfnytpd1hu3.runscope.net/reference/android/content/UriPermission.html). it's new in KitKat, from API 19. I think your manifest is correct. – Álvaro Nov 19 '13 at 15:00
  • Visit also the new [Storage Access Framework](https://developer.android.com/guide/topics/providers/document-provider.html) – Álvaro Nov 19 '13 at 15:06
  • I'm not compiling against 19 though – serenskye Nov 19 '13 at 15:23
  • Same problem with my app on my Nexus 4(kitkat updated).The app used to work fine on on Android 4.3.I need to find a fix soon. – Amel Jose Nov 22 '13 at 15:21

6 Answers6

44

Had the same problem for the last couple of days. Tried a few solutions, but for some reason I was getting permission denial on Uri content provider for some images even when I had the android.permission.MANAGE_DOCUMENTS permission added to my manifest.

Here's a workaround, for the time being:

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

This forces the older image gallery to open instead of the new Kitkat documents view.

Now, you can get the Uri by calling the following in your onActivityResult:

Uri selectedImageURI = data.getData();

Hope this helps.

rahulritesh
  • 860
  • 1
  • 9
  • 17
13

In the Intent used to prompt the user to add a file, use Intent.ACTION_OPEN_DOCUMENT (on KitKat API 19 or higher) instead of Intent.ACTION_GET_CONTENT or Intent.ACTION_PICK. Then, when you want to use the Uri, take the previous persistent permissions that were set by Intent.ACTION_OPEN_DOCUMENT as described in @feri's link ( 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);

You can read more about the differences between Intent.ACTION_GET_CONTENT, Intent.ACTION_PICK, and Intent.ACTION_OPEN_DOCUMENT here: http://developer.android.com/reference/android/content/Intent.html#ACTION_OPEN_DOCUMENT

Tony Wickham
  • 4,706
  • 3
  • 29
  • 35
12

OK, I found a working sample that gets past the issue:

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

Here's what I've learned...this is a change in KitKat, and this code only works on API 19 and up. It will not work for older versions so you need to have methods for pre-KitKat as well. Once you get the file using the Category_Openable argument, in my case an image, you can then use it by referencing it as the URI. In my case, I store the URIString (file path) and I'm able to do what I want with it after the open occurs.

The issue I'm now trying to figure out is how long the file permissions persist. It appears that it expired since yesterday, as my code looks for the UriString, then tries to open the file. If I use the code above to select the image, it works - it stores the name, and I was able to exit the program, go back in and it still worked...however, my first run of the program this morning (after not touching it in 12+ hours), it acted like it couldn't find the file (and I'm sure if watching through the debugger, I'd see the non-critical error appear again.

So now the question is: How do we persist the permissions once I know what the file (name) is?

user1082348
  • 229
  • 2
  • 10
3

I assume the Uri you want to show references an image from a provider which implements the new Storage Access Framework introduced with Android 4.4 KitKat. This can be Gallery as well as Google-Drive. The only way to access theese documents seems to be to use the system file picker. If the user selects files for opening, the system grants permission to the app, which started the file open dialog. Theese permissions are valid as long as the device is not rebootet. Other images can not be accessed and lead to the Security Exception.

If the Uri is be persisted, then the rights granted to access the Uri must also be persisted. For more details look here: https://developer.android.com/guide/topics/providers/document-provider.html#permissions

feri
  • 69
  • 2
3

The MANAGE_DOCUMENTS permission can be hold only by the system :

The MANAGE_DOCUMENTS permission. By default a provider is available to everyone. Adding this permission restricts your provider to the system. This restriction is important for security.

(taken from Storage Access Framework)

So by using this permission in your DocumentProvider you are restricting the access to your provider to only the system. What this means is that only the System UI picker will be able to access your files. So in order for an app to pick a file from your Provider it will have to launch an Intent with ACTION_OPEN_DOCUMENT, which will in fact launch the System UI picker, the user will choose a file from there, and then the URI will be returned to you.

Ovidiu Latcu
  • 71,607
  • 15
  • 76
  • 84
0

The solution seems to be using http://developer.android.com/guide/topics/providers/document-provider.html#client instead to access images from the gallery

I'm not sure why the other approach does not work. But its a short term fix for now.

serenskye
  • 3,467
  • 5
  • 35
  • 51