本进程的contentprovider的启动过程一般是在应用进程启动的时候就会启动contentproivder,contentprovider是四大组件启动最早的那个
1:创建一个新的进程。调用ActivityThread的main方法
2: 调用ActivityThread的attach方法
3:调用ActivityManagerService的attachApplication方法,通知新的进程创建完成,根据新创建的进程初始化ProcessRecord的信息。然后查询所有和本进程相关的ContentProvider信息。
4:调用新建进程的bindApplication方法,通知新进程安装并启动这些ContentProvider
ContentProvider的启动流程
我们都知道应用程序的入口是ActivityThread的main方法,其中有一个重要的操作就是在main方法中构造一个ActivityThread,然后调用其attach方法在attach方法有有一个很重要的操作
attach方法
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
向ams注册一个appthread对象
2:我们分析下attachApplication在ams端的实现
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
这个方法很简单,只是简单的调用下attachApplicationLocked方法
3:继续分析attachApplicationLocked方法的实现
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
我们可以看到有这么一个关键的调用
Ams会回调thread的bindApplication方法,此处的thread也就是刚刚想ams注册的applicationthread,这样又通过binder的方式回到了应用进程
4:向应用的主线程发送一个消息
sendMessage(H.BIND_APPLICATION, data);
5:对于消息的处理
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
6:handleBindApplication
该方法主要完成LoadedApk对象的创建,ApplicationContext, ApplicationInfo,Instrumention,Application等初始化工作,其中中间有一步重要的判断就是
// 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);
}
}
判断ApplicationInfo中是否包含contetprovider
ApplicationInfo是通过PackageParser解析AndroidMainfiest.xml构建出来的,如果有,那么就会安装
7:installContentProviders的实现
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
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());
}
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
逻辑也不是很多,根据providerinfo安装数组中的每一个provider,其中providerinfo描述的就是一个provider的所有信息,类似的还有activityinfo,serviceinfo等,和packageparser里面的providerinfo是对应的,安装完成之后就执行发布操作
8:先看看installProvider的实现
try {
final java.lang.ClassLoader cl = c.getClassLoader();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
if (packageInfo == null) {
// System startup case.
packageInfo = getSystemContext().mPackageInfo;
}
localProvider = packageInfo.getAppFactory()
.instantiateProvider(cl, info.name);
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.
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;
}
首先通过classloader发射调用创建一个provider,然后关联一个context对象
localProvider.attachInfo(c, info);
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) {
setReadPermission(info.readPermission);
setWritePermission(info.writePermission);
setPathPermissions(info.pathPermissions);
mExported = info.exported;
mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
setAuthorities(info.authority);
}
ContentProvider.this.onCreate();
}
在这个过程中还设置了其读写权限和能不能被其他进程和组件应用,然后会回调其oncreate方法,contentprovider的oncreate方法是一个抽象方法,我们得去实现它
9:发布应用所有的provider
try {
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
通过ams去发布provider
10:进入到ams里面去看看具体的实现
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 (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();
}
updateOomAdjLocked(r, true);
maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
src.info.authority);
}
}
具体的操作也就是:
1:为每一个providerInfo信息创建一个ContentProviderRecord对象,并且保存到mProviderMap对象中
2:移除contentprovider启动超时的消息
if (wasInLaunchingProviders) {
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG,r);
}
如果这个消息没有在delayed设定的时间之内移除,那么将在ams的activitymanager线程中处理该消息,这个消息是在attachApplicationLocked中发出的
具体的在ams:
if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
}
3:通过所有等待的client进程
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}
4:调整oom_adj值
updateOomAdjLocked(r, true);
四大组件的启动都会调整对应的oom_adj值,android有一套lowmenmorykiller机制,实现在驱动层,但是框架层本身也有维护一份oom_adj值,驱动层会根据框架层的值去决定应用的进程优先级
至此,contentprovider组件的启动流程基本讲完
值得注意的是contentprovider的启动时机还是比较早的
Application,activity,contentprovider的启动顺序是
Application创建-->contentprovider创建—>contentprovider::oncreate-->Application::oncreate--->Activity创建--->Activity::oncreate
具体的可以参考这段代码
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);
}
}
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
throw new RuntimeException(
"Exception thrown in onCreate() of "
+ data.instrumentationName + ": " + e.toString(), e);
}
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
```
网友评论