繁体   English   中英

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

[英]android content provider robustness on provider crash

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

这是我使用下载管理器查询尝试执行此操作后休眠的logcat输出。 “睡眠”是为了重现问题。 您可以想象,当提供者在正确/错误的时间死亡时,它会在常规用例中发生。 然后杀死com.android.media(托管downloadProvider)。

“杀死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     }

这是策略决定,还是提供者死亡后游标访问不安全?

看起来客户端光标正在为由CP填充的ashmem位置持有fd。 这是服务器(提供程序)死亡时客户端被杀死而不是引发诸如Binders之类的异常的原因吗?

Cursor是不安全的。 尽管我认为大多数时候Cursor仅用于对数据的“读取访问”,但它们比这更复杂。

简短说明在描述Cursor的Android文档中:

该接口提供对数据库查询返回的结果集的随机读写访问。

因此, Cursor不仅仅是保存在对象中的数据。 它们通过数据库连接将您放在ResultSet ResultSet使用JDBC访问数据库。 因此, Cursor仅充当“ Java友好”数据库调用。 这是关于ResultSet文档的Android:

通过适当的getter方法读取数据时,JDBC驱动程序将从数据库检索的SQL数据映射到应用程序调用的方法所隐含的Java类型。 JDBC规范有一个表,用于从SQL类型到Java类型的映射。

ResultSet保持与数据库的连接。 数据未“复制”到接口中( CursorResultSet都是接口,而不是对象;某些实现可能会复制数据,但我尚未对其进行测试,因为通过关闭的Connection保持StatementResultSet资源打开可能会导致数据库资源问题)。

Java提供接口来获得JDBC对ResultSet数据库中“结果集表”的访问,如Java文档中所述:

代表数据库结果集的数据表,通常通过执行查询数据库的语句来生成。

http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html

您无法为因数据库中的ResultSet表没有连接而死亡的ContentProvider提供“数据库访问”,因此应该处理Cursor

编辑:

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

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

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

从讨论中,您可能会向Joerg Pleumann询问更多详细信息...

暂无
暂无

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

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