Android Permission denial in Widget RemoteViewsFac

2019-01-23 06:07发布

问题:

I have a widget which I am trying to use to display information from my app's local database inside of a listview.

I'm using the RemoteViewsService.RemoteViewsFactory interface to load my list's contents. If I run the block of code which reloads the list in the onDataSetChanged method. the app crashes with the following message:

11-01 16:40:39.540: E/ACRA(27175): DataDisplay fatal error : Permission Denial: reading com.datadisplay.content.ContentProviderAdapter uri content://com.datadisplay.provider.internalDB/events from pid=573, uid=10029 requires the provider be exported, or grantUriPermission()

However, this same code run in the class's constructor works just fine. Of course, I need to have this also work in the onDataSetChanged method for updating and stuff.

Here is my provider's entry in the manifest:

    <provider android:name="com.datadisplay.content.ContentProviderAdapter"
        android:authorities="com.datadisplay.provider.internalDB"
        android:exported="true"
        android:enabled="true"
        android:grantUriPermissions="true">
            <grant-uri-permission android:pathPattern="/events/"/>
    </provider>

I am both exporting it AND granting Uri permissions like the error message requests, but it still fails. I found this question, where the guy had an issue but eventually removes his custom permissions and it worked. I don't have any custom permissions like that, but still no luck:

Widget with content provider; impossible to use ReadPermission?

If anyone has insight I'd be really grateful, this is getting incredibly frustrating, haha.

回答1:

Put this in your onDataSetChanged() method:

    Thread thread = new Thread() {
        public void run() {
            query();
        }
    };
    thread.start();
    try {
        thread.join();
    } catch (InterruptedException e) {
    }

Fetch data from the database inside query() method. I do not know why fetching data in a separate thread helps get around this problem, but it works! I got this from one of the Android examples.



回答2:

This is happening because RemoteViewsFactory is being called from a remote process, and that context is being used for permission enforcement. (The remote caller doesn't have permission to use your provider, so it throws a SecurityException.)

To solve this, you can clear the identity of the remote process, so that permission enforcement is checked against your app instead of against the remote caller. Here's a common pattern you'll find across the platform:

final long token = Binder.clearCallingIdentity();
try {
    [perform your query, etc]
} finally {
    Binder.restoreCallingIdentity(token);
}


回答3:

If this only happens for 4.2 and not the rest, you need to set the android:exported="true", because the default is changed: http://developer.android.com/about/versions/android-4.2.html

Content providers are no longer exported by default. That is, the default value for the android:exported attribute is now “false". If it’s important that other apps be able to access your content provider, you must now explicitly set android:exported="true".