概述
ContentProvider的启动其实是在App启动时就自动启动的,还不知道APP启动流程的,推荐看一下Android App启动过程,我们知道当一个App启动时,经历了以下步骤
- 首先是点击App图标,此时是运行在
Launcher进程,通过ActivityManagerServiceBinder IPC的形式向system_server进程发起startActivity的请求 system_server进程接收到请求后,通过Process.start方法向zygote进程发送创建进程的请求zygote进程fork出新的子进程,即App进程- 然后进入
ActivityThread.main方法中,这时运行在App进程中,通过ActivityManagerServiceBinder IPC的形式向system_server进程发起attachApplication请求 system_server接收到请求后,进行一些列准备工作后,再通过Binder IPC向App进程发送scheduleLaunchActivity请求App进程binder线程(ApplicationThread)收到请求后,通过Handler向主线程发送LAUNCH_ACTIVITY消息- 主线程收到Message后,通过反射机制创建目标
Activity,并回调Activity的onCreate
而我们的ContentProvider的启动是在第四步的attachApplication中请求的开始的,下面我们就具体看源码分析
ActivityManagerService.java
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);
}
}
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
....
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);
}
这里调用了thread的bindApplication方法,thread的类型是IApplicationThread,是一个binder用于跨进程通信,实现类是ActivityThread的内部类ApplicationThread类
ApplicationThread.java
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) {
...
sendMessage(H.BIND_APPLICATION, data);
}
这个方法其实最后发送了一个BIND_APPLICATION消息给ActivityThread的内部类H
ActivityThread.java
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
这个方法调用了handleBindApplication方法
private void handleBindApplication(AppBindData data) {
...
final InstrumentationInfo ii;
...
// 创建 mInstrumentation 实例
if (ii != null) {
...
//创建ContextImpl
final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
try {
//创建mInstrumentation实例
final ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
} catch (Exception e) {
...
}
...
} else {
mInstrumentation = new Instrumentation();
}
...
Application app;
...
try {
...
// 创建 Application 实例
app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
//启动ContentProvider
installContentProviders(app, data.providers);
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
try {
//调用Application的onCreate
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...
}
} finally {
...
}
...
}
我们从上向下分析这个方法
- 首先创建了
ContextImpl对象 - 然后创建了
mInstrumentation对象 - 接着创建了
Application对象 - 然后启动了
ContentProvider - 最后调用了
Application对象的onCreate
我们发现其实在调用Application的onCreate之前,就已经启动了ContentProvider,这个也可以作为启动优化的一部分,如果不需要ContentProvider的话建议删除,因为他会自动启动,之前我用TraceView测试过,大概占用5ms,但是蚊子再小也是肉啊
我们继续分析installContentProviders方法
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
//注释1
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());
}
//注释2
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
//注释3
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
- 注释1处,遍历当前应用程序的
ProviderInfo列表,得到每个ContentProvider的ProviderInfo(存储ContentProvider的信息) - 注释2处,调用
installProvider来启动ContentProvider - 通过
AMS的publishContentProviders方法,将这些ContentProvider储存到AMS的mProviderMap中,起到缓存作用,防止重复调用
我们继续分析installProvider方法
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
···
//注释1
final java.lang.ClassLoader cl = c.getClassLoader();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
localProvider = cl.loadClass(className).newInstance();
provider = localProvider.getIContentProvider();
···
//注释2
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);
}
}
- 注释1处,通过反射来创建
ContentProvider - 注释2处,调用了
ContentProvider的attachInfo方法
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;
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();
}
}
在这个方法中调用了ContentProvider的onCreate,到这里ContentProvider的启动就完成了
参考:《Android进阶解密》