您的位置:首页 > 移动开发 > Android开发

Android之ContentProvider的启动过程源码分析

2016-07-26 19:52 477 查看
ContentProvider组件一次传递的数据量可能非常大,如果直接使用Binder进程间通信机制来传递数据的话,传输效率是个问题。不同的应用程序进程可以通过匿名共享内存来传输大数据,因为无论多大的数据,对匿名共享内存来说,需要在进程间传递的仅仅是一个文件描述符而已。这样,结合Binder进程间通信机制和匿名共享内存机制,ContentProvider组件就可以实现高效的文件传输了。

ContentProvider中query方法返回的保存在cursor对象中的数据是通过匿名共享内存来传输的,call方法返回的数据是保存在Bundle对象中的,它直接使用Binder进程间通信机制来传输的。当传输的数据量比较小时,使用匿名共享内存就得不偿失了,因为它的创建过程和映射过程都是需要开销的。

Provider的启动过程大致分为几个步骤:

1.调用者通过URI访问目标Provider。

2.调用者所运行在的应用程序进程发现不存在要访问的目标Provider的代理对象,就会通过URI来请求ActivityManagerService返回一个用来访问目标Provider组件的代理对象。

3.AMS发现这个Provider组件还没有启动起来,就会先创建一个新的应用程序进程,然后在这个进程中启动目标Provider组件。

4.目标Provider组件启动起来后,就会将自己发布到AMS中,以便AMS可以将它的一个代理对象返回给调用者使用。

使用Provider时需要先调用getContentProvider()方法来获取ContentResolver对象,惯例先看时序图:



先看ContextWrapper类中的getContentResolver方法:

@Override
public ContentResolver getContentResolver() {
return mBase.getContentResolver();
}


调用到ContextImpl类中的getContentResolver方法:

private final ApplicationContentResolver mContentResolver;

private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration, int createDisplayWithId) {

mMainThread = mainThread;
. . .

mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}

@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}

private static final class ApplicationContentResolver extends ContentResolver {
private final ActivityThread mMainThread;
private final UserHandle mUser;

public ApplicationContentResolver(
Context context, ActivityThread mainThread, UserHandle user) {
super(context);
mMainThread = Preconditions.checkNotNull(mainThread);
mUser = Preconditions.checkNotNull(user);
}

// 实现父类中的抽象方法,后面会调用
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}

// 实现父类中的抽象方法,后面会调用
@Override
public boolean releaseProvider(IContentProvider provider) {
return mMainThread.releaseProvider(provider, true);
}

/** @hide */
protected int resolveUserIdFromAuthority(String auth) {
return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier());
}
. . .

}


上面ApplicationContentResolver是ContextImpl的内部类。到这里调用者就获取到了ContentResolver对象。

获取到对象后,假设调用者要访问目标Provider的insert方法(其他方法的流程基本一致),先看下时序图:



先看ContentResolver类的insert方法:

public static final String SCHEME_CONTENT = "content";

public ContentResolver(Context context) {
mContext = context != null ? context : ActivityThread.currentApplication();
mPackageName = mContext.getOpPackageName();
}

public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) {
android.util.SeempLog.record_uri(37, url);
Preconditions.checkNotNull(url, "url");
// 获取provider
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
long startTime = SystemClock.uptimeMillis();
// 执行插入操作
Uri createdRow = provider.insert(mPackageName, url, values);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
return createdRow;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
} finally {
// 释放provider
releaseProvider(provider);
}
}

/**
* Returns the content provider for the given content URI.
*
* @param uri The URI to a content provider
* @return The ContentProvider for the given URI, or null if no content provider is found.
* @hide
*/
public final IContentProvider acquireProvider(Uri uri) {
// 判断scheme是否以content开头,如果不是说明这个uri不是用来访问provider的
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
final String auth = uri.getAuthority();
if (auth != null) {
// 获取provider对象
return acquireProvider(mContext, auth);
}
return null;
}

// 抽象方法,由子类实现
/** @hide */
protected abstract IContentProvider acquireProvider(Context c, String name);


调用到这里,又回到了ContextImpl的内部类ApplicationContentResolver中的acquireProvider方法,该方法中又调用了ActivityThread类中的acquireProvider方法,看该方法之前,先看下传递的参数:

getUserIdFromAuthority方法获取userId:
/**
* Removes userId part from authority string. Expects format:
* userId@some.authority
* If there is no userId in the authority, it symply returns the argument
* @hide
*/
public static String getAuthorityWithoutUserId(String auth) {
if (auth == null) return null;
int end = auth.lastIndexOf('@');
// 截取authority
return auth.substring(end+1);
}

/** @hide */
public static int getUserIdFromAuthority(String auth, int defaultUserId) {
if (auth == null) return defaultUserId;
int end = auth.lastIndexOf('@');
if (end == -1) return defaultUserId;
// 截取userId
String userIdString = auth.substring(0, end);
try {
return Integer.parseInt(userIdString);
} catch (NumberFormatException e) {
Log.w(TAG, "Error parsing userId.", e);
return UserHandle.USER_NULL;
}
}


上面两个方法主要是截取不规则的authority和获取userId的。再接着看下后续的时序图:



根据上面时序图,先看下ActivityThread类中的acquireProvider方法:

public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
// 调用acquireExistingProvider检查该provider代理对象是否已经存在
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
// 如果已经存在则直接返回
if (provider != null) {
return provider;
}

// There is a possible race here.  Another thread may try to acquire
// the same provider at the same time.  When this happens, we want to ensure
// that the first one wins.
// Note that we cannot hold the lock while acquiring and installing the
// provider since it might take a long time to run and it could also potentially
// be re-entrant in the case where the provider is in the same process.
IActivityManager.ContentProviderHolder holder = null;
try {
// 通过BInder代理对象调用AMS的getContentProvider方法获取到目标Provider的代理对象
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}

// Install provider will increment the reference count for us, and break
// any ties in the race.
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}

// 用来保存当前应用程序进程中访问过的Content Provider组件代理对象
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
= new ArrayMap<ProviderKey, ProviderClientRecord>();
// 各Provider被引用次数map
final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
= new ArrayMap<IBinder, ProviderRefCount>();

public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
final ProviderKey key = new ProviderKey(auth, userId);
// 检查mProviderMap中是否已经有目标Provider代理对象
final ProviderClientRecord pr = mProviderMap.get(key);
// 如果没有则返回null
if (pr == null) {
return null;
}

IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
// 判断目标Provider代理对象所运行在的进程是否还在运行
if (!jBinder.isBinderAlive()) {
// The hosting process of the provider has died; we can't
// use this one.
Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+ ": existing object's process dead");
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}

// Only increment the ref count if we have one.  If we don't then the
// provider is not reference counted and never needs to be released.
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
// 判断mProviderRefCountMap中是否有目标Provider,如果有则其引用次数加1
if (prc != null) {
incProviderRefLocked(prc, stable);
}
return provider;
}
}


接着看下ActivityManagerService类中的getContentProvider方法:

@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
// The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
// with cross-user grant.
return getContentProviderImpl(caller, name, null, stable, userId);
}

final ProviderMap mProviderMap;

private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
// 在AMS中,每个已经启动的Provider组件都使用一个ContentProviderRecord对象来描述,并保存在mProviderMap中
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;

/*在这里可以准备自启动黑白名单的初始化操作*/

synchronized(this) {
long startTime = SystemClock.elapsedRealtime();

ProcessRecord r = null;
if (caller != null) {
// 获取目标Provider组件代理对象的应用程序进程的信息
r = getRecordForAppLocked(caller);
if (r == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when getting content provider " + name);
}
}

boolean checkCrossUser = true;

// 判断从startTime到这里的操作是否超过1秒
checkTime(startTime, "getContentProviderImpl: getProviderByName");

// First check if this content provider has been published...
// mProviderMap在构造方法中初始化
cpr = mProviderMap.getProviderByName(name, userId);
// If that didn't work, check if it exists for user 0 and then
// verify that it's a singleton provider before using it.
if (cpr == null && userId != UserHandle.USER_OWNER) {
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
if (cpr != null) {
cpi = cpr.info;
if (isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
userId = UserHandle.USER_OWNER;
checkCrossUser = false;
} else {
cpr = null;
cpi = null;
}
}
}

boolean providerRunning = cpr != null;
if (providerRunning) {
cpi = cpr.info;
String msg;
checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
// 检查权限
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
!= null) {
throw new SecurityException(msg);
}
checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");

// 判断目标Provider的android:multiprocess属性是否为true
if (r != null && cpr.canRunHere(r)) {
// This provider has been published or is in the process
// of being published...  but it is also allowed to run
// in the caller's process, so don't make a connection
// and just let the caller instantiate its own instance.
// 为true说明目标Provider可以运行在调用者所在进程,故这里不用建立连接,因为调用者可以自己实例化目标Provider
ContentProviderHolder holder = cpr.newHolder(null);
// don't give caller the provider object, it needs
// to make its own.
holder.provider = null;
return holder;
}

final long origId = Binder.clearCallingIdentity();

checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");

// In this case the provider instance already exists, so we can
// return it right away.
// 获取连接
conn = incProviderCountLocked(r, cpr, token, stable);
// 如果稳定连接和不稳定连接之和为1
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// If this is a perceptible app accessing the provider,
// make sure to count it as being accessed and thus
// back up on the LRU list.  This is good because
// content providers are often expensive to start.
checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
// 开启Provider成本较高,故这里做下备份以后续访问时减小开销
updateLruProcessLocked(cpr.proc, false, null);
checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
}
}

if (cpr.proc != null) {
if (false) {
if (cpr.name.flattenToShortString().equals(
"com.android.providers.calendar/.CalendarProvider2")) {
Slog.v(TAG, "****************** KILLING "
+ cpr.name.flattenToShortString());
Process.killProcess(cpr.proc.pid);
}
}
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
// 更新目标Provider所在进程的Adj值,如果返回false说明进程被杀
boolean success = updateOomAdjLocked(cpr.proc);
// 更新目标Provider最近使用时间
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
// NOTE: there is still a race here where a signal could be
// pending on the process even though we managed to update its
// adj level.  Not sure what to do about this, but at least
// the race is now smaller.
if (!success) {
// Uh oh...  it looks like the provider's process
// has been killed on us.  We need to wait for a new
// process to be started, and make sure its death
// doesn't kill our process.
Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
// 连接数减1后是否还有连接,如果没有则为true
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
checkTime(startTime, "getContentProviderImpl: before appDied");
appDiedLocked(cpr.proc);
checkTime(startTime, "getContentProviderImpl: after appDied");
if (!lastRef) {
// This wasn't the last ref our process had on
// the provider...  we have now been killed, bail.
return null;
}
providerRunning = false;
conn = null;
}
}

Binder.restoreCallingIdentity(origId);
}

boolean singleton;
// 目标Provider没有在运行中
if (!providerRunning) {
try {
checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
// 到PMS中查找android:authorities属性值等于name的Provider组件的信息
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
} catch (RemoteException ex) {
}
// cpi为null说明没有任何应用提供该Provider
if (cpi == null) {
return null;
}
// If the provider is a singleton AND
// (it's a call within the same user || the provider is a
// privileged app)
// Then allow connecting to the singleton provider
singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_OWNER;
}else{
//SmartContainer modified begin
if (!SmartContainerConfig.WITH_OUT_VIRTUAL_BOX){
userId = UserHandle.getUserId(cpi.applicationInfo.uid);
}
//SmartContainer modified end
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
checkTime(startTime, "getContentProviderImpl: got app info for user");

String msg;
checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
// 检查权限
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
throw new SecurityException(msg);
}
checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");

if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
&& !cpi.processName.equals("system")) {
// If this content provider does not run in the system
// process, and the system is not yet ready to run other
// processes, then fail fast instead of hanging.
throw new IllegalArgumentException(
"Attempt to launch content provider before system ready");
}

// Make sure that the user who owns this provider is running.  If not,
// we don't want to allow it to run.
if (!isUserRunningLocked(userId, false)) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": user " + userId + " is stopped");
return null;
}

// cpi.name是Provider组件的类名
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
// 根据从PMS中查询到的Provider类名到mProviderMap查找是否有与类名一致的cpr对象
cpr = mProviderMap.getProviderByClass(comp, userId);
checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
final boolean firstClass = cpr == null;
// firstClass为true说明目标Provider组件还没有启动起来
if (firstClass) {
final long ident = Binder.clearCallingIdentity();
try {
checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
// 到PMS中查找目标Provider所属应用程序的信息
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS, userId);
checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
// 如果为null说明不存在,直接返回null
if (ai == null) {
Slog.w(TAG, "No package info for content provider "
+ cpi.name);
return null;
}
ai = getAppInfoForUser(ai, userId);
// 将cpi、ai等信息封装成一个cpr对象,用来描述即将要启动的Provider组件
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
} finally {
Binder.restoreCallingIdentity(ident);
}
}

checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");

// 启动之前先检查先检查multiprocess属性是否为true
if (r != null && cpr.canRunHere(r)) {
// If this is a multiprocess provider, then just return its
// info and allow the caller to instantiate it.  Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
return cpr.newHolder(null);
}

if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
+ (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
+ cpr.info.name + " callers=" + Debug.getCallers(6));

// This is single process, and our app is now connecting to it.
// See if we are already in the process of launching this
// provider.
// AMS把所有正在启动的Provider组件都保存在mLaunchingProviders中
final int N = mLaunchingProviders.size();
int i;
// 遍历查找要启动的Provider是否正在启动中
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}

// If the provider is not already being launched, then get it
// started.
// i >= N说明要启动的Provider没有在启动中
if (i >= N) {
final long origId = Binder.clearCallingIdentity();

try {
// Content provider is now in use, its package can't be stopped.
try {
checkTime(startTime, "getContentProviderImpl: before set stopped state");
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
checkTime(startTime, "getContentProviderImpl: after set stopped state");
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ cpr.appInfo.packageName + ": " + e);
}

// Use existing process if already started
checkTime(startTime, "getContentProviderImpl: looking for process record");
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
// 如果要启动的Provider所在的进程已经启动,则直接在进程中安装该Provider即可
if (proc != null && proc.thread != null) {
if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
"Installing in existing process " + proc);
// 判断目标Provider是否已经发布
if (!proc.pubProviders.containsKey(cpi.name)) {
checkTime(startTime, "getContentProviderImpl: scheduling install");
// 把目标Provider保存在pubProviders中
proc.pubProviders.put(cpi.name, cpr);
try {
// 都有ActivityThread类中的scheduleInstallProvider方法安装模板Provider
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
// 目标Provider所运行在的进程还没有启动,则需要先启动进程再安装Provider
} else {

/*下面要启动进程了,故这里可以增加禁止自启动的判断*/

checkTime(startTime, "getContentProviderImpl: before start process");
// 启动进程
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
checkTime(startTime, "getContentProviderImpl: after start process");
if (proc == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": process is bad");
return null;
}
}
cpr.launchingApp = proc;
// 把cpr放到正在启动的Provider列表中
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}

checkTime(startTime, "getContentProviderImpl: updating data structures");

// Make sure the provider is published (the same provider class
// may be published under multiple names).
if (firstClass) {
// 保存cpr对象
mProviderMap.putProviderByClass(comp, cpr);
}

// 保存cpr对象
mProviderMap.putProviderByName(name, cpr);
// 获取连接
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
// 因为目标Provider组件需要等待进程启动后才能启动,故需要等待进程启动完成
conn.waiting = true;
}
}
checkTime(startTime, "getContentProviderImpl: done!");
}

// Wait for the provider to be published...
synchronized (cpr) {
// 循环等待cpr所描述的Provider组件启动完成
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();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}

// 判断每个操作是否超过1秒
private void checkTime(long startTime, String where) {
long now = SystemClock.elapsedRealtime();
if ((now-startTime) > 1000) {
// If we are taking more than a second, log about it.
Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where);
}
}


下面看ActivityThread类中的scheduleInstallProvider方法:

@Override
public void scheduleInstallProvider(ProviderInfo provider) {
sendMessage(H.INSTALL_PROVIDER, provider);
}

private class H extends Handler {

public static final int INSTALL_PROVIDER        = 145;
. . .

public void handleMessage(Message msg) {
switch (msg.what) {
. . .
case INSTALL_PROVIDER:
handleInstallProvider((ProviderInfo) msg.obj);
break;
}
}
}

public void handleInstallProvider(ProviderInfo info) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
try {
installContentProviders(mInitialApplication, Lists.newArrayList(info));
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}

private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();

// 循环调用installProvider方法在当前应用程序进程中启动保存在providers列表中的所有Provider组件
for (ProviderInfo cpi : providers) {
if (DEBUG_PROVIDER) {
StringBuilder buf = new StringBuilder(128);
buf.append("Pub ");
buf.append(cpi.authority);
buf.append(": ");
buf.append(cpi.name);
Log.i(TAG, buf.toString());
}
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}

try {
// 将所有的cph对象传递给AMS,以便AMS可以获取到它们所描述的Provider组件的一个访问接口
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
}
}


接下来先分析installProvider方法在当前应用程序进程中启动一个Provider组件的过程,然后再分析AMS的publishContentProviders方法将启动完成之后的Provider组件发布到AMS中的过程:

publishContentProviders方法将启动完成之后的Provider组件发布到AMS中的过程:
/**
* Installs the provider.
*
* Providers that are local to the process or that come from the system server
* may be installed permanently which is indicated by setting noReleaseNeeded to true.
* Other remote providers are reference counted.  The initial reference count
* for all reference counted providers is one.  Providers that are not reference
* counted do not have a reference count (at all).
*
* This method detects when a provider has already been installed.  When this happens,
* it increments the reference count of the existing provider (if appropriate)
* and returns the existing provider.  This can happen due to concurrent
* attempts to acquire the same provider.
*/
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) {
if (DEBUG_PROVIDER || noisy) {
Slog.d(TAG, "Loading provider " + info.authority + ": "
+ info.name);
}
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 {
try {
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
}
if (c == null) {
Slog.w(TAG, "Unable to get context for package " +
ai.packageName +
" while loading content provider " +
info.name);
return null;
}
try {
final java.lang.ClassLoader cl = c.getClassLoader();
// info.name描述了要在当前进程中启动的Provider组件的类名
// 这里根据类名在进程中创建了一个Provider组件的实例
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
// 获得一个IContentProvider接口,该接口是要发布到AMS中的,以便AMS可以将它返回给那些需要
// 访问它所描述的Provider组件的应用程序进程
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
info.name + " from sourceDir " +
info.applicationInfo.sourceDir);
return null;
}
if (DEBUG_PROVIDER) Slog.v(
TAG, "Instantiating local provider " + info.name);
// XXX Need to create the correct context for this provider.
// 进一步初始化创建的Provider组件
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
if (!mInstrumentation.onException(null, e)) {
throw new RuntimeException(
"Unable to get provider " + info.name
+ ": " + e.toString(), e);
}
return null;
}
} else {
provider = holder.provider;
if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
+ info.name);
}

IActivityManager.ContentProviderHolder retHolder;

synchronized (mProviderMap) {
if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
+ " / " + info.name);
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
// 根据组件名到mLocalProvidersByName中查询是否已经存在
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, "
+ "using existing local provider");
}
provider = pr.mProvider;
} else {
holder = new IActivityManager.ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
// 将provider组件封装成一个pr对象
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
// 对一个应用程序进程来说,它所访问的Provider组件有可能是在当前应用程序进程中运行,也有可能是在
// 其他应用程序进程中运行。为了区分这两种情况,用mLocalProviders变量来保存运行在当前进程中的Provider
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
// 根据Provider的Binder对象获取prc对象
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, updating ref count");
}
// We need to transfer our new reference to the existing
// ref count, releasing the old one...  but only if
// release is needed (that is, it is not running in the
// system process).
if (!noReleaseNeeded) {
// Provider的引用数量加1
incProviderRefLocked(prc, stable);
try {
ActivityManagerNative.getDefault().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {
// 如果prc对象为null,说明不存在目标Provider对象,需要创建
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) {
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;
}

private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
// authority描述了android:authorities属性值,它是一个多值属性
final String auths[] = holder.info.authority.split(";");
final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);

// 创建一个pcr对象
final ProviderClientRecord pcr = new ProviderClientRecord(
auths, provider, localProvider, holder);
// 循环根据auth创建ProviderKey对象并保存在mProviderMap中
for (String auth : auths) {
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord existing = mProviderMap.get(key);
if (existing != null) {
Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
+ " already published as " + auth);
} else {
mProviderMap.put(key, pcr);
}
}
return pcr;
}


每一个Provider组件内部都有一个类型为Transport的Binder本地对象,这个Binder本地对象是用来传递给AMS的,然后AMS再将引用了它的一个Binder代理对象返回给需要访问该Provider组件的其他应用程序进程。这样,其他应用程序进程就可以通过这个Binder代理对象来间接地访问一个Provider组件中的数据了。

下面看ContentProvider类中的getIContentProvider方法和attachInfo方法:

private Transport mTransport = new Transport();

/**
* Binder object that deals with remoting.
* @hide
*/
class Transport extends ContentProviderNative {
. . .
}

/**
* Returns the Binder object for this provider.
* @hide
*/
public IContentProvider getIContentProvider() {
return mTransport;
}

/**
* After being instantiated, this is called to tell the content provider
* about itself.
*/
public void attachInfo(Context context, ProviderInfo info) {
attachInfo(context, info, false);
}

private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;

/*
* Only allow it to be set once, so after the content service gives
* this to us clients can't change it.
*/
if (mContext == null) {
mContext = context;
if (context != null) {
mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(
Context.APP_OPS_SERVICE);
}
mMyUid = Process.myUid();
if (info != null) {
// 将Provider的访问权限保存
setReadPermission(info.readPermission);
setWritePermission(info.writePermission);
setPathPermissions(info.pathPermissions);
mExported = info.exported;
mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
setAuthorities(info.authority);
}
// 回调ContentProvider的onCreate方法
ContentProvider.this.onCreate();
}
}


最后看AMS中的publishContentProviders方法:

public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}

enforceNotIsolatedCaller("publishContentProviders");
synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
if (r == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when publishing content providers");
}

final long origId = Binder.clearCallingIdentity();

final int N = providers.size();
// 循环取出保存在providers中的每一个ContentProviderHolder对象src,
// 然后在AMS中找到与它对应的ContentProviderHolder对象dst
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 (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) {
// 将src所描述的一个Provider组件的一个IContentProvider访问接口保存在dst的成员变量provider中
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}
updateOomAdjLocked(r);
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
src.info.authority);
}
}

Binder.restoreCallingIdentity(origId);
}
}


到这里Provider已经启动完成了,并且将它的一个代理对象即一个类型为Transport的Binder代理对象发布到AMS中了。

内容有理解错误或偏差之处,请包涵指正,谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: