【问题标题】:Android Permission denial in Widget RemoteViewsFactory for Content用于内容的 Widget RemoteViewsFactory 中的 Android 权限拒绝
【发布时间】:2012-10-22 15:25:56
【问题描述】:

我有一个小部件,我试图用它在列表视图中显示来自应用程序本地数据库的信息。

我正在使用 RemoteViewsService.RemoteViewsFactory 接口来加载列表的内容。如果我运行在 onDataSetChanged 方法中重新加载列表的代码块。应用程序崩溃并显示以下消息:

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

但是,在类的构造函数中运行的相同代码可以正常工作。当然,我还需要在 onDataSetChanged 方法中使用它来进行更新和填充。

这是我的供应商在清单中的条目:

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

我同时导出它并授予 Uri 权限,如错误消息请求,但它仍然失败。我发现了这个问题,这家伙遇到了问题,但最终删除了他的自定义权限并且它起作用了。我没有任何这样的自定义权限,但仍然没有运气:

Widget with content provider; impossible to use ReadPermission?

如果有人有见识,我将不胜感激,这令人难以置信的沮丧,哈哈。

【问题讨论】:

    标签: android android-widget android-contentprovider android-permissions


    【解决方案1】:

    发生这种情况是因为 RemoteViewsFactory 是从远程进程调用的,并且该上下文正在用于权限强制执行。 (远程调用者没有使用你的提供者的权限,所以它会抛出一个 SecurityException。)

    要解决此问题,您可以清除远程进程的身份,以便针对您的应用而不是远程调用者检查权限强制执行。以下是您可以在整个平台上找到的常见模式:

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

    【讨论】:

    • 你摇滚。这帮助我解决了我的问题。
    • 感谢您提供真正的解决方案。请注意,此方法可以使您的提供程序不被导出,因为您使用自己的身份而不是默认设置的传入 IPC 的身份。
    【解决方案2】:

    把它放在你的onDataSetChanged() 方法中:

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

    query() 方法中从数据库中获取数据。我不知道为什么在单独的线程中获取数据有助于解决这个问题,但它确实有效!我是从其中一个 Android 示例中得到的。

    【讨论】:

    • 解决了这个问题。当然,另一个出现在它的位置。但至少这个问题解决了。谢谢!
    • 之所以有效,是因为 query() 发生在不同的线程上,该线程没有当前的 Binder 远程调用上下文。请参阅下面关于如何清除当前线程上的调用者身份的答案。
    【解决方案3】:

    如果这仅发生在 4.2 而不是其余版本,则需要设置 android:exported="true",因为默认值已更改: http://developer.android.com/about/versions/android-4.2.html

    默认情况下不再导出内容提供程序。也就是说,android:exported 属性的默认值现在是“false”。如果其他应用能够访问您的内容提供程序很重要,您现在必须显式设置 android:exported="true"。

    【讨论】:

    • +1,对于 Android 4.2,这就是解决方案!未更新的 sdk 示例! &lt;provider android:name="WeatherDataProvider" android:exported="true"
    • 谢谢,这不仅让我对这个特殊情况有了更清晰的认识,而且更普遍地了解了内容提供者和小部件之间的交互。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-31
    • 2017-09-19
    • 1970-01-01
    • 2020-10-25
    • 2022-06-22
    • 2019-01-06
    相关资源
    最近更新 更多