前言
Content Provider作为四大组件之一,即内容提供者,与其他组件比使用率低,它主要用于进程内和进程间的数据共享。ContentProvider启动后外界都可以通过它提供的增删改查四个接口来操作数据源,通过这任何一个方法都可以触发ContentProvider所在进程的启动。这部分内容我们将分为两部分讲解,query到AMS过程和AMS到Content Provider的启动过程。
query到AMS过程
为了便于理解query到AMS过程,我们先看它调用过程序列图,如图所示:
在查询数据时,我们需要调用ContentResolver的query方法,在这方法里面又调用acquireUnstableProvider方法,如代码所示。
public final Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
//1
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
//2
qCursor = unstableProvider.query(mPackageName, uri, projection,
queryArgs, remoteCancellationSignal);
}
1 调用acquireUnstableProvider方法返回IContentProvider类型的unstableProvider对象。
2 unstableProvider去调用query方法查询数据。
IContentProvider实则是ContentProvider的本地代理,实现的方法在ContentProvider里,然后我们再看看acquireUnstableProvider方法做了什么,代码所示。
public final IContentProvider acquireUnstableProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
String auth = uri.getAuthority();
if (auth != null) {
return acquireUnstableProvider(mContext, uri.getAuthority());
}
return null;
}
acquireUnstableProvider调用了ContentResolver的抽象方法,实则调用了ContentResolver的子类ApplicationContentResolver,也是ContextImpl的内部类。我们在看下什么时候初始化ApplicationContentResolver子类对象的,去ContextImpl构造方法,代码如下。
private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread,
@NonNull LoadedApk packageInfo, @Nullable String splitName,
@Nullable IBinder activityToken, @Nullable UserHandle user, int flags,
@Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) {
mOuterContext = this;
mMainThread = mainThread;
mActivityToken = activityToken;
//1
mContentResolver = new ApplicationContentResolver(this, mainThread);
}
1 当Application初始化时候前都创建了ContextImpl实例,并且把ApplicationContentResolver对象赋值给mContentResolver。
ApplicationContentResolver的acquireUnstableProvider方法调用了ActivityThread的acquireProvider方法。
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
//1
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
ContentProviderHolder holder = null;
try {
synchronized (getGetProviderLock(auth, userId)) {
//2
holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
//3
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
1 在ActivityThread的mProviderMap全局变量查找是否存在IContentProvider类型的对象即具体实现者ContentProvider,没有都继续走第二步,后面会讲mProviderMap的存入过程。
2 在AMS的getContentProvider去获取。
3 获取到新的IContentProvider对象包装后存在mProviderMap中。
第二点调用了AMS的getContentProvider方法,这是跨进程调用。
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String callingPackage, String name, int userId,
boolean stable) {
return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
null, stable, userId);
}
然后调用了getContentProviderImpl方法,如代码所示。
private ContentProviderHolder
getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingPackage, String callingTag,
boolean stable, int userId) {
ContentProviderRecord cpr;
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
if (proc != null && proc.thread != null && !proc.killed) {
//1
proc.thread.scheduleInstallProvider(cpi);
} else {
//2
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0,
new HostingRecord("content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name)), false, false, false);
}
mProviderMap.putProviderByName(name, cpr);
return cpr.newHolder(conn);
}
1 创建的ContentProvider的进程是否存在,都会调用这个方法。
2 需要创建新的进程。
由于分析2点包含了1点内容,我们继续分析2点的方法。startProcessLocked方法创建一个新的进程,新进程创建好后调用了ActivityThread的main方法,绑定进程和应用关联,下面是main的具体代码。
public static void main(String[] args) {
Process.setArgV0("<pre-initialized>");
//为主线程创建loop对象,我们在主线程使用Handler时候没有初始化都可以使用,因为这里做了初始化。
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
//开始死循环获得消息
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
调用了ActivityThread的attach方法。接着我们继续看源码,如下。
private void attach(boolean system, long startSeq) {
if (!system) {
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
}
attach方法中,调用了AMS attachApplication方法。上面的分析都是query到AMS过程的代码。
Content Provider 启动过程
再看源码之前先看一张启动过程的代码时序图,让我们更容易读懂源码过程,如图:
在创建Application时需要调用AMS的attachApplication方法,代码如下。
private void handleBindApplication(AppBindData data) {
//设置进程名字
Process.setArgV0(data.processName);
//创建LoadedApk实例
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
//1
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi,
appContext.getOpPackageName());
final ClassLoader cl = instrContext.getClassLoader();
//2
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
//3
mInstrumentation.init(this, instrContext, appContext, component,
data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
Application app;
//4
app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
//5
installContentProviders(app, data.providers);
}
}
//6
mInstrumentation.onCreate(data.instrumentationArgs);
}
1)创建ContextImpl上下文。2) 利用反射机制创建Instrumentation的实例。3)初始化Instrumentation且调用init方法。4)调用LoadedApk的makeApplication方法创建Application对象。5)创建ContextProvider并且调用onCreate方法。6)调用Application的onCreate方法。
从上面的5和6的标记点看出ContentProvider比Application先调用onCreate方法,这是与其他三大组件有所不同的地方。继续看5点调用installContentProviders方法。
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
for (ProviderInfo cpi : providers) {
//1
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
//2
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
1)installContentProviders调用了installProvider来创建ContentProviderHolder类的对象。2)通过调用AMS的publishContentProviders方法将ContentProviderHolder数组存在ProviderMap中。在1点中调用了installProvider方法,代码如下。
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
final ClassLoader cl = c.getClassLoader();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
if (packageInfo == null) {
packageInfo = getSystemContext().mPackageInfo;
}
//1
localProvider = packageInfo.getAppFactory()
.instantiateProvider(cl, info.name);
provider = localProvider.getIContentProvider();
if (provider == null) {
return null;
}
//2
localProvider.attachInfo(c, info);
holder = new ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
//3
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
return retHolder;
}
在installProvider方法中,1 通过反射创建ContentProvider对象。2 调用了attachInfo方法,然后调用了ContextProvider的onCreate方法,完成了ContextProvider的创建。3 调用了installProviderAuthoritiesLocked方法,主要工作是把IContentProvider类和ContentProvider类封装在ProviderClientRecord中且保存在mProviderMap的map里面,这个都是之前分析acquireExistingProvider方法获取存在缓存的IContentProvider类型对象。上面都是所有的Content Provider 启动过程的分析。