Надежность поставщика содержимого Android при сбое поставщика
На платформах Android (подтверждено на ICS), если поставщик контента умирает, когда клиент находится в середине запроса (то есть имеет открытый курсор), платформа решает уничтожить клиентские процессы, удерживающие открытый курсор.
Вот вывод logcat, когда я попробовал это с запросом менеджера загрузки, который спит после выполнения запроса. "Сон" должен был воспроизвести проблему. Вы можете себе представить, что это происходит в случае обычного использования, когда поставщик умирает в нужное / неправильное время. А затем выполните уничтожение com.android.media (в котором размещен поставщик загрузки).
"Убийство com.example (pid 12234), поскольку поставщик com.android.providers.downloads.DownloadProvider находится в процессе умирания android.process.media"
Я отслеживал код для этого в ActivityManagerService::removeDyingProviderLocked
10203 private final void removeDyingProviderLocked(ProcessRecord proc,
10204 ContentProviderRecord cpr) {
10205 synchronized (cpr) {
10206 cpr.launchingApp = null;
10207 cpr.notifyAll();
10208 }
10210 mProvidersByClass.remove(cpr.name);
10211 String names[] = cpr.info.authority.split(";");
10212 for (int j = 0; j < names.length; j++) {
10213 mProvidersByName.remove(names[j]);
10214 }
10215
10216 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10217 while (cit.hasNext()) {
10218 ProcessRecord capp = cit.next();
10219 if (!capp.persistent && capp.thread != null
10220 && capp.pid != 0
10221 && capp.pid != MY_PID) {
10222 Slog.i(TAG, "Kill " + capp.processName
10223 + " (pid " + capp.pid + "): provider " + cpr.info.name
10224 + " in dying process " + (proc != null ? proc.processName : "??"));
10225 EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
10226 capp.processName, capp.setAdj, "dying provider "
10227 + cpr.name.toShortString());
10228 Process.killProcessQuiet(capp.pid);
10229 }
10230 }
10231
10232 mLaunchingProviders.remove(cpr);
10233 }
Это решение политики или доступ к курсору небезопасен после смерти провайдера?
Похоже, что клиентский курсор держит fd для местоположения ashmem, заполненного CP. Это причина, по которой клиенты убиваются вместо того, чтобы генерировать исключение, такое как Binders, когда сервер (поставщик) умирает?
1 ответ
Cursor
небезопасно Хотя я думаю, что большую часть времени Cursor
Они используются только для "доступа для чтения" к данным, они более сложны, чем это.
Краткое объяснение в документации для Android, которая описывает Cursor
:
Этот интерфейс обеспечивает произвольный доступ для чтения и записи к набору результатов, возвращаемому запросом базы данных.
Так Cursor
Это не просто данные, содержащиеся в объекте. Они занимают ваше место в ResultSet
через соединение с базой данных. ResultSet
использует JDBC для доступа к базе данных. Итак Cursor
действует только как "дружественный к Java" вызов базы данных. Вот Android для ResultSet
документы на это:
При чтении данных с помощью соответствующих методов получения драйвер JDBC отображает данные SQL, извлеченные из базы данных, на тип Java, подразумеваемый методом, вызываемым приложением. В спецификации JDBC есть таблица для сопоставления типов SQL с типами Java.
ResultSet
поддерживает связь с базой данных Данные не "копируются" в интерфейс (оба Cursor
а также ResultSet
являются интерфейсами, а не объектами; некоторые реализации могут копировать данные, но я не проверял, потому что оставляя Statement
а также ResultSet
ресурсы открыты через закрытый Connection
может вызвать проблемы с ресурсами БД).
Java предоставляет интерфейс для получения доступа JDBC к "таблице наборов результатов" в базе данных для ResultSet
как описано в документации по Java здесь:
Таблица данных, представляющая набор результатов базы данных, который обычно генерируется путем выполнения оператора, который запрашивает базу данных.
http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
Вы не можете предоставить "доступ к базе данных" для ContentProvider, который умер, потому что нет соединения ResultSet
таблица в базе данных, поэтому Cursor
должны быть утилизированы.
РЕДАКТИРОВАТЬ:
Один комментарий предполагает, что Android не использует JDBC' or
ResultSet` - реализация SQLite для Android очень похожа на реализацию JDBC, и концепции практически одинаковы без удобных имен и описаний.
Тот факт, что Android использует собственную реализацию, усложняет описание проблемы, хотя я должен был упомянуть об этом в своем первоначальном посте. Вот поток групп Google о состоянии JDBC и реализации интерфейса SQLite в Android, если требуются более подробные ссылки и информация:
https://groups.google.com/forum/
Из обсуждения вы, вероятно, могли бы спросить у Joerg Pleumann более подробную информацию...