ContentProvider 启动流程(基于Android 14)

问题背景

  • 面试中经常会提到 Application#onCreate() 在执行前会先执行 ContentProvider#onCreate()
  • 想知道原因,那就不得不去看下这两个启动流程了,总是能发现调用的先后顺序
  • 本文将会梳理 ContentProvider 的启动流程
  • 前置知识:应用进程创建后会先去通知AMS进程创建完毕(AMS#attatch),并且传入ApplicationThread的binder代理对象给到AMS,此时AMS会调用到 ApplicationThread#bindApplication

整个启动时序图

启动时序图

启动过程

  • 第一步:AMS 调用 ApplicationThreadbindApplication(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();
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容