Надежность поставщика содержимого 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' orResultSet` - реализация SQLite для Android очень похожа на реализацию JDBC, и концепции практически одинаковы без удобных имен и описаний.

Тот факт, что Android использует собственную реализацию, усложняет описание проблемы, хотя я должен был упомянуть об этом в своем первоначальном посте. Вот поток групп Google о состоянии JDBC и реализации интерфейса SQLite в Android, если требуются более подробные ссылки и информация:

https://groups.google.com/forum/

Из обсуждения вы, вероятно, могли бы спросить у Joerg Pleumann более подробную информацию...

Другие вопросы по тегам