简体   繁体   English

Android内容提供程序崩溃时的健壮性

[英]android content provider robustness on provider crash

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. 在android平台(在ICS上已确认)上,如果内容提供者在客户端处于查询中间(即具有打开的游标)时死亡,则框架决定杀死持有打开的游标的客户端进程。

Here is a logcat output when i tried this with a download manager query that sleeps after doing a query. 这是我使用下载管理器查询尝试执行此操作后休眠的logcat输出。 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). 然后杀死com.android.media(托管downloadProvider)。

"Killing com.example (pid 12234) because provider com.android.providers.downloads.DownloadProvider is in dying process android.process.media" “杀死com.example(pid 12234),因为提供程序com.android.providers.downloads.DownloadProvider即将死于android.process.media”

I tracked the code for this in ActivityManagerService::removeDyingProviderLocked 我在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. 看起来客户端光标正在为由CP填充的ashmem位置持有fd。 Is this the reason the clients are killed instead of throwing an exception like Binders when the server (provider) dies ? 这是服务器(提供程序)死亡时客户端被杀死而不是引发诸如Binders之类的异常的原因吗?

The Cursor is unsafe. Cursor是不安全的。 Although I think most of the time Cursor s are used only for "read access" to data, they are more complex than that. 尽管我认为大多数时候Cursor仅用于对数据的“读取访问”,但它们比这更复杂。

The short explanation is in the Android docs that describes a Cursor : 简短说明在描述Cursor的Android文档中:

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. 因此, Cursor不仅仅是保存在对象中的数据。 They hold your place in a ResultSet through a database connection. 它们通过数据库连接将您放在ResultSet The ResultSet uses JDBC to access a database. ResultSet使用JDBC访问数据库。 So the Cursor is acting only as a "Java friendly" database call. 因此, Cursor仅充当“ Java友好”数据库调用。 Here are the Android for the ResultSet docs on that: 这是关于ResultSet文档的Android:

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. 通过适当的getter方法读取数据时,JDBC驱动程序将从数据库检索的SQL数据映射到应用程序调用的方法所隐含的Java类型。 The JDBC specification has a table for the mappings from SQL types to Java types. JDBC规范有一个表,用于从SQL类型到Java类型的映射。

The ResultSet keeps a connection to the database. ResultSet保持与数据库的连接。 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). 数据未“复制”到接口中( CursorResultSet都是接口,而不是对象;某些实现可能会复制数据,但我尚未对其进行测试,因为通过关闭的Connection保持StatementResultSet资源打开可能会导致数据库资源问题)。

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: Java提供接口来获得JDBC对ResultSet数据库中“结果集表”的访问,如Java文档中所述:

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 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. 您无法为因数据库中的ResultSet表没有连接而死亡的ContentProvider提供“数据库访问”,因此应该处理Cursor

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. 有评论指出,Android不使用JDBC' or ResultSet'-SQLite的Android实现与JDBC非常相似,其概念在本质上是相同的,没有方便的名称和描述。

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. Android使用自定义实现的事实使问题的描述更加困难,尽管我应该在原始帖子中对此进行引用。 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: 如果需要更详细的参考和信息,这是有关JDBC状态和Android中SQLite接口实现的Google Groups线程:

https://groups.google.com/forum/#!topic/android-developers/zz3qlNL2JDw https://groups.google.com/forum/#!topic/android-developers/zz3qlNL2JDw

From the discussion, you could probably ask Joerg Pleumann for more details... 从讨论中,您可能会向Joerg Pleumann询问更多详细信息...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM