frameworks/base/core/java/android/app/
- ActivityThread.java
- ContextImpl.java
- IActivityManager.java
frameworks/base/core/java/android/content/
- ContentResolver.java
- IContentProvider.java
- ContentProvider.java
- ContentProviderNative.java
frameworks/base/services/core/java/com/android/server/am/
- ContentProviderRecord.java
一、概述
ContentProvider(内容提供者)用于提供数据的统一访问格式,封装底层的具体实现。对于数据的使用者来说,无需知晓数据的来源是数据库、文件,或者网络,只需简单地使用ContentProvider提供的数据操作接口,也就是增(insert)、删(delete)、改(update)、查(query)四个过程。
1.1 ContentProvider
ContentProvider作为Android四大组件之一,并没有Activity那样复杂的生命周期,只有简单地onCreate过程。ContentProvider是一个抽象类,当实现自己的ContentProvider类,只需继承于ContentProvider,并且实现以下六个abstract方法即可:
- insert(Uri, ContentValues):插入新数据;
- delete(Uri, String, String[]):删除已有数据;
- update(Uri, ContentValues, String, String[]):更新数据;
- query(Uri, String[], String, String[], String):查询数据;
- onCreate():执行初始化工作;
- getType(Uri):获取数据MIME类型。
Uri: 从ContentProvider的数据操作方法可以看出都依赖于Uri,对于Uri有其固定的数据格式,例如:content://com.gityuan.articles/android/3
字段 | 含义 | 对应项 |
---|---|---|
前缀 | 默认的固定开头格式 | content:// |
授权 | 唯一标识provider | com.gityuan.articles |
路径 | 数据类别以及数据项 | /android/3 |
1.2 ContentResolver
其他app或者进程想要操作ContentProvider
,则需要先获取其相应的ContentResolver
,再利用ContentResolver类来完成对数据的增删改查操作,下面列举一个查询操作,查询得到的是一个Cursor
结果集,再通过操作该Cursor便可获取想要查询的结果。
ContentResolver cr = getContentResolver(); //获取ContentResolver
Uri uri = Uri.parse("content://com.gityuan.articles/android/3");
Cursor cursor = cr.query(uri, null, null, null, null); //执行查询操作
...
cursor.close(); //关闭
1.3 继承关系图

- CPP与CPN是一对Binder通信的C/S两端;
- ACR(ApplicationContentResolver)继承于ContentResolver, 位于ContextImpl的内部类. ACR的实现往往是通过调用其成员变量mMainThread(数据类型为ActivityThread)来完成;
1.4 重要成员变量
在开始源码分析之前,先说说涉及到的几个关于contentProvider的重要的成员变量。
类名 | 成员变量 | 含义 |
---|---|---|
AMS | CONTENT_PROVIDER_PUBLISH_TIMEOUT | 默认值为10s |
AMS | mProviderMap | 记录所有contentProvider |
AMS | mLaunchingProviders | 记录存在客户端等待publish的ContentProviderRecord |
PR | pubProviders | 该进程创建的ContentProviderRecord |
PR | conProviders | 该进程使用的ContentProviderConnection |
AT | mLocalProviders | 记录所有本地的ContentProvider,以IBinder以key |
AT | mLocalProvidersByName | 记录所有本地的ContentProvider,以组件名为key |
AT | mProviderMap | 记录该进程的contentProvider |
AT | mProviderRefCountMap | 记录所有对其他进程中的ContentProvider的引用计数 |
- PR:ProcessRecord, AT: ActivityThread
-
CONTENT_PROVIDER_PUBLISH_TIMEOUT
(10s): provider所在进程发布其ContentProvider的超时时长为10s,超过10s则会系统所杀。 -
mLaunchingProviders
:记录的每一项是一个ContentProviderRecord对象, 所有的存在client等待其发布完成的contentProvider列表,一旦发布完成则相应的contentProvider便会从该列表移除; -
mProviderMap
: AMS和AT都有一个同名的成员变量, AMS的数据类型为ProviderMap,而AT则是以ProviderKey为key的ArrayMap类型. -
mLocalProviders
和mLocalProvidersByName
:都是用于记录所有本地的ContentProvider,不同的只是key.
1.5 query流程图
点击查看大图

getContentProviderImpl()过程返回的对象ContentProviderRecord中有成员变量ContentProviderConnection对象, 这个binder服务端.
二、查询ContentProvider
接下来,从源码角度来说说,以query
的为例来说说ContentProvider的整个完整流程,首先获取ContentResolver再执行相应query方法.
ContentResolver cr = getContentResolver(); //获取ContentResolver
Cursor cursor = cr.query(uri, null, null, null, null); //执行查询操作
2.1 getContentResolver
[-> ContextImpl.java]
class ContextImpl extends Context {
public ContentResolver getContentResolver() {
return mContentResolver;
}
private ContextImpl(...) {
...
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
}
Context中调用getContentResolver,经过层层调用来到ContextImpl类。返回值mContentResolver
赋值是在ContextImpl
对象创建过程完成赋值.接下来看看query查询操作。
2.2 CR.query
[-> ContentResolver.java]
public final Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
public final Cursor query(final Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
//获取unstable provider【见小节2.3】
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
long startTime = SystemClock.uptimeMillis();
...
try {
//执行查询操作【见小节2.9】
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// 远程进程死亡,处理unstable provider死亡过程
unstableProviderDied(unstableProvider);
//unstable类型死亡后,再创建stable类型的provider
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
//再次执行查询操作
qCursor = stableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}
//强制执行查询操作,可能会失败并跑出RuntimeException
qCursor.getCount();
//创建对象CursorWrapperInner
CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
stableProvider != null ? stableProvider : acquireProvider(uri));
stableProvider = null;
qCursor = null;
return wrapper;
} catch (RemoteException e) {
return null;
} finally {
if (qCursor != null) {
qCursor.close();
}
if (cancellationSignal != null) {
cancellationSignal.setRemote(null);
}
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}
一般地获取unstable的provider:
- 调用acquireUnstableProvider(),尝试获取unstable的ContentProvider;
- 然后执行query操作;
当执行query过程抛出DeadObjectException,即代表ContentProvider所在进程死亡,则尝试获取stable的ContentProvider:
- 先调用unstableProviderDied(), 清理刚创建的unstable的ContentProvider;
- 调用acquireProvider(),尝试获取stable的ContentProvider; 此时当ContentProvider进程死亡,则会杀掉该ContentProvider的客户端进程。
- 然后执行query操作;
先用一句话说说stable与unstable的区别,采用unstable类型的ContentProvider的app不会因为远程ContentProvider进程的死亡而被杀,stable则恰恰相反。这便是ContentProvider坑爹之处,对于app无法事先决定创建的ContentProvider是stable,还是unstable 类型的,也便无法得知自己的进程是否会依赖于远程ContentProvider的生死。
2.3 CR.acquireUnstableProvider
[-> ContentResolver.java]
public final IContentProvider acquireUnstableProvider(Uri uri) {
//此处SCHEME_CONTENT = "content"
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
String auth = uri.getAuthority();
if (auth != null) {
//【见小节2.4】
return acquireUnstableProvider(mContext, uri.getAuthority());
}
return null;
}
2.4 ACR.acquireUnstableProvider
[-> ContextImpl.java ::ApplicationContentResolver]
class ContextImpl extends Context {
private static final class ApplicationContentResolver extends ContentResolver {
...
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
//【见小节2.5】
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
}
}
不论是acquireUnstableProvider还是acquireProvider方法,最终都会调用ActivityThread的同一个方法acquireProvider()。 getAuthorityWithoutUserId()的过程是字符截断过程,即去掉auth中的UserId信息,比如com.gityuan.articles@123
,经过该方法处理后就变成了com.gityuan.articles
。
2.5 AT.acquireProvider
[-> ActivityThread.java]
public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) {
//【见小节2.5.1】
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
//成功获取已经存在的ContentProvider对象,则直接返回
return provider;
}
IActivityManager.ContentProviderHolder holder = null;
try {
//【见小节2.6】
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
//无法获取auth所对应的provider则直接返回
return null;
}
//安装provider将会增加引用计数【见小节2.8】
holder = installProvider(c, holder, holder.info,
true , holder.noReleaseNeeded, stable);
return holder.provider;
}
该方法的主要功能:
- 首先,尝试获取已存储的provider,当成功获取则直接返回,否则继续执行;
- 通过AMS来获取provider,当无法获取auth所对应的provider则直接返回,否则继续执行;
- 采用installProvider安装provider,并该provider的增加引用计数。
2.5.1 AT.acquireExistingProvider
[-> ActivityThread.java]
public final IContentProvider acquireExistingProvider( Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
final ProviderKey key = new ProviderKey(auth, userId);
//从AT.mProviderMap查询是否存在相对应的provider
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
if (!jBinder.isBinderAlive()) {
//当provider所在进程已经死亡则返回
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
//增加引用计数
incProviderRefLocked(prc, stable);
}
return provider;
}
}
- 首先从ActivityThread的
mProviderMap
查询是否存在相对应的provider,若不存在则直接返回; - 当provider记录存在,但其所在进程已经死亡,则调用
handleUnstableProviderDiedLocked
清理provider信息,并返回; - 当provider记录存在,且进程存活的情况下,则在provider引用计数不为空时则继续增加引用计数。
2.6 AMS.getContentProvider
[-> ActivityManagerService.java]
public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name, int userId, boolean stable) {
if (caller == null) {
throw new SecurityException();
}
//见小节2.7】
return getContentProviderImpl(caller, name, null, stable, userId);
}
ActivityManagerNative.getDefault()返回的是AMP,AMP经过binder IPC通信传递给AMS来完成相应工作, 从这里开始便进入了system_server进程。 清理,此处name就是前面的auth, 即com.gityuan.articles. 对应于AndroidManifest.xml中provider标签里面的android:authorities
的值.
2.7 AMS.getContentProviderImpl
[-> ActivityManagerService.java]
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
//获取调用者的进程记录ProcessRecord;
ProcessRecord r = getRecordForAppLocked(caller);
//从AMS中查询相应的ContentProviderRecord
cpr = mProviderMap.getProviderByName(name, userId);
...
boolean providerRunning = cpr != null;
// 目标provider已存在的情况 [见小节2.7.1]
if (providerRunning) {
...
}
// 目标provider不存在的情况 [见小节2.7.2]
if (!providerRunning) {
...
}
}
//循环等待provider发布完成 [见小节2.7.3]
synchronized (cpr) {
while (cpr.provider == null) {
...
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}
该方法比较长,也是获取provider的核心实现代码, 这里分成以下3部分:
- 目标provider已存在的情况;
- 目标provider不存在的情况;
- 循环等待provider发布完成;
此处name,也就是ComponentName的mClass=com.gityuan.articles
.
另外,
- mProviderMap.putProviderByClass(comp, cpr): 以ComponentName(组件名)为key, ContentProviderRecord为value;
- mProviderMap.putProviderByName(name, cpr): 以auth(即com.gityuan.articles)为key, ContentProviderRecord为value;
2.7.1 目标provider已存在
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
//该ContentProvider已发布
if (providerRunning) {
cpi = cpr.info;
//当允许运行在调用者进程且已发布,则直接返回[见小节2.7.4]
if (r != null && cpr.canRunHere(r)) {
ContentProviderHolder holder = cpr.newHolder(null);
holder.provider = null;
return holder;
}
final long origId = Binder.clearCallingIdentity();
//增加引用计数[见小节2.8.3]
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
//更新进程LRU队列
updateLruProcessLocked(cpr.proc, false, null);
}
}
if (cpr.proc != null) {
boolean success = updateOomAdjLocked(cpr.proc); //更新进程adj
if (!success) {
//provider进程被杀,则减少引用计数 [见小节2.8.2]
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
appDiedLocked(cpr.proc);
if (!lastRef) {
return null;
}
providerRunning = false;
conn = null;
}
}
Binder.restoreCallingIdentity(origId);
}
...
}
...
}
当ContentProvider所在进程已存在时的功能:
- 权限检查
- 当允许运行在调用者进程且已发布,则直接返回
- 增加引用计数
- 更新进程LRU队列
- 更新进程adj
- 当provider进程被杀时,则减少引用计数并调用appDiedLocked,且设置ContentProvider为没有发布的状态
2.7.2 目标provider不存在
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) {
...
synchronized(this) {
...
if (!providerRunning) {
//根据authority,获取ProviderInfo对象
cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
...
singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_OWNER;
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
...
if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
&& !cpi.processName.equals("system")) {
throw new IllegalArgumentException(...);
}
//当拥有该provider的用户并没有运行,则直接返回
if (!isUserRunningLocked(userId, false)) {
return null;
}
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
cpr = mProviderMap.getProviderByClass(comp, userId);
final boolean firstClass = cpr == null;
if (firstClass) {
final long ident = Binder.clearCallingIdentity();
try {
ApplicationInfo ai = AppGlobals.getPackageManager().
getApplicationInfo(cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId);
ai = getAppInfoForUser(ai, userId);
//创建对象ContentProviderRecord
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
// [见小节2.7.4]
if (r != null && cpr.canRunHere(r)) {
return cpr.newHolder(null);
}
final int N = mLaunchingProviders.size();
int i;
//从mLaunchingProviders中查询是否存在该cpr
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
//当provider并没有处于mLaunchingProviders队列,则启动它
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
try {
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
//查询进程记录ProcessRecord
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null) {
if (!proc.pubProviders.containsKey(cpi.name)) {
proc.pubProviders.put(cpi.name, cpr);
//启动provider进程启动并发布provider[见小节三]
proc.thread.scheduleInstallProvider(cpi);
}
} else {
// 启动进程[见小节三]
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
if (proc == null) {
return null;
}
}
cpr.launchingApp = proc;
//将cpr添加到mLaunchingProviders
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);
//增加引用计数
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
...
}
当ContentProvider所在进程没有存在时的功能:
- 根据authority,获取ProviderInfo对象;
- 权限检查
- 当provider不是运行在system进程,且系统未准备好,则抛出IllegalArgumentException
- 当拥有该provider的用户并没有运行,则直接返回
- 根据ComponentName,从AMS.mProviderMap中查询相应的ContentProviderRecord;
- 当首次调用,则创建对象ContentProviderRecord
- 当允许运行在调用者进程且ProcessRecord不为空,则直接返回
- 当provider并没有处于mLaunchingProviders队列,则启动它
- 当ProcessRecord不为空,则加入到pubProviders,并开始安装provider;
- 当ProcessRecord为空,则启动进程
- 增加引用计数
2.7.3 等待目标provider发布
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) {
...
//循环等待provider发布
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
return null;
}
try {
if (conn != null) {
conn.waiting = true;
}
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}
循环等待,直到provider发布完成才会退出循环.
2.7.4 canRunHere
[-> ContentProviderRecord.java]
public boolean canRunHere(ProcessRecord app) {
return (info.multiprocess || info.processName.equals(app.processName))
&& uid == app.info.uid;
}
该ContentProvider是否能运行在调用者所在进程需要满足以下条件:
- 条件1:ContentProvider在AndroidManifest.xml文件配置multiprocess=true;或调用者进程与ContentProvider在同一个进程。
- 条件2:ContentProvider进程跟调用者所在进程是同一个uid。
一般地, 程序进行到此处[小节2.5] AT.acquireProvider方法应该已成功获取了Provider对象, 接下来便是在调用端安装Provider.
2.8 AT.installProvider
[-> ActivityThread.java]
private IActivityManager.ContentProviderHolder installProvider(Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
if (holder == null || holder.provider == null) {
...
} else {
provider = holder.provider; //进入该分支
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
...
} else {
//根据jBinder,从mProviderRefCountMap中查询相应的ProviderRefCount
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
//只有当需要释放引用时则进入该分支
if (!noReleaseNeeded) {
//向ams来增加引用计数
incProviderRefLocked(prc, stable);
//[见流程2.8.1]
ActivityManagerNative.getDefault().removeContentProvider(
holder.connection, stable);
...
}
} else {
//[见流程2.8.4]
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) {
//[见流程2.8.5]
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
prc = stable
? new ProviderRefCount(holder, client, 1, 0)
: new ProviderRefCount(holder, client, 0, 1);
}
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
return retHolder;
}
获取ContentProviderHolder对象,该对象的成员变量provider记录着ContentProviderProxy对象.
2.8.1 AMS.removeContentProvider
[-> ActivityManagerService.java]
public void removeContentProvider(IBinder connection, boolean stable) {
enforceNotIsolatedCaller("removeContentProvider");
long ident = Binder.clearCallingIdentity();
try {
synchronized (this) {
ContentProviderConnection conn;
try {
conn = (ContentProviderConnection)connection;
} catch (ClassCastException e) {
throw new IllegalArgumentException(msg);
}
...
//[见流程2.8.2]
if (decProviderCountLocked(conn, null, null, stable)) {
updateOomAdjLocked();
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
2.8.2 AMS.decProviderCountLocked
[-> ActivityManagerService.java]
boolean decProviderCountLocked(ContentProviderConnection conn, ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (conn != null) {
cpr = conn.provider;
if (stable) {
conn.stableCount--;
} else {
conn.unstableCount--;
}
//当provider连接的 stable和unstable引用次数都为0时,则移除该连接对象信息
if (conn.stableCount == 0 && conn.unstableCount == 0) {
cpr.connections.remove(conn);
conn.client.conProviders.remove(conn);
stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.name);
return true;
}
return false;
}
cpr.removeExternalProcessHandleLocked(externalProcessToken);
return false;
}
减小provider引用所相反的操作便是增加引用incProviderCountLocked,再来说说增加引用计数
2.8.3 AMS.incProviderCountLocked
[-> ActivityManagerService.java]
ContentProviderConnection incProviderCountLocked(ProcessRecord r, final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (r != null) {
for (int i=0; i<r.conProviders.size(); i++) {
//从当前进程所使用的provider中查询与目标provider一致的信息
ContentProviderConnection conn = r.conProviders.get(i);
if (conn.provider == cpr) {
if (stable) {
conn.stableCount++;
conn.numStableIncs++;
} else {
conn.unstableCount++;
conn.numUnstableIncs++;
}
return conn;
}
}
//当查询不到时,则新建provider连接对象
ContentProviderConnection conn = new ContentProviderConnection(cpr, r);
if (stable) {
conn.stableCount = 1;
conn.numStableIncs = 1;
} else {
conn.unstableCount = 1;
conn.numUnstableIncs = 1;
}
cpr.connections.add(conn);
r.conProviders.add(conn);
startAssociationLocked(r.uid, r.processName, cpr.uid, cpr.name, cpr.info.processName);
return conn;
}
cpr.addExternalProcessHandleLocked(externalProcessToken);
return null;
}
2.8.4 AT.installProviderAuthoritiesLocked
[-> ActivityThread.java]
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider, ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
final String auths[] = holder.info.authority.split(";");
final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
final ProviderClientRecord pcr = new ProviderClientRecord(
auths, provider, localProvider, holder);
for (String auth : auths) {
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord existing = mProviderMap.get(key);
if (existing != null) {
... //已发布
} else {
mProviderMap.put(key, pcr);
}
}
return pcr;
}
2.8.5 ProviderRefCount
[-> ActivityThread.java ::ProviderRefCount]
private static final class ProviderRefCount {
public final IActivityManager.ContentProviderHolder holder;
public final ProviderClientRecord client;
public int stableCount;
public int unstableCount;
//当该标记设置,意味着stable和unstable的引用都会设置为0
public boolean removePending;
ProviderRefCount(IActivityManager.ContentProviderHolder inHolder,
ProviderClientRecord inClient, int sCount, int uCount) {
holder = inHolder;
client = inClient;
stableCount = sCount;
unstableCount = uCount;
}
}
- stableCount代表的是stable引用的次数;
- unstableCount代表的是unstable引用的次数;
2.9 CPP.query
回到[小节2.3]执行完acquireUnstableProvider()操作则成功获取了
[-> ContentProviderNative.java ::ContentProviderProxy]
public Cursor query(String callingPkg, Uri url, String[] projection, String selection, String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal) throws RemoteException {
//实例化BulkCursorToCursorAdaptor对象
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
int length = 0;
if (projection != null) {
length = projection.length;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(projection[i]);
}
data.writeString(selection);
if (selectionArgs != null) {
length = selectionArgs.length;
} else {
length = 0;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(selectionArgs[i]);
}
data.writeString(sortOrder);
data.writeStrongBinder(adaptor.getObserver().asBinder());
data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
//发送给Binder服务端【见小节2.10】
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
if (reply.readInt() != 0) {
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
adaptor.initialize(d);
} else {
adaptor.close();
adaptor = null;
}
return adaptor;
} catch (RemoteException ex) {
adaptor.close();
throw ex;
} catch (RuntimeException ex) {
adaptor.close();
throw ex;
} finally {
data.recycle();
reply.recycle();
}
}
2.10 CPN.onTransact
[-> ContentProviderNative.java]
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case QUERY_TRANSACTION:{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
int num = data.readInt();
String[] projection = null;
if (num > 0) {
projection = new String[num];
for (int i = 0; i < num; i++) {
projection[i] = data.readString();
}
}
String selection = data.readString();
num = data.readInt();
String[] selectionArgs = null;
if (num > 0) {
selectionArgs = new String[num];
for (int i = 0; i < num; i++) {
selectionArgs[i] = data.readString();
}
}
String sortOrder = data.readString();
IContentObserver observer = IContentObserver.Stub.asInterface(
data.readStrongBinder());
ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
//【见小节2.11】
Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
sortOrder, cancellationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = null;
try {
//创建CursorToBulkCursorAdaptor对象
adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
getProviderName());
cursor = null;
BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
adaptor = null;
reply.writeNoException();
reply.writeInt(1);
d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} finally {
if (adaptor != null) {
adaptor.close();
}
if (cursor != null) {
cursor.close();
}
}
} else {
reply.writeNoException();
reply.writeInt(0);
}
return true;
}
...
}
}
2.11 Transport.query
[-> ContentProvider.java ::Transport]
public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
if (projection != null) {
return new MatrixCursor(projection, 0);
}
Cursor cursor = ContentProvider.this.query(uri, projection, selection,
selectionArgs, sortOrder, CancellationSignal.fromTransport(
cancellationSignal));
if (cursor == null) {
return null;
}
return new MatrixCursor(cursor.getColumnNames(), 0);
}
final String original = setCallingPackage(callingPkg);
try {
// 回调目标ContentProvider所定义的query方法
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}
query过程更为繁琐,本文就不再介绍,到这里便真正调用到了目标provider的query方法.
三、Provider进程
3.1 两种场景
发布ContentProvider分两种情况:Provider进程尚未启动,Provider进程已启动但未发布。
- 场景一(Provider进程尚未启动):system_server进程调用startProcessLocked()创建provider进程且attach到system_server后, 通过binder call到provider进程执行AT.bindApplication()方法【见小节3.2】;
- 场景二(Provider进程已启动但未发布): 获取provider的过程[小节2.7.2], 发现provider进程已存在且attach到system_server,但所对应的provider还没有发布, 通过binder call到provider进程执行AT.scheduleInstallProvider方法【见小节3.6】。
殊途同归,这两种途径最终都会合入【小节3.3】installContentProviders过程。
这里先来说说目标provider进程尚未启动的情况。
3.2 AT.bindApplication
[-> ActivityThread.java]
public final void bindApplication(...) {
...
AppBindData data = new AppBindData();
data.providers = providers;
...
sendMessage(H.BIND_APPLICATION, data);
}
当主线程收到H.BIND_APPLICATION
消息后,会调用handleBindApplication方法。
3.2.1 AT.handleBindApplication
[-> ActivityThread.java]
private void handleBindApplication(AppBindData data) {
...
Process.setArgV0(data.processName); //设置进程名
//实例化app
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
...
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
//安装ContentProviders 【见小节3.3】
installContentProviders(app, providers);
}
}
...
//回调app.onCreate()
mInstrumentation.callApplicationOnCreate(app);
}
3.3 AT.installContentProviders
[-> ActivityThread.java]
private void installContentProviders( Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
// 安装provider 【见小节3.4】
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
// 发布provider 【见小节3.5】
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
}
}
3.4 AT.installProvider
[-> ActivityThread.java]
private IActivityManager.ContentProviderHolder installProvider(Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
if (holder == null || holder.provider == null) {
Context c = null;
ApplicationInfo ai = info.applicationInfo;
if (context.getPackageName().equals(ai.packageName)) {
c = context;
} else if (mInitialApplication != null &&
mInitialApplication.getPackageName().equals(ai.packageName)) {
c = mInitialApplication;
} else {
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
}
//无法获取context则直接返回
if (c == null) {
return null;
}
try {
final java.lang.ClassLoader cl = c.getClassLoader();
//通过反射,创建目标ContentProvider对象
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
//[见小节3.4.1]
provider = localProvider.getIContentProvider();
if (provider == null) {
return null;
}
//回调目标ContentProvider.onCreate方法
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
return null;
}
} else {
...
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
provider = pr.mProvider;
} else {
holder = new IActivityManager.ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
...
}
}
return retHolder;
}
该过程主要是通过反射,创建目标ContentProvider对象,并调用该对象onCreate方法.
3.4.1 getIContentProvider
[-> ContentProvider.java]
public abstract class ContentProvider implements ComponentCallbacks2 {
private Transport mTransport = new Transport();
class Transport extends ContentProviderNative {
ContentProvider getContentProvider() {
return ContentProvider.this;
}
}
//获取Transport
public IContentProvider getIContentProvider() {
return mTransport;
}
}
Transport继承于ContentProviderNative, 而ContentProviderNative实现接口IContentProvider.
3.5 AMS.publishContentProviders
由AMP.publishContentProviders经过binder IPC,交由AMS.publishContentProviders来处理
public final void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}
synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (r == null) {
throw new SecurityException(...);
}
final long origId = Binder.clearCallingIdentity();
final int N = providers.size();
for (int i = 0; i < N; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
}
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (dst != null) {
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
//将该provider添加到mProviderMap
mProviderMap.putProviderByClass(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
mProviderMap.putProviderByName(names[j], dst);
}
int launchingCount = mLaunchingProviders.size();
int j;
boolean wasInLaunchingProviders = false;
for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
//将该provider移除mLaunchingProviders队列
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
launchingCount--;
}
}
if (wasInLaunchingProviders) {
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
//唤醒客户端的wait等待方法
dst.notifyAll();
}
updateOomAdjLocked(r);
}
}
Binder.restoreCallingIdentity(origId);
} }
一旦publish成功,则会移除provider发布超时的消息,并且调用notifyAll()来唤醒所有等待的Client端进程。 Provider进程的工作便是完成,接下来便开始执行【2.8】installProvider过程。
再来看看场景二,如下:
3.6 AT.scheduleInstallProvider
[-> ActivityThread.java]
public void scheduleInstallProvider(ProviderInfo provider) {
sendMessage(H.INSTALL_PROVIDER, provider);
}
3.6.1 AT.handleInstallProvider
[-> ActivityThread.java]
public void handleInstallProvider(ProviderInfo info) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
try {
//[见流程3.3]
installContentProviders(mInitialApplication, Lists.newArrayList(info));
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
场景二,跟场景一后面的过程一样,再执行【小节3.3-3.5】过程。
四、总结
本文以ContentProvider的查询过程为例展开了对Provider的整个使用过程的源码分析.先获取provider,然后安装provider信息,最后便是真正的查询操作.
4.1 场景一(进程不存在)
Provider进程不存在: 当provider进程不存在时,先创建进程并publish相关的provider:

图解:
- client进程:通过binder(调用AMS.getContentProviderImpl)向system_server进程请求相应的provider;
- system进程:如果目标provider所对应的进程尚未启动,system_server会调用startProcessLocked来启动provider进程; 当进程启动完成,此时cpr.provider ==null,则system_server便会进入wait()状态,等待目标provider发布;
- provider进程:进程启动后执行完attch到system_server,紧接着执行bindApplication;在这个过程会installProvider以及 publishContentProviders;再binder call到system_server进程;
- system进程:再回到system_server,发布provider信息,并且通过notify机制,唤醒前面处于wait状态的binder线程;并将 getContentProvider的结果返回给client进程;
- client进程:接着执行installProvider操作,安装provider的(包含对象记录,引用计数维护等工作);
另外,关于CONTENT_PROVIDER_PUBLISH_TIMEOUT
超时机制所统计的时机区间是指在startProcessLocked之后会调用AMS.attachApplicationLocked为起点,一直到AMS.publishContentProviders的过程。
4.2 场景二(进程已存在)
provider未发布: 请求provider时,provider进程存在但provide的记录对象cpr ==null,这时的流程如下:

- Client进程在获取provider的过程,发现cpr为空,则调用scheduleInstallProvider来向provider所在进程发出一个oneway的binder请求,并进入wait()状态.
- provider进程安装完provider信息,则notifyAll()处于等待状态的进程/线程;
如果provider在publish完成之后, 这时再次请求该provider,那就便没有的最右侧的这个过程,直接在AMS.getContentProviderImpl之后便进入AT.installProvider的过程,而不会再次进入wait()过程.
最后, 关于provider分为stable provider和unstable provider, 在于引用计数 的不同,一句话来说就是stable provider建立的是强连接, 客户端进程的与provider进程是存在依赖关系, 即provider进程死亡则会导致客户端进程被杀.
网友评论