前一篇Android 进阶——Framework 核心四大组件之跨进程共享组件ContentProvider 核心知识总结(一)文章,总结了ContentProvider机制的基本概念及开发中的应用,这一篇文章好好结合源码分析下其背后的机制和原理。如果做过插件化或者热修复,自己去加载四大组件,会发现ContentProvider的加载过程有些特殊…ContentProvider的onCreate方法先于Application的onCreate而执行。
源码基于API 28,源码有删减,只保留本专题相关的核心代码,仅供参考。
ActivityThread 与Thread 没有任何继承关系,源码涉及到核心类有android.app.ActivityThread.ApplicationThread、android.app.ActivityThread.AppBindData、android.content.ContentProvider、android.app.LoadedApk、android.content.pm.ApplicationInfo、com.android.server.am.ActivityManagerService、android.app.ActivityManager。
Android四大组件在APP启动后随时可用,所以从App程序的运行入口开始,即ActivityThread#main方法(一般源码中的带有main方法的类都是作为启动类,由Framework 机制去调用的,比如使用adb 命令、cmd命令等等配置的参数都是传到对应启动类的方法里的)
public static void main(String[] args) {
...
//初始化MainLooper 并以ThreadLocal形式存储
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
// 通过Binder进行IPC通信
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
// 开启Looper消息循环
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在App的入口方法里创建自身ActivityThread对象之后,通过Binder与ActivityManagerService(AMS)进行通信
private void attach(boolean system, long startSeq) {
if (!system) {
...
//Binder通信,获取到的是ActivityManagerService的代理
final IActivityManager mgr = ActivityManager.getService();
try {
//AMS#attachApplication(final ApplicationThread mAppThread = new ApplicationThread();) 通过IPC通信与AMS 通信,即由AMS去接力
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
} else {
...
}
...
ViewRootImpl.addConfigCallback(configChangedCallback);
}
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
通过ActivityThread的attach方法把接力棒交到AMS,由AMS往下执行
@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
...
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
}
}
ActivityManagerService#attachApplicationLocked
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
try {
ApplicationInfo appInfo = app.instr != null ? app.instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
// If we were asked to attach an agent on startup, do so now, before we're binding
// application code.
if (preBindAgent != null) {
thread.attachAgent(preBindAgent);
}
if (app.isolatedEntryPoint != null) {
thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
} else if (app.instr != null) {
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);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
}
...
} catch (Exception e) {
}
return true;
}
又回到了ActivityThread$ActivityApplication#bindApplication方法中
private class ApplicationThread extends IApplicationThread.Stub {
...
public final void scheduleSleeping(IBinder token, boolean sleeping) {
sendMessage(H.SLEEPING, token, sleeping ? 1 : 0);
}
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
sendMessage(H.RECEIVER, r);
}
public final void scheduleCreateBackupAgent(ApplicationInfo app,
CompatibilityInfo compatInfo, int backupMode) {
sendMessage(H.CREATE_BACKUP_AGENT, d);
}
public final void scheduleDestroyBackupAgent(ApplicationInfo app,
CompatibilityInfo compatInfo) {
sendMessage(H.DESTROY_BACKUP_AGENT, d);
}
public final void scheduleCreateService(IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
sendMessage(H.CREATE_SERVICE, s);
}
public final void scheduleBindService(IBinder token, Intent intent,
boolean rebind, int processState) {
sendMessage(H.BIND_SERVICE, s);
}
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, boolean autofillCompatibilityEnabled) {
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
...
sendMessage(H.BIND_APPLICATION, data);
}
public void processInBackground() {
mH.removeMessages(H.GC_WHEN_IDLE);
mH.sendMessage(mH.obtainMessage(H.GC_WHEN_IDLE));
}
@Override
public void scheduleLowMemory() {
sendMessage(H.LOW_MEMORY, null);
}
}
在bindApplication中初始化AppBindData数据之后通过ActivityThread$H#sendMessage(H.BIND_APPLICATION, data)通过Handler机制把数据传递(msg.obj)出去,
在H中进行处理调用ActivityThread#handleBindApplication方法完成四件事:
经过以上四部曲之后,ContentProvider所在进程及ContentProvider皆已成功启动了。
private void handleBindApplication(AppBindData data) {
final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
final InstrumentationInfo ii;
if (data.instrumentationName != null) {
try {
ii = new ApplicationPackageManager(null, getPackageManager())
.getInstrumentationInfo(data.instrumentationName, 0);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
"Unable to find instrumentation info for: " + data.instrumentationName);
}
mInstrumentationPackageName = ii.packageName;
mInstrumentationAppDir = ii.sourceDir;
} else {
ii = null;
}
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
// Continue loading instrumentation.
if (ii != null) {
ApplicationInfo instrApp;
try {
instrApp = getPackageManager().getApplicationInfo(ii.packageName, 0,
UserHandle.myUserId());
} catch (RemoteException e) {
instrApp = null;
}
if (instrApp == null) {
instrApp = new ApplicationInfo();
}
ii.copyTo(instrApp);
instrApp.initForUser(UserHandle.myUserId());
//APK的内存表现形式
final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true, false);
// 创建初始化Context 上下文对象
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
final ClassLoader cl = instrContext.getClassLoader();
//反射创建Instrumentation
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
}
final ComponentName component = new ComponentName(ii.packageName, ii.name);
//初始化Instrumentation
mInstrumentation.init(this, instrContext, appContext, component,
data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
} else {
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
}
// Allow disk access during application and provider setup. This could
// block processing ordered broadcasts, but later processing would
// probably end up doing the same disk access.
Application app;
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);
// Propagate autofill compat state
app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
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)) {
//创建启动当前进程的ContentProvider 并主动调用自己的onCreate方法
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) {
}
try {
// 触发Application 的onCreate方法
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
}
}
// Preload fonts resources
FontsContract.setApplicationContextForResources(appContext);
}
通过data.info.makeApplication(data.restrictedBackupMode, null)方法把创建Application的接力棒交到了LoaderApk中
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
String appClass = mApplicationInfo.className;
try {
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals("android")) {
initializeJavaContextClassLoader();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
//创建Application 对象
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
if (!mActivityThread.mInstrumentation.onException(app, e)) {
}
}
mActivityThread.mAllApplications.add(app);
mApplication = app;
//第一次创建时instrumentation 为null 不执行,
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
}
}
// Rewrite the R 'constants' for all library apks.
SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();
return app;
}
因为第一次创建时instrumentation 为null 所以instrumentation 没有调用callApplicationOnCreate方法即Application的onCreate方法没有被触发,
接着调用链回到android.app.ActivityThread#installContentProviders方法,首先遍历当前进程的ProviderInfo列表并一一调用installProvider方法来启动,最后将已经运行的ContentProvider 注册到AMS中(AMS 存储到ProviderMap),这样其他进程使用时就可以通过Binder 与AMS获取对应的ContentProvider。
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
for (ProviderInfo cpi : providers) {
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
}
try {
//又回到AMS
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
android.app.ActivityThread#installProvider,通过类加载器
private ContentProviderHolder installProvider(Context context,
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();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
if (packageInfo == null) {
// System startup case.
packageInfo = getSystemContext().mPackageInfo;
}
localProvider = packageInfo.getAppFactory()
.instantiateProvider(cl, info.name);
//本质是通过android.app.AppComponentFactory#instantiateProvider 反射创建ContentProvider对象
provider = localProvider.getIContentProvider();
if (provider == null) {
return null;
}
// XXX Need to create the correct context for this provider.
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
}
} else {
provider = holder.provider;
}
return retHolder;
}
接力棒交到android.content.ContentProvider#attachInfo
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);
}
//ContentProvider自身执行自己的onCreate方法
ContentProvider.this.onCreate();
}
}
然后调用链再次回到handleBindApplication 方法中
mInstrumentation.callApplicationOnCreate(app) 被执行Application#onCreate方法被触发。
简而言之,ContentProvider是在ActivityThread#handleBindApplication方法里被创建并由自身对象去主动调用自己的onCreate方法的;而Application虽然是由LoadedApk先于ContentProvider创建,但是它的onCreate方法是由Instrumentation 去触发的,而初次创建时Instrumentation为null,未完待续…