On android platforms (confirmed on ICS), if a content provider dies while a client is in the middle of a query (ie has a open cursor) the framework decides to kill the client processes holding a open cursor.
Here is a logcat output when i tried this with a download manager query that sleeps after doing a query. The "sleep" was to reproduce the problem. you can imagine it happening in a regular use case when the provider dies at the right/wrong time. And then do a kill of com.android.media (which hosts the downloadProvider).
"Killing com.example (pid 12234) because provider com.android.providers.downloads.DownloadProvider is in dying process android.process.media"
I tracked the code for this in 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 }
Is this a policy decision or is the cursor access unsafe after the provider has died?
It looks like the client cursor is holding a fd for an ashmem location populated by the CP. Is this the reason the clients are killed instead of throwing an exception like Binders when the server (provider) dies ?
The Cursor
is unsafe. Although I think most of the time Cursor
s are used only for "read access" to data, they are more complex than that.
The short explanation is in the Android docs that describes a Cursor
:
This interface provides random read-write access to the result set returned by a database query.
So Cursor
s are not just data held in an object. They hold your place in a ResultSet
through a database connection. The ResultSet
uses JDBC to access a database. So the Cursor
is acting only as a "Java friendly" database call. Here are the Android for the ResultSet
docs on that:
When reading data via the appropriate getter methods, the JDBC driver maps the SQL data retrieved from the database to the Java type implied by the method invoked by the application. The JDBC specification has a table for the mappings from SQL types to Java types.
The ResultSet
keeps a connection to the database. The data is not "copied" into the interface (both Cursor
and ResultSet
are interfaces, not objects; some implementations may copy the data, but I haven't tested it because leaving Statement
and ResultSet
resources open through a closed Connection
can cause DB resource issues).
Java provides the interface to gain JDBC access to a "results set table" in the database for the ResultSet
as described in the Java docs here:
A table of data representing a database result set, which is usually generated by executing a statement that queries the database.
http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
You cannot provide "database access" to a ContentProvider that has died because there is no connection the ResultSet
table in the database, so the Cursor
should be disposed of.
EDIT:
One comment suggests that Android does not use JDBC' or
ResultSet` - the Android implementation of the SQLite is a very similar implementation to JDBC, and the concepts are essentially the same without the convenient names and descriptions.
The fact that Android uses a custom implementation makes the description of the problem more difficult, although I should have made reference to this in my original post. Here is the Google Groups thread on the status of JDBC and the SQLite interface implementation in Android, if more detailed references and information is required:
https://groups.google.com/forum/#!topic/android-developers/zz3qlNL2JDw
From the discussion, you could probably ask Joerg Pleumann for more details...
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.