

為了放大時序圖,一些類縮小下:
CR:ContentResolver
ACR:ApplicationContentResolver
CPN:ContentProviderNative
CPR:ContentProviderProxy
AMN:ActivityManagerNative
AMP:ActivityManagerProxy
AMS:ActivityManagerService
ATP:ApplicationThreadProxy


- A應用發(fā)送信息給AMS(ActivityManagerService,進程system_server)要訪問B應用的XXXContentProvider
- AMS檢查B應用沒有被啟動過,則新開一個進程啟動B應用
- 啟動應用B后,AMS向B應用啟動XXXContentProvider,并實行相應的onCreate,返回IActivityManager.ContentProviderHolder,其中實現(xiàn)IContentProvider接口的Transact
- AMS 把IActivityManager.ContentProviderHolder對象返回給A應用,A應用改造成代理ContentProviderProxy(即IContentProvider),此時A應用就可以調(diào)用增刪改查等接口到B應用了。
照著類圖和時序圖的步數(shù)來分析:
在A應用進程處理:Step1、2、3、4、5、6、18、19
在AMS system_server進程處理:Step7、10、11、12、17
在B應用進程處理:Step8、9、13、14、15、16、20
Step1:
??ContentResolver contentResolver = Conext.getContentResolver();
返回是ApplicationContentResolver,定義在ContextImpl內(nèi)部靜態(tài)類。
Step2:
??Uri uri = Uri.parse("content://cn.umbrella.providers.contact/item");
Cursor cursor = contentResolver.query(uri, new String[]{"id","name","phone"}, null, null, "id asc");
在ApplicationContentResolver.acquireProvider()調(diào)用ActivityThread類的acquireProvider函數(shù)進一步執(zhí)行獲取Content Provider接口的操作。
Step3、4、5:
??ActivityThread. acquireProvider:先本地查找,若有,則直接返回,沒有則調(diào)用ActivityManagerNative.getDefault().getContentProvider(getApplicationThread(), auth, userId, stable)即ActivityManagerProxy到AMS的getContentProvider()。
Step6:
??在AMS. getContentProvider()調(diào)用getContentProviderImpl進一步處理,
在AMS中:ProviderMap mProviderMap成員變量是保存系統(tǒng)中的ContentProvider信息,boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed先檢查XXXContentProvider存在、宿主進程以及沒有被殺的情況下,就直接返回。
??若不存在,則會通過AppGlobals.getPackageManage().resolveContentProvider和getApplicationInfo來分別獲取XXXProvider應用程序的相關(guān)信息,并保存cpi和cpr變量中。接下來會判斷mLaunchingProviders(系統(tǒng)中所有正在加載的Content Provider都保到這里面)是不是正在被其它應用程序加載XXXContentProvider,如果B應用進程已開啟,但對應的contentprovider未初始化過,則會走proc.thread.scheduleInstallProvider(cpi),到B應用的ActivityThread的handleInstallProvider、installContentProviders初始化contentProvider,略過Step7-13步直接Step14。
??如果B應用進程未啟動,則繼續(xù)走Step7 調(diào)用startProcessLocked函數(shù)來啟動新進程并加裝XXXContentProvider,并且把這個正在加載的信息增加到mLaunchingProviders中去,同步等到XXXContentProvider初始化完,while循環(huán)cpr.provider判空,然后cpr.wait(),等到Step17步publishContentProviders會dst.notifyAll()過來。
Step7、8、9、10:
??ActivityManagerService.startProcessLocked、Process.start、ActivityThread.main、ActivityThread.attach、ActivityManagerService.attachApplication 新進程的創(chuàng)建完回到AMS的過程,可參考startService源碼從AMS進程到service的新進程啟動過程分析
Step11:
??AMS. attachApplicationLocked, 會對這個B應用進程記錄塊做一些初始化,并獲得需要加裝的ContentProvider列表,即包括XXXContentProvider,然后調(diào)用從參數(shù)傳進來的IApplicationThread對象thread(即ApplicationThreadProxy)的bindApplication進入到B應用程序XXXContentProvider進程中的ApplicationThread對象的bindApplication函數(shù)中去。
Step12、13:
??ApplicationThread(ActivityThread 變量). bindApplication通過H(Handler)到ActivityThread主進程中handleBindApplication處理,調(diào)用installContentProviders函數(shù)來在初始化XXXContent Providers信息,以及Application等初始化工作。
Step14、15:
??ActivityThread.installContentProviders 先調(diào)用installContentProviders對XXXContentProvider的初始化attachInfo,并調(diào)用onCreate,并把ContextProvider的成員變量Transport(父類ContentProviderNative,是binder對象,并且實現(xiàn)了IContentProvider接口)然后調(diào)用ActivityManagerNative.getDefault().publishContentProviders(getApplicationThread(), results),到Step16.
Step16:
??ActivityManagerProxy. publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers)通知AMS進程 ,B應用進程及XXXContentProvider都已初始化完畢,并把相應的IContentProvider給過去。
Step17 :
??AMS. publishContentProviders:會把B應用進程的的ContentProvider保存起來,并移除mLaunchingProviders里面相應的值,然后通知dst.notifyAll();到Step6的getContentProviderImpl,接著返回給A應用進程的ContentProviderHolder對象。
Step18:
??在AMS進程通過binder返回給A應用對象ContentProviderHolder,會把B應用進程的IContentProvider接口(即Transport)通過ContentProviderNative.asInterface(source.readStrongBinder())改造為ContentProviderProxy。
Step19、20:
??A應用進程拿到B應用進程的Transport后, ContentResolver.query()中調(diào)用ContentProviderProxy.query,這里面會BulkCursorToCursorAdaptor,包含CursorWindow等匿名共享內(nèi)存方式讀取數(shù)據(jù)。
附上一些關(guān)鍵的源碼:
ContextImpl.java:
class ContextImpl extends Context {
private final ApplicationContentResolver mContentResolver;
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
...
private static final class ApplicationContentResolver extends ContentResolver {
private final ActivityThread mMainThread;
private final UserHandle mUser;
...
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
...
}
}
ContentResolver.java:
public abstract class ContentResolver {
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
IContentProvider unstableProvider = acquireUnstableProvider(uri);
...
try {
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
...
}
}
ActivityThread.java:
public final class ActivityThread {
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
...
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord pr = mProviderMap.get(key);
...
IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
...
return provider;
}
}
private void installContentProviders(Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false, true , true );
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
}
}
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 {
try {
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
}
}
try {
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
}
} else {
provider = holder.provider;
}
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;
}
private void handleBindApplication(AppBindData data) {
...
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
...
if (ii != null) {
final ApplicationInfo instrApp = new ApplicationInfo();
ii.copyTo(instrApp);
instrApp.initForUser(UserHandle.myUserId());
final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true, false);
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
}
final ComponentName component = new ComponentName(ii.packageName, ii.name);
mInstrumentation.init(this, instrContext, appContext, component,
data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
} else {
mInstrumentation = new Instrumentation();
}
...
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
// 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);
}
}
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
try {
mInstrumentation.callApplicationOnCreate(app);
}
}
}
}
ActivityManagerNative.java:
public abstract class ActivityManagerNative extends Binder implements IActivityManager{
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);
}
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
IActivityManager am = asInterface(b);
return am;
}
};
}
class ActivityManagerProxy implements IActivityManager{
public ActivityManagerProxy(IBinder remote) {
mRemote = remote;
}
public ContentProviderHolder getContentProvider(IApplicationThread caller,
String name, int userId, boolean stable) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(name);
data.writeInt(userId);
data.writeInt(stable ? 1 : 0);
mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
ContentProviderHolder cph = null;
if (res != 0) {
cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
}
data.recycle();
reply.recycle();
return cph;
}
public void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeTypedList(providers);
mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
}
ActivityManagerService.java:
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
...
// The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
// with cross-user grant.
return getContentProviderImpl(caller, name, null, stable, userId);
}
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
long startTime = SystemClock.uptimeMillis();
ProcessRecord r = null;
...
// First check if this content provider has been published...
cpr = mProviderMap.getProviderByName(name, userId);
...
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
if (providerRunning) {
cpi = cpr.info;
...
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.
ContentProviderHolder holder = cpr.newHolder(null);
// don't give caller the provider object, it needs
// to make its own.
holder.provider = null;
return holder;
}
...
}
if (!providerRunning) {
try {
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
} catch (RemoteException ex) {
}
...
try {
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS, userId);
ai = getAppInfoForUser(ai, userId);
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} catch (RemoteException ex) {
...
}
...
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// If the provider is not already being launched, then get it
// started.
if (i >= N) {
...
try {
...
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null && !proc.killed) {
if (!proc.pubProviders.containsKey(cpi.name)) {
checkTime(startTime, "getContentProviderImpl: scheduling install");
proc.pubProviders.put(cpi.name, cpr);
try {
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
...
}
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
...
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
// Wait for the provider to be published...
synchronized (cpr) {
while (cpr.provider == 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;
}
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
ProfilerInfo profilerInfo = profileFile == null ? null
: new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked());
...
return true;
}
}
IActivityManager.java:
public interface IActivityManager extends IInterface {
public static class ContentProviderHolder implements Parcelable {
public final ProviderInfo info;
public IContentProvider provider;
public IBinder connection;
public boolean noReleaseNeeded;
...
public static final Parcelable.Creator<ContentProviderHolder> CREATOR
= new Parcelable.Creator<ContentProviderHolder>() {
@Override
public ContentProviderHolder createFromParcel(Parcel source) {
return new ContentProviderHolder(source);
}
@Override
public ContentProviderHolder[] newArray(int size) {
return new ContentProviderHolder[size];
}
};
private ContentProviderHolder(Parcel source) {
info = ProviderInfo.CREATOR.createFromParcel(source);
provider = ContentProviderNative.asInterface(
source.readStrongBinder());
connection = source.readStrongBinder();
noReleaseNeeded = source.readInt() != 0;
}
}
}