android内容提供商在提供商崩溃时的稳健性

时间:2012-12-17 21:13:54

标签: android android-contentprovider robustness ashmem

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

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

“Killing 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这样的异常吗?

1 个答案:

答案 0 :(得分:-1)

Cursor不安全。虽然我认为大部分时间Cursor仅用于&#34;读访问&#34;对于数据,它们比这更复杂。

简短说明位于描述Cursor

的Android文档中
  

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

所以Cursor不仅仅是对象中保存的数据。它们通过数据库连接在ResultSet中保留您的位置。 ResultSet使用JDBC访问数据库。所以Cursor只是作为一个&#34; Java友好&#34;数据库调用。以下是ResultSet文档的Android:

  

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

ResultSet保持与数据库的连接。数据未被复制&#34;进入界面(CursorResultSet都是接口,而不是对象;有些实现可能会复制数据,但我还没有对其进行测试,因为留下了Statement和{{1}通过关闭的ResultSet打开资源会导致数据库资源问题。

Java提供了获取JDBC访问结果集表的接口&#34;在这里的Java文档中描述的Connection的数据库中:

  

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

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

您无法提供&#34;数据库访问&#34;由于数据库中ResultSet表没有连接而导致已死亡的ContentProvider,因此应处理ResultSet

编辑:

一条评论表明Android不使用Cursor ResultSet` - SQLite的Android实现与JDBC非常相似,如果没有方便的名称和描述,概念基本相同。

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

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

从讨论中,你可能会问Joerg Pleumann更多细节......