概述
ContentProvider的启动其实是在App启动时就自动启动的,还不知道APP启动流程的,推荐看一下Android App启动过程,我们知道当一个App启动时,经历了以下步骤
- 首先是点击App图标,此时是运行在
Launcher
进程,通过ActivityManagerService
Binder IPC的形式向system_server
进程发起startActivity
的请求 system_server
进程接收到请求后,通过Process.start
方法向zygote
进程发送创建进程的请求zygote
进程fork
出新的子进程,即App
进程- 然后进入
ActivityThread.main
方法中,这时运行在App
进程中,通过ActivityManagerService
Binder 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进阶解密》