从App启动理解ContentProvider的建立

ActivityThread.main

咱们知道app的启动是从ActivityThread.main方法开始的,因此咱们先从main看起java

public static void main(String[] args) {
     ...
    //建立Looper
    Looper.prepareMainLooper();
    //建立ActivityThread
    ActivityThread thread = new ActivityThread();
    thread.attach(false);

   if (sMainThreadHandler == null) {
          sMainThreadHandler = thread.getHandler();
     }
    ...
    //开启Looper循环
    Looper.loop();
    ...
    }
复制代码

main方法里主要作了三件事android

  • 建立主线程Looper,并开启循环
  • 建立ActivityThread
  • 调用attach方法

ActivityThread.attach

接下来咱们看ActivityThread.attach方法bash

private void attach(boolean system) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        ...
        final IActivityManager mgr = ActivityManager.getService();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            ...
        }
        ...
    }
    ...
}
复制代码

attach方法里主要作里就是调用ActivityManager.getService() 方法返回IActivityManager 类型的 Binder 对象, 具体实现是在AMS里实现attachApplicationapp

ActivityManagerService.attachApplication

public final void attachApplication(IApplicationThread thread) {
    ...
    attachApplicationLocked(thread, callingPid);
    ...
}

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);
    ...
    if (normalMode) {
        try {
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            ...
        }
    }
    ...
}
复制代码

能够发现attachApplication实际调用了attachApplicationLocked,而在attachApplicationLocked里又经过IApplicationThread (其类型是ApplicationThreadActivityThread的内部类,继承自IApplicationThread.Stub) 的bindApplication方法async

ActivityThread.bindApplication

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) {
    ...
    sendMessage(H.BIND_APPLICATION, data);
}
复制代码
private void sendMessage(int what, Object obj) {
    sendMessage(what, obj, 0, 0, false);
}
复制代码
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);
}
复制代码

bindApplication最终调用了mH.sendMessage方法,由于AMS经过ApplicationThread回调到咱们的进程,这也是一次跨进程过程,而ApplicationThread就是一个binder,回调逻辑是在binder线程池中完成的,因此须要经过Handler 将其切换到ui线程.因此这里调用mh.sendMessage(mhActivityThread 的内部类 H 的一个实例)来通知处理BIND_APPLICATION事件ide

H.handleMessage

public void handleMessage(Message msg) {
    ...
    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;
        ...
    }
}
复制代码

能够看到Handler.H收到BIND_APPLICATION事件后实际调用来handleBindApplication方法来完成Application的建立以及ContentProvider的建立oop

ActivityThread.handleBindApplication

private void handleBindApplication(AppBindData data) {
     ....
     final InstrumentationInfo ii;
     ....
     
    if (ii != null) {
       //1.建立ContentImpl
       final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

            try {
                final ClassLoader cl = instrContext.getClassLoader();
                mInstrumentation = (Instrumentation)
                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
            } catch (Exception e) {
                throw new RuntimeException(
                    "Unable to instantiate instrumentation "
                    + data.instrumentationName + ": " + e.toString(), e);
            }

        //2.建立Instrumentation
      final ComponentName component = new ComponentName(ii.packageName, ii.name);
            mInstrumentation.init(this, instrContext, appContext, component,
                    data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
        ....
    
        //3.建立Application对象
         Application app;
         app = data.info.makeApplication(data.restrictedBackupMode, null);

         // Propagate autofill compat state
            app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);

            mInitialApplication = app;

        ...
        //4.启动当前进程中的ContentProvider和调用其onCreate方法

        if (!data.restrictedBackupMode) {
                if (!ArrayUtils.isEmpty(data.providers)) {
                    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);
                }
            }

        //5.调用Application的onCreate方法
        try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                      "Unable to create application " + app.getClass().getName()
                      + ": " + e.toString(), e);
                }
            }
    }
 }
复制代码
  • 3.1 LoadedApk.makeApplication Application的建立
public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
        ...

        Application app = null;

        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }
        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                initializeJavaContextClassLoader();
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            if (!mActivityThread.mInstrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to instantiate application " + appClass
                    + ": " + e.toString(), e);
            }
        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!instrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        }

        ...

        return app;
}
复制代码
  • 3.1.1 Instrumentation.newApplication
public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = getFactory(context.getPackageName())
                .instantiateApplication(cl, className);
        app.attach(context);
        return app;
    }
复制代码

AppComponentFactory.instantiateApplicationui

public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
            @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Application) cl.loadClass(className).newInstance();
    }
复制代码

通过 上面的5个步骤就完成了Application的建立和启动,能够看到在第5步调用ApplicationonCreate方法以前,第4步进行了ContentProvicer的建立和调用其onCreate,这里就解释到了为何能够在ContentProvicer.onCreate里初始化sdk,下面介绍下ContentProvicer的建立和调用其onCreatethis

  • 4.1 ActivityThread.installContentProviders
private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<ContentProviderHolder> results = new ArrayList<>();

        for (ProviderInfo cpi : providers) {
        
            ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }

        try {
            ActivityManager.getService().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
复制代码

installContentProviders完成了ContentProvider的启动,它首先遍历当前进程的ProviderInfo列表并一一调用其installProvder方法来启动它,接着将已启动的ContentProvider发布到AMS上,AMS会把它们存在ProviderMap里,这样外部调用者就能够直接从AMS中获取到ContentProviderspa

  • 4.1.1 ActivityThread.installProvider
private ContentProviderHolder installProvider(Context context,
            ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
        ....

        final java.lang.ClassLoader cl = c.getClassLoader();
        LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
        if (packageInfo == null) {
            packageInfo = getSystemContext().mPackageInfo;
        }
        localProvider = packageInfo.getAppFactory()
                .instantiateProvider(cl, info.name);
        provider = localProvider.getIContentProvider();
        if (provider == null) {
            Slog.e(TAG, "Failed to instantiate class " +
                          info.name + " from sourceDir " +
                          info.applicationInfo.sourceDir);
            return null;
        }

         localProvider.attachInfo(c, info);

        ....
}
复制代码

这里经过类加载器完成了ContentProvider的建立

  • 4.1.1.1 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); } 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(); } } 复制代码

installProvider方法里除了完成了ContentProvider的建立还掉用了attachInfo,在改方法里来调用它的onCreate方法。到此位置ContentProvider的建立已经完成,而且它的onCreate也被调用

相关文章
相关标签/搜索