Отказ разрешения прав Android в виджетах RemoteViewsFactory для контента

У меня есть виджет, который я пытаюсь использовать для отображения информации из локальной базы данных моего приложения внутри списка.

Я использую интерфейс 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, такие как запросы сообщений об ошибках, но он все равно не работает. Я нашел этот вопрос, когда у парня возникла проблема, но в конечном итоге удалил пользовательские разрешения, и это сработало. У меня нет каких-либо пользовательских разрешений, но все равно не повезло:

Виджет с поставщиком контента; невозможно использовать ReadPermission?

Если у кого-то есть понимание, я был бы действительно благодарен, это становится невероятно расстраивающим, ха-ха.

Ответ 1

Поместите это в свой метод onDataSetChanged():

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

Извлечь данные из базы данных внутри метода query(). Я не знаю, почему выборка данных в отдельном потоке помогает обойти эту проблему, но она работает! Я получил это от одного из примеров Android.

Ответ 2

Это происходит потому, что RemoteViewsFactory вызывается из удаленного процесса, и этот контекст используется для принудительного применения. (У удаленного абонента нет разрешения на использование вашего провайдера, поэтому он генерирует исключение SecurityException.)

Чтобы решить эту проблему, вы можете очистить идентификатор удаленного процесса, чтобы проверка прав доступа была проверена против вашего приложения, а не от удаленного вызывающего. Вот общий шаблон, который вы найдете на всей платформе:

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

Ответ 3

Если это происходит только для 4.2, а не для остальных, вам нужно установить android: exported = "true", потому что по умолчанию изменено: http://developer.android.com/about/versions/android-4.2.html

Поставщики контента больше не экспортируются по умолчанию. То есть значение по умолчанию для атрибута android: exported теперь "false". Если важно, чтобы другие приложения могли получить доступ к вашему провайдеру контента, вы должны теперь явно указать андроид: exported = "true".