An overview of the

When an App is started, it goes through the following steps

  • The first step is to click on the App iconLauncherProcess, throughActivityManagerServiceBinder IPC form tosystem_serverThe process bystartActivityThe request of
  • system_serverAfter receiving the request, the process passesProcess.startMethods tozygoteA process sends a request to create a process
  • zygoteprocessforkProduces a new child process, i.eAppprocess
  • Then enter theActivityThread.mainMethod, which runs in theAppIn process, passActivityManagerServiceBinder IPC form tosystem_serverThe process byattachApplicationrequest
  • system_serverAfter receiving the request, perform a series of preparatory work before submitting the request through Binder IPCAppThe process to sendscheduleLaunchActivityrequest
  • AppprocessBinder Threads (ApplicationThreads)After receiving the request, passHandlerSend to the main threadLAUNCH_ACTIVITYThe message
  • After the main thread receives the Message, it creates the target through reflectionActivityAnd the callbackActivitytheonCreate

The start of our ContentProvider is in the fourth step of attachApplication. Here we look at the source code

ActivityManagerService.java

 public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final longorigId = Binder.clearCallingIdentity(); attachApplicationLocked(thread, callingPid, callingUid, startSeq); Binder.restoreCallingIdentity(origId); }}Copy the code
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);
}
Copy the code

The bindApplication method of thread is called. Thread is of type IApplicationThread, a binder used for cross-process communication, and the implementation class is the inner class ApplicationThread of ActivityThread

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); }Copy the code

This method actually ends up sending a BIND_APPLICATION message to the inner class H of ActivityThread

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;
Copy the code

This method calls the handleBindApplication method

private void handleBindApplication(AppBindData data) {...finalInstrumentationInfo ii; .// Create the mInstrumentation instance
    if(ii ! =null) {.../ / create ContextImpl
        final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

        try {
            // Create the mInstrumentation instance
            final ClassLoader cl = instrContext.getClassLoader();
            mInstrumentation = (Instrumentation)
                cl.loadClass(data.instrumentationName.getClassName()).newInstance();
        } catch(Exception e) { ... }... }else {
        mInstrumentation = newInstrumentation(); }... Application app; .try{...// Create Application instance
        app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;
         if(! data.restrictedBackupMode) {if(! ArrayUtils.isEmpty(data.providers)) {/ / start the ContentProvider
                    installContentProviders(app, data.providers);
                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000); }}try {
            // Call Application onCreate
            mInstrumentation.callApplicationOnCreate(app);
        } catch(Exception e) { ... }}finally{... }... }Copy the code

Let’s analyze the method from the top down

  • I first createdContextImplobject
  • And then createmInstrumentationobject
  • And then I createApplicationobject
  • And then it startsContentProvider
  • And then finally calledApplicationThe object’sonCreate

We found that the ContentProvider is already started before calling onCreate of the Application. This can also be used as part of the startup optimization. If the ContentProvider is not needed, we recommend removing it because it will automatically start. I tested it with TraceView before, and it takes about 5ms, but no matter how small the mosquito is, it is still meat

Let’s move on to the installContentProviders method

 private void installContentProviders( Context context, List
       
         providers)
        {
        final ArrayList<ContentProviderHolder> results = new ArrayList<>();
        / / comment 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());
            }
            / / comment 2
            ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/.true /*noReleaseNeeded*/.true /*stable*/);
            if(cph ! =null) {
                cph.noReleaseNeeded = true; results.add(cph); }}try {
            / / comment 3
            ActivityManager.getService().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
            throwex.rethrowFromSystemServer(); }}Copy the code
  • At comment 1, iterate over the current application’sProviderInfoList, get eachContentProvidertheProviderInfo(storageContentProviderThe information)
  • At comment 2, callinstallProviderTo start theContentProvider
  • throughAMSthepublishContentProvidersMethod, take theseContentProviderStore toAMSthemProviderMap, play the role of cache, to prevent repeated calls

Let’s move on to the installProvider method

 private ContentProviderHolder installProvider(Context context,
            ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {.../ / comment 1
                final java.lang.ClassLoader cl = c.getClassLoader();
                LoadedApk packageInfo = peekPackageInfo(ai.packageName, true); localProvider = cl.loadClass(className).newInstance(); provider = localProvider.getIContentProvider(); .../ / comment 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); }}Copy the code
  • At comment 1, create by reflectionContentProvider
  • At comment 2, it is calledContentProvidertheattachInfomethods
 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(); }}Copy the code

This method calls onCreate of the ContentProvider, where the startup of the ContentProvider is complete

Reference: Advanced Android Decryption