作为四大组件之一的ContentProvider,相比来说是设计得稍逊色,有些地方不太合理,比如provider级联被杀, 请求provider时占用system_server的binder线程来wait()等。
即便很少自定义ContentProvider,但你也可以会需要使用到ContentProvider,比如通信录,Settings等; 使用Provider往往跟数据库结合起来使用,所以这里需要注意不要再主线程用provider做过多的io操作。
先以一幅图来展示AMS管理ContentProvider所涉及的相关数据结构: 点击查看大图
功能:连接contentProvider与请求该provider所对应的进程
点击查看大图
更多源码详细过程,见理解ContentProvider原理
以上博文转自gityuan的四大组件之ContentProviderRecord
------------------------------------------------------分割线--------------------------------------------------
以下是本人的一些备注:
ActivityThread中的相关成员:
mProviderMap:ProviderKey由ContentProvider的authorith和userId组成;mProviderMap里面包含了acquireProvider得来的Transport,也包含和从本进程publish的ContentProvider。就是说ProviderClientRecord是本地Provider和从远端进程获得的Provider共用的一个结构体,即ProviderClientRecord可以表示一个本地Provider,也可以表示从远端进程获得的Provider(后面会称为远端Provider)。如果表示从远端进程获得的Provider,那么ContentProvider mLocalProvider成员为null。ContentProviderHolder是两者都有的一个成员。但是ContentProviderHolder#ContentProviderConnection只有表示从远端进程获得的Provider才不为null。
mProviderRefCountMap:是专门用于对远端Provider计数的。
mLocalProviders和mLocalProvidersByName:两者都只是包含本地Provider,两者的区别只在于key不一样。一个是IContentProvider作为key,一个是ComponentName作为key。
ContentProviderRecord创建于ActivityThread调用AMS#attachApplication时(如果Client acquireProvider()时,ContentProviderRecord没创建,则会创建,那么attachApplication时就不会重复创建),而installContentPrivders是在AMS调用IApplicationThread#bindApplication时,在AT中执行的。
AMS#attachApplication
List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
generateApplicationProvidersLocked
private final List generateApplicationProvidersLocked(ProcessRecord app) {
List providers = null;
try {
providers = AppGlobals.getPackageManager()
.queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
| MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
.getList();
} catch (RemoteException ex) {
}
if (DEBUG_MU) Slog.v(TAG_MU,
"generateApplicationProvidersLocked, app.info.uid = " + app.uid);
int userId = app.userId;
if (providers != null) {
int N = providers.size();
app.pubProviders.ensureCapacity(N + app.pubProviders.size());
for (int i=0; i
ActivityThread#handleBindApplication(AppBindData data)
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
ContentProviderConnection在应用进程向AMS获取IContentProvider时创建
getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId)
conn = incProviderCountLocked(r, cpr, token, stable);
ContentProviderConnection incProviderCountLocked(ProcessRecord r,
final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable)
if (r != null) {
for (int i=0; i // Wait for the provider to be published...
synchronized (cpr) {
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": launching app became null");
EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
UserHandle.getUserId(cpi.applicationInfo.uid),
cpi.applicationInfo.packageName,
cpi.applicationInfo.uid, name);
return null;
}
try {
if (DEBUG_MU) Slog.v(TAG_MU,
"Waiting to start provider " + cpr
+ " launchingApp=" + cpr.launchingApp);
if (conn != null) {
conn.waiting = true;
}
cpr.wait();//Object.wait(),在这里等待provider发布
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
AMS#publishContentProviders()
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
if (dst != null) {
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
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) {
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;
dst.notifyAll();//Object.notifyAll(),唤醒在等待队列中的binder线程
}