-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsearch.xml
115 lines (55 loc) · 63.5 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Android开发,主线程不要做IPC!</title>
<link href="/blog/android/android-kai-fa-zhu-xian-cheng-bu-yao-zuo-ipc/"/>
<url>/blog/android/android-kai-fa-zhu-xian-cheng-bu-yao-zuo-ipc/</url>
<content type="html"><![CDATA[<p>经常会听到有人说:不要在主线程上做耗时操作,会崩溃的! </p><p>那么什么样的操作是耗时操作?很多人只能意识到:哦,磁盘IO,网络IO很耗时,不能放在主线程上面加载。但在大型的工程协作中,同时存在多个应用协作时,往往会忽略一个很重要、常用的点:应用之间通讯的耗时。</p><p>那么这里又有一个点:我经常在主线程上调用Android Framework提供的接口呀,这怎么没事,这也是IPC吧?那么应用2应用,对比应用2系统,这里面差异在哪里?</p><ul><li><p>应用 -> 系统。这里,系统的生命周期,是完全覆盖应用的。所以对于应用来说,系统是keep alive的,那么应用2系统的接口耗时,可以大体上分为两个阶段:Binder通讯耗时(速度等同内存操作)和系统逻辑耗时(通常性能很好)。所以通常系统接口的延时是确定性的,嗯,这里指“通常”,极端情况下它也不靠谱。</p></li><li><p>应用 -> 应用。这里得分两种情况,一种是service应用生命周期可以覆盖client,那么基本等同“应用-系统”的情况,多考虑个获取service binder的耗时。另一种当然是无法完全覆盖的情况下,要考虑service应用的冷启动。这里就很可怕了,如果应用冷启动逻辑很重,导致接口的逻辑有阻塞,那么这个延时就可能很长,导致client ANR。</p></li></ul><p>所以,划重点,</p><h1 id="不要在主线程上,做非常不确定延时的操作"><a href="#不要在主线程上,做非常不确定延时的操作" class="headerlink" title="不要在主线程上,做非常不确定延时的操作"></a>不要在主线程上,做非常不确定延时的操作</h1><p>通常,如果想最大程度上保障应用本身的稳定性,那么可以移除在主线程上面任何加载资源的操作,以及毫秒级别不能完成的过程,主线程上只留系统核心逻辑、不耗时的应用逻辑就好了。</p><p>这样设计的难度在于业务逻辑要异步化,并发编程相对不如过程式编程简单直观,但也没有那么有难度。诀窍在于把一个个过程切分打包,理解每个过程运行的先后顺序,以及它应该在哪个线程上面运行。</p><h1 id="为什么要有主线程"><a href="#为什么要有主线程" class="headerlink" title="为什么要有主线程"></a>为什么要有主线程</h1><p>应用主线程有两个核心的作用:</p><ol><li>系统核心逻辑同步化。(系统自己也不想面对复杂的并发架构,引入额外的设计难度)</li><li>保障应用能及时响应交互的请求,不要长时间阻塞卡住了后续的系统核心逻辑。(ANR时间阈值是一个被设定的经验值,在Android里面是这样设定而已)</li></ol><img src="https://source.android.google.cn/static/images/android-stack.svg?hl=zh-cn" alt="Android架构图" height="500"><style> img { background: white }</style>]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
<tag> ContentProvider </tag>
</tags>
</entry>
<entry>
<title>把Git玩坏了</title>
<link href="/blog/devops/ba-git-wan-pi-liao/"/>
<url>/blog/devops/ba-git-wan-pi-liao/</url>
<content type="html"><![CDATA[<h1 id="把Git玩坏了"><a href="#把Git玩坏了" class="headerlink" title="把Git玩坏了"></a>把Git玩坏了</h1><p>故事是这样的:</p><p>大多数Git的远程repo存储系统是Linux,但是很多开发者的开发环境是Windows。众所周知,</p><ul><li>Linux的文件系统严格区分路径大小写。</li><li>Windows的文件系统命名中可以有大小写,但运行时实际不区分大小写。</li></ul><p>那么如果有人在Windows下开发时,重命名文件的时候“不小心”只修改了大小写,那就坏了。假设是把<code>Dict-a</code>修改成<code>Dict-A</code>后,commit到远程仓库,你以为是重命名成功了,但远程的Linux repo由于会区分大小写,这次重命名<code>Dict-a</code>的操作会被视为新增<code>Dict-A</code>。</p><p>此时如果再pull同步远程repo的内容,在Windows环境下<code>Dict-a</code>和<code>Dict-A</code>会共存,git的工作区会存在一个无法被合并的幽灵修改,这个时候本地仓库由于永远存在未add的change,就无法commit新修改,把Git玩坏了~</p><p><strong>解决方案也很清晰:</strong> 去区分大小写的Linux系统下做修改,路径命名同时考虑Windows不区分大小写这个特性。</p><h1 id="Tips"><a href="#Tips" class="headerlink" title="Tips"></a>Tips</h1><p><strong>Win&Linux协作开发要特别注意系统间的差异,路径大小写也只是其中一个很小的点。</strong></p>]]></content>
<categories>
<category> DevOps </category>
</categories>
<tags>
<tag> DevOps </tag>
<tag> Git </tag>
</tags>
</entry>
<entry>
<title>Sqlcipher mlock使用分析</title>
<link href="/blog/android/sqlcipher-mlock-shi-yong-fen-xi/"/>
<url>/blog/android/sqlcipher-mlock-shi-yong-fen-xi/</url>
<content type="html"><![CDATA[<h1 id="什么是mlock"><a href="#什么是mlock" class="headerlink" title="什么是mlock"></a>什么是mlock</h1><blockquote><p>通过mlock可以将进程使用的部分或者全部的地址空间锁定在物理内存中,防止其被交换到swap空间。对时间敏感的应用会希望全部使用物理内存,提高数据访问和操作的效率。</p></blockquote><p>mlock的函数原型:<br><code>int mlock(const void *addr, size_t len);</code></p><p>系统调用sys_mlock支撑这个机制在内核中的实现。在内核中,具体实现是将指定的内存页面加入不可回收的LRU链表中,达到pin内存的目的。</p><p><img src="https://pic2.zhimg.com/80/v2-91a01a7d3fd60edfdf7f9cb7cccf533d_1440w.webp" alt="mlock内核实现原理"></p><h1 id="sqlcipher中的mlock"><a href="#sqlcipher中的mlock" class="headerlink" title="sqlcipher中的mlock"></a>sqlcipher中的mlock</h1><p>mlock在sqlcipher中的应用目的是防止内存被交换到磁盘时被黑客篡改,提升数据交换的安全性。但它使用mlock的频率非常高,频繁的mlock & munlock导致损耗系统性能,同时可能加剧内存碎片化。需要谨慎评估后再使用sqlcipher提供的这个特性。</p><h2 id="源头"><a href="#源头" class="headerlink" title="源头"></a>源头</h2><p>sqlcipher_mlock中涉及mlock的调用。</p><ul><li><code>void sqlcipher_mlock(void *ptr, sqlite_uint64 sz)</code></li><li>sqlcipher_mem_malloc系列函数中,在<code>sqlcipher_mem_security_on = 1</code>时,会调用sqlcipher_mlock锁定内存。</li><li>sqlcipher_mem_free函数中unlock对应的内存。</li></ul><h2 id="内存操作函数"><a href="#内存操作函数" class="headerlink" title="内存操作函数"></a>内存操作函数</h2><p>sqlcipher_init_memmethods()会将mem函数加载到sqlite3_config中,内部库通过调用config中malloc内存的接口使用这个实现。</p><pre class="line-numbers language-cpp" data-language="cpp"><code class="language-cpp"><span class="token keyword">static</span> sqlite3_mem_methods sqlcipher_mem_methods <span class="token operator">=</span> <span class="token punctuation">{</span> sqlcipher_mem_malloc<span class="token punctuation">,</span> sqlcipher_mem_free<span class="token punctuation">,</span> sqlcipher_mem_realloc<span class="token punctuation">,</span> sqlcipher_mem_size<span class="token punctuation">,</span> sqlcipher_mem_roundup<span class="token punctuation">,</span> sqlcipher_mem_init<span class="token punctuation">,</span> sqlcipher_mem_shutdown<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token keyword">void</span> <span class="token function">sqlcipher_init_memmethods</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span><span class="token punctuation">(</span>sqlcipher_mem_initialized<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token function">sqlite3_config</span><span class="token punctuation">(</span>SQLITE_CONFIG_GETMALLOC<span class="token punctuation">,</span> <span class="token operator">&</span>default_mem_methods<span class="token punctuation">)</span> <span class="token operator">!=</span> SQLITE_OK <span class="token operator">||</span> <span class="token function">sqlite3_config</span><span class="token punctuation">(</span>SQLITE_CONFIG_MALLOC<span class="token punctuation">,</span> <span class="token operator">&</span>sqlcipher_mem_methods<span class="token punctuation">)</span> <span class="token operator">!=</span> SQLITE_OK<span class="token punctuation">)</span> <span class="token punctuation">{</span> sqlcipher_mem_security_on <span class="token operator">=</span> sqlcipher_mem_executed <span class="token operator">=</span> sqlcipher_mem_initialized <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> sqlcipher_mem_initialized <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>sqlite3_malloc函数中会通过<a href="https://github.com/sqlcipher/sqlcipher/blob/c7f9a1c348fde215ac18ce2b78a62ce8111a3743/src/malloc.c#L269">sqlite3GlobalConfig.m</a>调用sqlcipher_mem_malloc方法分配内存。</p><p>结论:sqlite3任意通过malloc分配内存的时候,如果有开启内存安全特性,都会用到mlock。</p><h3 id="内存使用调试信息"><a href="#内存使用调试信息" class="headerlink" title="内存使用调试信息"></a>内存使用调试信息</h3><p>可以通过SQLiteDebug#memoryUsed获取当前sqlite分配的内存大小。底层调用sqlite3_status(SQLITE_STATUS_MEMORY_USED)。</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/** the current amount of memory checked out by sqlite using sqlite3_malloc(). * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html */</span><span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token class-name">SQLiteDebug</span>#<span class="token class-name">PagerStats</span>#memoryUsed<span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span></span></code></pre><h2 id="特性:sqlcipher-set-mem-security"><a href="#特性:sqlcipher-set-mem-security" class="headerlink" title="特性:sqlcipher_set_mem_security"></a>特性:sqlcipher_set_mem_security</h2><p>最新版本上sqlcipher_set_mem_security特性默认是关闭的,一旦打开不能关闭。<br>但在4.1.x的版本上,则是默认打开的,可以修改。这与不同版本作者的实现相关。</p><pre class="line-numbers language-cpp" data-language="cpp"><code class="language-cpp"><span class="token keyword">void</span> <span class="token function">sqlcipher_set_mem_security</span><span class="token punctuation">(</span><span class="token keyword">int</span> on<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">/* memory security can only be enabled, not disabled */</span> <span class="token keyword">if</span><span class="token punctuation">(</span>on<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">sqlcipher_log</span><span class="token punctuation">(</span>SQLCIPHER_LOG_DEBUG<span class="token punctuation">,</span> <span class="token string">"sqlcipher_set_mem_security: on"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> sqlcipher_mem_security_on <span class="token operator">=</span> on<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><hr><p>可以通过SQLite的PRAGMA配置操作来开关这个特性。</p><blockquote><p>SQLite解析SQL语句后,通过sqlite3Pragma接口修改配置<br><code>int sqlcipher_codec_pragma(sqlite3*, int, Parse*, const char *, const char*);</code></p></blockquote><hr><p>cipher_memory_security特性介绍:<a href="https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_memory_security">PRAGMA cipher_memory_security</a></p><pre class="line-numbers language-none"><code class="language-none">PRAGMA cipher_memory_security = ON;PRAGMA cipher_memory_security = OFF;<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span></span></code></pre><p>数据库中,可通过 <code>SQLiteDatabase.execSQL(String sql)</code> 来执行配置修改语句。</p>]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
<tag> Database </tag>
</tags>
</entry>
<entry>
<title>ContentProvider中的连接</title>
<link href="/blog/android/contentprovider-zhong-de-lian-jie/"/>
<url>/blog/android/contentprovider-zhong-de-lian-jie/</url>
<content type="html"><![CDATA[<p>ContentProvider 中常用的函数,除了 query 之外(异常情况下也会),在调用过程中都在 ActivityManagerService 侧有维护强连接的概念。一旦内容提供者进程死亡,使用者也会连坐被杀。</p><hr><p>Android 应用进程会有因为 Provider 依赖关联杀死的情况,你可以看到以下日志:<br><code>am_kill : [xx, xx, com.xx, xx, depends on provider com.xxx in dying proc com.xx]</code></p><p>这会令你感到疑惑,是什么神秘机制导致我的应用被连坐呢?首先我们要按图索骥。</p><h1 id="寻根"><a href="#寻根" class="headerlink" title="寻根"></a>寻根</h1><p>既然是 AM 的日志,那自然要去 Framework 寻找答案啦。<br><code>ContentProviderHelper.java#removeDyingProviderLocked</code></p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token class-name">ProcessRecord</span> capp <span class="token operator">=</span> conn<span class="token punctuation">.</span>client<span class="token punctuation">;</span><span class="token keyword">final</span> <span class="token class-name">IApplicationThread</span> thread <span class="token operator">=</span> capp<span class="token punctuation">.</span><span class="token function">getThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>conn<span class="token punctuation">.</span>dead <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>conn<span class="token punctuation">.</span><span class="token function">stableCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">final</span> <span class="token keyword">int</span> pid <span class="token operator">=</span> capp<span class="token punctuation">.</span><span class="token function">getPid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>capp<span class="token punctuation">.</span><span class="token function">isPersistent</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span> thread <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> pid <span class="token operator">!=</span> <span class="token number">0</span> <span class="token operator">&&</span> pid <span class="token operator">!=</span> <span class="token class-name">ActivityManagerService</span><span class="token punctuation">.</span><span class="token constant">MY_PID</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> capp<span class="token punctuation">.</span><span class="token function">killLocked</span><span class="token punctuation">(</span> <span class="token string">"depends on provider "</span> <span class="token operator">+</span> cpr<span class="token punctuation">.</span>name<span class="token punctuation">.</span><span class="token function">flattenToShortString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" in dying proc "</span> <span class="token operator">+</span> <span class="token punctuation">(</span>proc <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">?</span> proc<span class="token punctuation">.</span>processName <span class="token operator">:</span> <span class="token string">"??"</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">" (adj "</span> <span class="token operator">+</span> <span class="token punctuation">(</span>proc <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">?</span> proc<span class="token punctuation">.</span>mState<span class="token punctuation">.</span><span class="token function">getSetAdj</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token string">"??"</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">,</span> <span class="token class-name">ApplicationExitInfo</span><span class="token punctuation">.</span><span class="token constant">REASON_DEPENDENCY_DIED</span><span class="token punctuation">,</span> <span class="token class-name">ApplicationExitInfo</span><span class="token punctuation">.</span><span class="token constant">SUBREASON_UNKNOWN</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>thread <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> conn<span class="token punctuation">.</span>provider<span class="token punctuation">.</span>provider <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> thread<span class="token punctuation">.</span><span class="token function">unstableProviderDied</span><span class="token punctuation">(</span>conn<span class="token punctuation">.</span>provider<span class="token punctuation">.</span>provider<span class="token punctuation">.</span><span class="token function">asBinder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RemoteException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token comment">// In the protocol here, we don't expect the client to correctly</span> <span class="token comment">// clean up this connection, we'll just remove it.</span> cpr<span class="token punctuation">.</span>connections<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>conn<span class="token punctuation">.</span>client<span class="token punctuation">.</span>mProviders<span class="token punctuation">.</span><span class="token function">removeProviderConnection</span><span class="token punctuation">(</span>conn<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> mService<span class="token punctuation">.</span><span class="token function">stopAssociationLocked</span><span class="token punctuation">(</span>capp<span class="token punctuation">.</span>uid<span class="token punctuation">,</span> capp<span class="token punctuation">.</span>processName<span class="token punctuation">,</span> cpr<span class="token punctuation">.</span>uid<span class="token punctuation">,</span> cpr<span class="token punctuation">.</span>appInfo<span class="token punctuation">.</span>longVersionCode<span class="token punctuation">,</span> cpr<span class="token punctuation">.</span>name<span class="token punctuation">,</span> cpr<span class="token punctuation">.</span>info<span class="token punctuation">.</span>processName<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>ContentProviderConnection 是 Framework 层里面记录应用 Provider 组件信息的数据结构。</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token comment">/** * Represents a link between a content provider and client. */</span><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">ContentProviderConnection</span> <span class="token keyword">extends</span> <span class="token class-name">Binder</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token class-name">ContentProviderRecord</span> provider<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token class-name">ProcessRecord</span> client<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token class-name">String</span> clientPackage<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">AssociationState<span class="token punctuation">.</span>SourceState</span> association<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">long</span> createTime<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">int</span> stableCount<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">int</span> unstableCount<span class="token punctuation">;</span> <span class="token comment">// The client of this connection is currently waiting for the provider to appear.</span> <span class="token comment">// Protected by the provider lock.</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> waiting<span class="token punctuation">;</span> <span class="token comment">// The provider of this connection is now dead.</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> dead<span class="token punctuation">;</span> <span class="token comment">// For debugging.</span> <span class="token keyword">public</span> <span class="token keyword">int</span> numStableIncs<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">int</span> numUnstableIncs<span class="token punctuation">;</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>以下是几个调用到该函数的路径,总结一下,就是进程要死亡的时候会做这个动作。</p><p><code>ActivityManagerService.java#forceStopPackageLocked ActivityManagerService.java#cleanupDisabledPackageComponentsLocked ActivityManagerService.java#processStartTimedOutLocked ProcessProviderRecord.java#onCleanupApplicationRecordLocked </code></p><p>那么从以上的源码分析中,我们可以得到以下信息:<br>进程死亡时,provider 有 stable 连接,依赖方也会被杀。<br>这个机制不会杀 persist 进程。(persist 进程被定义为系统的一部分,由系统保活)</p><p>那么问题又来了,什么是 provider 的 stable 连接。</p><h1 id="探源"><a href="#探源" class="headerlink" title="探源"></a>探源</h1><p>那么我们来找一下 stableCount 是在哪里被修改的。</p><p><code>ActivityManagerService.java#getContentProvider(..., boolean stable, ...) ActivityManagerService.java#getContentProviderImpl(..., boolean stable, ...)</code></p><p>应用进程的 ActivityThread 中,<code>acquireProvider(..., boolean stable, ...)</code> 方法会调用获取目标 provider 的 binder 对象进行通讯。</p><p>显然我们日常使用的 provider 的时候,用的是 ContentResolver 呢。那么他们之间有什么联系呢?那显然是有调用关系的。</p><p>ActivityThread 是 ContextImpl 的成员,那巧了,ContentResolver 也是它的成员,可以愉快地调用 ActivityThread#acquireProvider 函数了。应用的 ContextImpl 对象是在 LoadedApk#makeApplication 函数中被创建的,这个函数会在 AM 和 App 通信的时候调用。</p><p>总结一下,provider 的连接数在 acquireProvider 系列函数中添加计数,在 releaseProvider 函数中消减计数。这个计数维护在 AM 中。</p><p>对了,ContextImpl 也是我们常用的 Context 对象的实现类,我们通常使用的 ContentResolver 是它内部预定义的一个实现类。</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">ApplicationContentResolver</span> <span class="token keyword">extends</span> <span class="token class-name">ContentResolver</span> <span class="token punctuation">{</span> <span class="token annotation punctuation">@UnsupportedAppUsage</span> <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">ActivityThread</span> mMainThread<span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">ApplicationContentResolver</span><span class="token punctuation">(</span><span class="token class-name">Context</span> context<span class="token punctuation">,</span> <span class="token class-name">ActivityThread</span> mainThread<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span> mMainThread <span class="token operator">=</span> <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">requireNonNull</span><span class="token punctuation">(</span>mainThread<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token annotation punctuation">@UnsupportedAppUsage</span> <span class="token keyword">protected</span> <span class="token class-name">IContentProvider</span> <span class="token function">acquireProvider</span><span class="token punctuation">(</span><span class="token class-name">Context</span> context<span class="token punctuation">,</span> <span class="token class-name">String</span> auth<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> mMainThread<span class="token punctuation">.</span><span class="token function">acquireProvider</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> <span class="token class-name">ContentProvider</span><span class="token punctuation">.</span><span class="token function">getAuthorityWithoutUserId</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">resolveUserIdFromAuthority</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">protected</span> <span class="token class-name">IContentProvider</span> <span class="token function">acquireExistingProvider</span><span class="token punctuation">(</span><span class="token class-name">Context</span> context<span class="token punctuation">,</span> <span class="token class-name">String</span> auth<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> mMainThread<span class="token punctuation">.</span><span class="token function">acquireExistingProvider</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> <span class="token class-name">ContentProvider</span><span class="token punctuation">.</span><span class="token function">getAuthorityWithoutUserId</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">resolveUserIdFromAuthority</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">releaseProvider</span><span class="token punctuation">(</span><span class="token class-name">IContentProvider</span> provider<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> mMainThread<span class="token punctuation">.</span><span class="token function">releaseProvider</span><span class="token punctuation">(</span>provider<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">protected</span> <span class="token class-name">IContentProvider</span> <span class="token function">acquireUnstableProvider</span><span class="token punctuation">(</span><span class="token class-name">Context</span> c<span class="token punctuation">,</span> <span class="token class-name">String</span> auth<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> mMainThread<span class="token punctuation">.</span><span class="token function">acquireProvider</span><span class="token punctuation">(</span>c<span class="token punctuation">,</span> <span class="token class-name">ContentProvider</span><span class="token punctuation">.</span><span class="token function">getAuthorityWithoutUserId</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">resolveUserIdFromAuthority</span><span class="token punctuation">(</span>auth<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">releaseUnstableProvider</span><span class="token punctuation">(</span><span class="token class-name">IContentProvider</span> icp<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> mMainThread<span class="token punctuation">.</span><span class="token function">releaseProvider</span><span class="token punctuation">(</span>icp<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">unstableProviderDied</span><span class="token punctuation">(</span><span class="token class-name">IContentProvider</span> icp<span class="token punctuation">)</span> <span class="token punctuation">{</span> mMainThread<span class="token punctuation">.</span><span class="token function">handleUnstableProviderDied</span><span class="token punctuation">(</span>icp<span class="token punctuation">.</span><span class="token function">asBinder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token annotation punctuation">@Override</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">appNotRespondingViaProvider</span><span class="token punctuation">(</span><span class="token class-name">IContentProvider</span> icp<span class="token punctuation">)</span> <span class="token punctuation">{</span> mMainThread<span class="token punctuation">.</span><span class="token function">appNotRespondingViaProvider</span><span class="token punctuation">(</span>icp<span class="token punctuation">.</span><span class="token function">asBinder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/** @hide */</span> <span class="token keyword">protected</span> <span class="token keyword">int</span> <span class="token function">resolveUserIdFromAuthority</span><span class="token punctuation">(</span><span class="token class-name">String</span> auth<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token class-name">ContentProvider</span><span class="token punctuation">.</span><span class="token function">getUserIdFromAuthority</span><span class="token punctuation">(</span>auth<span class="token punctuation">,</span> <span class="token function">getUserId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>既然了解了他们之间的调用链,那么我们日常使用的 API 中,有哪些不是 stable 的,也就是不会导致连坐呢。答案很遗憾,没有绝对安全的方法。</p><p>我们常用的 provider 相关的函数有:query,insert,update,delete,call。只有 query 来说是“相对安全”的。其他的函数均获取 stable provider 进行通信。</p><p>query 过程会优先获取 unstable provider,通信失败时会获取 stable provider 重试。</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">Cursor</span> <span class="token function">query</span><span class="token punctuation">(</span><span class="token keyword">final</span> <span class="token annotation punctuation">@RequiresPermission.Read</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">Uri</span> uri<span class="token punctuation">,</span><span class="token annotation punctuation">@Nullable</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> projection<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">Bundle</span> queryArgs<span class="token punctuation">,</span><span class="token annotation punctuation">@Nullable</span> <span class="token class-name">CancellationSignal</span> cancellationSignal<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token namespace">android<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span>SeempLog</span><span class="token punctuation">.</span><span class="token function">record_uri</span><span class="token punctuation">(</span><span class="token number">13</span><span class="token punctuation">,</span> uri<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">requireNonNull</span><span class="token punctuation">(</span>uri<span class="token punctuation">,</span> <span class="token string">"uri"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>mWrapped <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> mWrapped<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span>uri<span class="token punctuation">,</span> projection<span class="token punctuation">,</span> queryArgs<span class="token punctuation">,</span> cancellationSignal<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RemoteException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token class-name">IContentProvider</span> unstableProvider <span class="token operator">=</span> <span class="token function">acquireUnstableProvider</span><span class="token punctuation">(</span>uri<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>unstableProvider <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token class-name">IContentProvider</span> stableProvider <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token class-name">Cursor</span> qCursor <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">long</span> startTime <span class="token operator">=</span> <span class="token class-name">SystemClock</span><span class="token punctuation">.</span><span class="token function">uptimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">ICancellationSignal</span> remoteCancellationSignal <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>cancellationSignal <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> cancellationSignal<span class="token punctuation">.</span><span class="token function">throwIfCanceled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> remoteCancellationSignal <span class="token operator">=</span> unstableProvider<span class="token punctuation">.</span><span class="token function">createCancellationSignal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> cancellationSignal<span class="token punctuation">.</span><span class="token function">setRemote</span><span class="token punctuation">(</span>remoteCancellationSignal<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> qCursor <span class="token operator">=</span> unstableProvider<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span>mPackageName<span class="token punctuation">,</span> mAttributionTag<span class="token punctuation">,</span> uri<span class="token punctuation">,</span> projection<span class="token punctuation">,</span> queryArgs<span class="token punctuation">,</span> remoteCancellationSignal<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">DeadObjectException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// The remote process has died... but we only hold an unstable</span> <span class="token comment">// reference though, so we might recover!!! Let's try!!!!</span> <span class="token comment">// This is exciting!!1!!1!!!!1</span> <span class="token function">unstableProviderDied</span><span class="token punctuation">(</span>unstableProvider<span class="token punctuation">)</span><span class="token punctuation">;</span> stableProvider <span class="token operator">=</span> <span class="token function">acquireProvider</span><span class="token punctuation">(</span>uri<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>stableProvider <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> qCursor <span class="token operator">=</span> stableProvider<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span>mPackageName<span class="token punctuation">,</span> mAttributionTag<span class="token punctuation">,</span> uri<span class="token punctuation">,</span> projection<span class="token punctuation">,</span> queryArgs<span class="token punctuation">,</span> remoteCancellationSignal<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>qCursor <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Force query execution. Might fail and throw a runtime exception here.</span> qCursor<span class="token punctuation">.</span><span class="token function">getCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">long</span> durationMillis <span class="token operator">=</span> <span class="token class-name">SystemClock</span><span class="token punctuation">.</span><span class="token function">uptimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">;</span> <span class="token function">maybeLogQueryToEventLog</span><span class="token punctuation">(</span>durationMillis<span class="token punctuation">,</span> uri<span class="token punctuation">,</span> projection<span class="token punctuation">,</span> queryArgs<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Wrap the cursor object into CursorWrapperInner object.</span> <span class="token keyword">final</span> <span class="token class-name">IContentProvider</span> provider <span class="token operator">=</span> <span class="token punctuation">(</span>stableProvider <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token operator">?</span> stableProvider <span class="token operator">:</span> <span class="token function">acquireProvider</span><span class="token punctuation">(</span>uri<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">final</span> <span class="token class-name">CursorWrapperInner</span> wrapper <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CursorWrapperInner</span><span class="token punctuation">(</span>qCursor<span class="token punctuation">,</span> provider<span class="token punctuation">)</span><span class="token punctuation">;</span> stableProvider <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> qCursor <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token keyword">return</span> wrapper<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RemoteException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Arbitrary and not worth documenting, as Activity</span> <span class="token comment">// Manager will kill this process shortly anyway.</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>qCursor <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> qCursor<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>cancellationSignal <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> cancellationSignal<span class="token punctuation">.</span><span class="token function">setRemote</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>unstableProvider <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">releaseUnstableProvider</span><span class="token punctuation">(</span>unstableProvider<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>stableProvider <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">releaseProvider</span><span class="token punctuation">(</span>stableProvider<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><p>其他的几个函数都会获取 stable provider 进行通信。</p><pre class="line-numbers language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Override</span><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">Uri</span> <span class="token function">insert</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequiresPermission.Write</span> <span class="token annotation punctuation">@NonNull</span> <span class="token class-name">Uri</span> url<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">ContentValues</span> values<span class="token punctuation">,</span> <span class="token annotation punctuation">@Nullable</span> <span class="token class-name">Bundle</span> extras<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token namespace">android<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span>SeempLog</span><span class="token punctuation">.</span><span class="token function">record_uri</span><span class="token punctuation">(</span><span class="token number">37</span><span class="token punctuation">,</span> url<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">requireNonNull</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> <span class="token string">"url"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>mWrapped <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> mWrapped<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> values<span class="token punctuation">,</span> extras<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RemoteException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token class-name">IContentProvider</span> provider <span class="token operator">=</span> <span class="token function">acquireProvider</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>provider <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">IllegalArgumentException</span><span class="token punctuation">(</span><span class="token string">"Unknown URL "</span> <span class="token operator">+</span> url<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token keyword">long</span> startTime <span class="token operator">=</span> <span class="token class-name">SystemClock</span><span class="token punctuation">.</span><span class="token function">uptimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">Uri</span> createdRow <span class="token operator">=</span> provider<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span>mPackageName<span class="token punctuation">,</span> mAttributionTag<span class="token punctuation">,</span> url<span class="token punctuation">,</span> values<span class="token punctuation">,</span> extras<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">long</span> durationMillis <span class="token operator">=</span> <span class="token class-name">SystemClock</span><span class="token punctuation">.</span><span class="token function">uptimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">;</span> <span class="token function">maybeLogUpdateToEventLog</span><span class="token punctuation">(</span>durationMillis<span class="token punctuation">,</span> url<span class="token punctuation">,</span> <span class="token string">"insert"</span><span class="token punctuation">,</span> <span class="token keyword">null</span> <span class="token comment">/* where */</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> createdRow<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RemoteException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// Arbitrary and not worth documenting, as Activity</span> <span class="token comment">// Manager will kill this process shortly anyway.</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span> <span class="token function">releaseProvider</span><span class="token punctuation">(</span>provider<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre><h1 id="思考和启示"><a href="#思考和启示" class="headerlink" title="思考和启示"></a>思考和启示</h1><p>通过机制的挖掘,我们了解到使用 provider 通讯时,除了 query 函数一般情况下不会建立强连接,其他函数的 IPC 过程都是被定义为强连接的。那么在通讯过程中,如果对端死亡,我们自己的进程也会发生裙带效应。</p><p>单次调用结束后,由于引用计数的消减,所以并不会导致发生连坐现象。但持续时间过长的调用,更容易因为对端进程的稳定性而引发连带的问题。</p><p>结合数据的 CRUD 操作,只有 query 查询是读操作,其他的都是写操作。通常我们需要保证写操作的一致性。那么 Android 对于写时异常的处理策略是这样的,你觉得它是好是坏呢?</p>]]></content>
<categories>
<category> Android </category>
</categories>
<tags>
<tag> Android </tag>
<tag> ContentProvider </tag>
</tags>
</entry>
</search>