问题背景
- 面试中经常会提到
Application#onCreate()
在执行前会先执行 ContentProvider#onCreate()
- 想知道原因,那就不得不去看下这两个启动流程了,总是能发现调用的先后顺序
- 本文将会梳理
ContentProvider
的启动流程
- 前置知识:应用进程创建后会先去通知AMS进程创建完毕(
AMS#attatch
),并且传入ApplicationThread
的binder代理对象给到AMS,此时AMS会调用到 ApplicationThread#bindApplication
整个启动时序图
启动过程
-
第一步:AMS 调用 ApplicationThread
的 bindApplication
(SystemServer进程向应用进程发起binder通信)
private class ApplicationThread extends IApplicationThread.Stub {
....
public final void bindApplication(...) {
....
sendMessage(H.BIND_APPLICATION, data);
}
....
}
-
第二步:接着调用到 ActivityThread#sendMessage(BIND_APPLICATION)
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
if (DEBUG_MESSAGES) {
Slog.v(TAG,
"SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj);
}
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
-
第三步:进而转到 大H(extends Handler)
,走handler切换到主线程
class H extends Handler {
public static final int BIND_APPLICATION = 110;
...
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;
....
}
...
}
}
-
第四步:ActivityThread#handleBindApplication
@UnsupportedAppUsage
private void handleBindApplication(AppBindData data) {
....
// 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.
// 注释1,创建application
app = data.info.makeApplication(data.restrictedBackupMode, null);
...
// 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)) {
// 注释2,初始化provider#oncreate
installContentProviders(app, data.providers);
}
}
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
try {
// 注释3,通过Instrumentation进而调用到application#create
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
}
....
}
- 注释1,创建
application
- 注释2,初始化
provider#oncreate
private ContentProviderHolder installProvider(...) {
...
// XXX Need to create the correct context for this provider.
localProvider.attachInfo(c, info);
...
}
- 注释3,通过
Instrumentation
进而调用到application#create
-
第五步:主要看下 ContentProvider#oncreate
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
mNoPerms = testing;
mCallingPackage = new ThreadLocal<>();
/*
* 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 != 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();
}
}