Android KitKat securityException when trying to read from MediaStore

别等时光非礼了梦想. 提交于 2019-11-26 04:46:45

问题


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\" />

回答1:


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.




回答2:


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




回答3:


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?




回答4:


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




回答5:


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.




回答6:


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.



来源:https://stackoverflow.com/questions/19837358/android-kitkat-securityexception-when-trying-to-read-from-mediastore

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!