美文网首页
Applicaiton启动流程分析

Applicaiton启动流程分析

作者: 孔鹏飞 | 来源:发表于2020-08-22 00:09 被阅读0次

    本文基于API 28 Android 9.0的代码

    性能优化的一个主要部分就是优化Application的启动时间,因此了解熟悉Application的启动流程很有必要,我们从程序的入口ActivityThread.java的main函数开始分析:

      public static void main(String[] args) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    
            // CloseGuard defaults to true and can be quite spammy.  We
            // disable it here, but selectively enable it later (via
            // StrictMode) on debug builds, but using DropBox, not logs.
            CloseGuard.setEnabled(false);
    
            Environment.initForCurrentUser();
    
            // Set the reporter for event logging in libcore
            EventLogger.setReporter(new EventLoggingReporter());
    
            // Make sure TrustedCertificateStore looks in the right place for CA certificates
            final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
            TrustedCertificateStore.setDefaultUserDirectory(configDir);
    
            Process.setArgV0("<pre-initialized>");
    
            Looper.prepareMainLooper();
    
            // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
            // It will be in the format "seq=114"
            long startSeq = 0;
            if (args != null) {
                for (int i = args.length - 1; i >= 0; --i) {
                    if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                        startSeq = Long.parseLong(
                                args[i].substring(PROC_START_SEQ_IDENT.length()));
                    }
                }
            }
            ActivityThread thread = new ActivityThread();
            thread.attach(false, startSeq);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
            if (false) {
                Looper.myLooper().setMessageLogging(new
                        LogPrinter(Log.DEBUG, "ActivityThread"));
            }
    
            // End of event ActivityThreadMain.
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            Looper.loop();
    
            throw new RuntimeException("Main thread loop unexpectedly exited");
        }
    

    在main函数里,创建了主线程的Looper并开启loop循环,还有一句重要的代码:

    thread.attach(false, startSeq);
    

    打开这个方法的定义看一下:

     private void attach(boolean system, long startSeq) {
            sCurrentActivityThread = this;
            mSystemThread = system;
            if (!system) {
                ViewRootImpl.addFirstDrawHandler(new Runnable() {
                    @Override
                    public void run() {
                        ensureJitEnabled();
                    }
                });
                android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                        UserHandle.myUserId());
                RuntimeInit.setApplicationObject(mAppThread.asBinder());
                final IActivityManager mgr = ActivityManager.getService();
                try {
                    mgr.attachApplication(mAppThread, startSeq);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
                // Watch for getting close to heap limit.
               ......
    }
    

    重点关注mgr.attachApplication(mAppThread, startSeq);这句代码,这里的mAppThread为ApplicationThread,ApplicationThread是ActivityThread的内部类,,它继承自IApplicationThread.Stub,此对象是ActivityThread 与 ActivityManagerService连接的桥梁。

      private class ApplicationThread extends IApplicationThread.Stub {
        ......
    
      }
    

    mgr为ActivityManagerService,即AMS,它是Android中最核心的服务之一,主要负责系统中四大组件的启动,切换,调度及应用进程的管理和调度工作。

        @Override
        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);
            }
        }
    

    attachApplication方法调用了attachApplicationLocked方法:

        @GuardedBy("this")
        private final boolean attachApplicationLocked(IApplicationThread thread,
                int pid, int callingUid, long startSeq) {
                ......
                checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
                mStackSupervisor.getActivityMetricsLogger().notifyBindApplication(app);
                if (app.isolatedEntryPoint != null) {
                    // This is an isolated process which should just call an entry point instead of
                    // being bound to an application.
                    thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
                } else if (app.instr != null) {
                    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, isAutofillCompatEnabled);
                } else {
                    thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                            null, null, null, testMode,
                            mBinderTransactionTrackingEnabled, enableTrackAllocation,
                            isRestrictedBackupMode || !normalMode, app.persistent,
                            new Configuration(getGlobalConfiguration()), app.compat,
                            getCommonServicesLocked(app.isolated),
                            mCoreSettingsObserver.getCoreSettingsLocked(),
                            buildSerial, isAutofillCompatEnabled);
                }
                if (profilerInfo != null) {
                    profilerInfo.closeFd();
                    profilerInfo = null;
                }
                checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
                updateLruProcessLocked(app, false, null);
                checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
                app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
            } catch (Exception e) {
                // todo: Yikes!  What should we do?  For now we will try to
                // start another process, but that could easily get us in
                // an infinite loop of restarting processes...
                Slog.wtf(TAG, "Exception thrown during bind of " + app, e);
    
                app.resetPackageList(mProcessStats);
                app.unlinkDeathRecipient();
                startProcessLocked(app, "bind fail", processName);
                return false;
            }
            ......
            return true;
        }
    

    attachApplicationLocked方法中调用了ApplicationThread的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, boolean autofillCompatibilityEnabled) {
    
                if (services != null) {
                    if (false) {
                        // Test code to make sure the app could see the passed-in services.
                        for (Object oname : services.keySet()) {
                            if (services.get(oname) == null) {
                                continue; // AM just passed in a null service.
                            }
                            String name = (String) oname;
    
                            // See b/79378449 about the following exemption.
                            switch (name) {
                                case "package":
                                case Context.WINDOW_SERVICE:
                                    continue;
                            }
    
                            if (ServiceManager.getService(name) == null) {
                                Log.wtf(TAG, "Service " + name + " should be accessible by this app");
                            }
                        }
                    }
    
                    // Setup the service cache in the ServiceManager
                    ServiceManager.initServiceCache(services);
                }
    
                setCoreSettings(coreSettings);
    
                AppBindData data = new AppBindData();
                data.processName = processName;
                data.appInfo = appInfo;
                data.providers = providers;
                data.instrumentationName = instrumentationName;
                data.instrumentationArgs = instrumentationArgs;
                data.instrumentationWatcher = instrumentationWatcher;
                data.instrumentationUiAutomationConnection = instrumentationUiConnection;
                data.debugMode = debugMode;
                data.enableBinderTracking = enableBinderTracking;
                data.trackAllocation = trackAllocation;
                data.restrictedBackupMode = isRestrictedBackupMode;
                data.persistent = persistent;
                data.config = config;
                data.compatInfo = compatInfo;
                data.initProfilerInfo = profilerInfo;
                data.buildSerial = buildSerial;
                data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
                sendMessage(H.BIND_APPLICATION, data);
            }
    

    这里将组装信息到AppBindData对象里,然后发送H.BIND_APPLICATION消息到ActivityThread中并被mH这个Handler处理:

     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;
                 ......
            }
        }
    

    方法中调用了handleBindApplicaiton方法:

     private void handleBindApplication(AppBindData data) {
            ......
    
            data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
       
            ......
    
            final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
            updateLocaleListFromAppContext(appContext,
                    mResourcesManager.getConfiguration().getLocales());
    
            if (!Process.isIsolated()) {
                final int oldMask = StrictMode.allowThreadDiskWritesMask();
                try {
                    setupGraphicsSupport(appContext);
                } finally {
                    StrictMode.setThreadPolicyMask(oldMask);
                }
            } else {
                ThreadedRenderer.setIsolatedProcess(true);
            }
    
            // If we use profiles, setup the dex reporter to notify package manager
            // of any relevant dex loads. The idle maintenance job will use the information
            // reported to optimize the loaded dex files.
            // Note that we only need one global reporter per app.
            // Make sure we do this before calling onCreate so that we can capture the
            // complete application startup.
            if (SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false)) {
                BaseDexClassLoader.setReporter(DexLoadReporter.getInstance());
            }
    
            // Install the Network Security Config Provider. This must happen before the application
            // code is loaded to prevent issues with instances of TLS objects being created before
            // the provider is installed.
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "NetworkSecurityConfigProvider.install");
            NetworkSecurityConfigProvider.install(appContext);
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    
            // Continue loading instrumentation.
            if (ii != null) {
                ApplicationInfo instrApp;
                try {
                    instrApp = getPackageManager().getApplicationInfo(ii.packageName, 0,
                            UserHandle.myUserId());
                } catch (RemoteException e) {
                    instrApp = null;
                }
                if (instrApp == null) {
                    instrApp = new ApplicationInfo();
                }
                ii.copyTo(instrApp);
                instrApp.initForUser(UserHandle.myUserId());
                final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                        appContext.getClassLoader(), false, true, false);
                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);
                }
    
                final ComponentName component = new ComponentName(ii.packageName, ii.name);
                mInstrumentation.init(this, instrContext, appContext, component,
                        data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
    
                if (mProfiler.profileFile != null && !ii.handleProfiling
                        && mProfiler.profileFd == null) {
                    mProfiler.handlingProfiling = true;
                    final File file = new File(mProfiler.profileFile);
                    file.getParentFile().mkdirs();
                    Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
                }
            } else {
                mInstrumentation = new Instrumentation();
                mInstrumentation.basicInit(this);
            }
    
            if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
                dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
            } else {
                // Small heap, clamp to the current growth limit and let the heap release
                // pages after the growth limit to the non growth limit capacity. b/18387825
                dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
            }
    
            // 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;
            final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
            final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
            try {
                // If the app is being launched for full backup or restore, bring it up in
                // a restricted environment with the base application class.
                app = data.info.makeApplication(data.restrictedBackupMode, null);
    
                // Propagate autofill compat state
                app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
    
                mInitialApplication = app;
    
                // 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)) {
                        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);
                    }
                }
    
                // Do this after providers, since instrumentation tests generally start their
                // test thread at this point, and we don't want that racing.
                try {
                    mInstrumentation.onCreate(data.instrumentationArgs);
                }
                catch (Exception e) {
                    throw new RuntimeException(
                        "Exception thrown in onCreate() of "
                        + data.instrumentationName + ": " + e.toString(), e);
                }
                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);
                    }
                }
            } finally {
                // If the app targets < O-MR1, or doesn't change the thread policy
                // during startup, clobber the policy to maintain behavior of b/36951662
                if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
                        || StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
                    StrictMode.setThreadPolicy(savedPolicy);
                }
            }
    
    

    data.info为LoadedApk对象,调用makeApplication方法生成了Application对象

     public Application makeApplication(boolean forceDefaultAppClass,
                Instrumentation instrumentation) {
            if (mApplication != null) {
                return mApplication;
            }
    
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");
    
            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")) {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                            "initializeJavaContextClassLoader");
                    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)) {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    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)) {
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        throw new RuntimeException(
                            "Unable to create application " + app.getClass().getName()
                            + ": " + e.toString(), e);
                    }
                }
            }
    
            // Rewrite the R 'constants' for all library apks.
            SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();
            final int N = packageIdentifiers.size();
            for (int i = 0; i < N; i++) {
                final int id = packageIdentifiers.keyAt(i);
                if (id == 0x01 || id == 0x7f) {
                    continue;
                }
    
                rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
            }
    
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    
            return app;
        }
    

    这里mInstrumentation为Instrumentation对象,通过newApplication方法生成了Application:

      app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
    
      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;
        }
    

    Application又调用了attach方法,对Context的变量mBase进行了赋值操作:

    final void attach(Context context) {
            attachBaseContext(context);
            mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
        }
    
      protected void attachBaseContext(Context base) {
            if (mBase != null) {
                throw new IllegalStateException("Base context already set");
            }
            mBase = base;
        }
    

    然后在makeApplication方法里又调用了Application的onCreate方法:

    instrumentation.callApplicationOnCreate(app);
    
    public void callApplicationOnCreate(Application app) {
            app.onCreate();
        }
    

    至此,Application的启动流程分析完毕

    相关文章

      网友评论

          本文标题:Applicaiton启动流程分析

          本文链接:https://www.haomeiwen.com/subject/ifkmjktx.html