Activity啓動流程總結-ActivityThread

前言

對於Activity的啓動流程,從事Android開發的同學都很熟悉。這裏僅結合自己的理解,通過博文梳理和記錄Activity啓動流程關鍵節點,便於記憶和將來回顧。

在Activity啓動流程中,當要啓動的Activity所在進程未創建時,ActivityManagerService會通過socket通信請求Zygote進程fork一個子進程作爲APP進程。APP進程啓動後會執行ActivityThread的main入口函數做一系列的初始化操作,之後和ActivityManagerService交互響應的方法也是在這個ActivityThread類中。

源碼探究

文中源碼基於Android 9.0

入口函數main

[ActivityThread.java]

public static void main(String[] args) {
    // 省略性能、調試設置部分
    // ···

    // 設置當前進程名稱
    Process.setArgV0("<pre-initialized>");

    // 在當前線程初始化Looper,並將其作爲主線程Looper。
    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"
    // 獲取啓動序列號。ActivityManagerService會爲待啓動的進程生成一個唯一標識,以該
    // 標識爲key,保存該進程對應的ProcessRecord(ProcessRecord儲存進程完整信息)。
    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
    ActivityThread thread = new ActivityThread();
    // 初始化以及通知ActivityManagerService
    thread.attach(false, startSeq);

    if (sMainThreadHandler == null) {
        // 保存主線程Handler
        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無限循環,監聽主線程消息任務
    Looper.loop();

    // 若執行到這裏,意味着主線程Looper退出,主線程將運行退出
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

ActivityThread.main作爲APP進程入口,在該方法中創建了Looper並開啓循環,因此將其視爲APP主線程,一直運行保持不退出,監聽主線程消息隊列中的消息。main方法中同時實例化ActivityThread自身,調用自身的attach方法,執行後續的初始化操作和通知(AMS)ActivityManagerService進程創建完成。

attach

[ActivityThread.java]

private void attach(boolean system, long startSeq) {
    sCurrentActivityThread = this;
    mSystemThread = system;
    if (!system) {
        // 省略JIT檢查部分
        // ···
        
        android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                UserHandle.myUserId());
        // mAppThread爲IApplicationThread,在ActivityThread實例化時創建
        RuntimeInit.setApplicationObject(mAppThread.asBinder());
        // 從ActivityManager的單例成員IActivityManagerSingleton獲取IActivityManager
        // 通信接口(ServiceManager.getService(Context.ACTIVITY_SERVICE))
        final IActivityManager mgr = ActivityManager.getService();
        try {
            // 通過IActivityManager binder通信接口通知到AMS,最終調用到AMS的attachApplication方法。
            // 這裏將IApplicationThread和啓動序列號傳給AMS,用於AMS向APP進程通信和AMS匹配啓動的ProcessRecord。
            mgr.attachApplication(mAppThread, startSeq);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
        // Watch for getting close to heap limit.
        // 省略堆內存監聽處理部分
        // ···
    } else {
        // 省略system process啓動相關
        // ···
    }

    // add dropbox logging to libcore
    DropBox.setReporter(new DropBoxReporter());

    ViewRootImpl.ConfigChangedCallback configChangedCallback
            = (Configuration globalConfig) -> {
        synchronized (mResourcesManager) {
            // We need to apply this change to the resources immediately, because upon returning
            // the view hierarchy will be informed about it.
            
            // 省略影響resource的設備配置信息改變監聽以及發送
            // CONFIGURATION_CHANGED消息相關部分
            // ···
        }
    };
    ViewRootImpl.addConfigCallback(configChangedCallback);
}

attach方法中最重要的一步是執行mgr.attachApplication通知ActivityManagerService APP進程創建,並傳遞IApplicationThread和startSeq。

attachApplication

接下來變從APP進程調用到了SystemServer進程中的ActivityManagerService,進入ActivityManagerService的attachApplication方法:

[ActivityManagerService.java]

@Override
public final void attachApplication(IApplicationThread thread, long startSeq) {
    synchronized (this) {
        // 獲取binder調用端的pid、uid
        int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        // 修改binder調用端的pid、uid爲當前進程的pid、uid,並返回原uid和pid的組合
        final long origId = Binder.clearCallingIdentity();
        // AMS對APP進程進行檢查、設置、執行後續任務等操作
        attachApplicationLocked(thread, callingPid, callingUid, startSeq);
        // 恢復pid、uid
        Binder.restoreCallingIdentity(origId);
    }
}

進入attachApplicationLocked方法:

1. 查找ProcessRecord

ProcessRecord用於記錄運行的進程的完整信息,正常情況下一個ProcessRecord對應一個進程。

[ActivityManagerService.java]

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    // Find the application record that is being attached...  either via
    // the pid if we are running in multiple processes, or just pull the
    // next app record if we are emulating process with anonymous threads.
    ProcessRecord app;
    long startTime = SystemClock.uptimeMillis();
    // 當前調用端的進程非SystemServer進程
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            // 根據pid獲取緩存的ProcessRecord,mPidsSelfLocked中緩存了在運行的進程對應的ProcessRecord。
            app = mPidsSelfLocked.get(pid);
        }
    } else {
        app = null;
    }

    // It's possible that process called attachApplication before we got a chance to
    // update the internal state.
    if (app == null && startSeq > 0) {
        // 根據啓動序列號從待啓動集合中取出ProcessRecord,AMS在通知zygote創建應用進程前,
        // 會先生成啓動序列號和ProcessRecord,並保存在mPendingStarts中。
        final ProcessRecord pending = mPendingStarts.get(startSeq);
        // 對pending進行檢查
        if (pending != null && pending.startUid == callingUid
                && handleProcessStartedLocked(pending, pid, pending.usingWrapper,
                        startSeq, true)) {
            app = pending;
        }
    }

    // 若沒有找到有效的ProcessRecord,則視爲應用進程啓動失敗
    if (app == null) {
        Slog.w(TAG, "No pending application record for pid " + pid
                + " (IApplicationThread " + thread + "); dropping process");
        EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
        if (pid > 0 && pid != MY_PID) {
            // 殺死應用進程
            killProcessQuiet(pid);
            //TODO: killProcessGroup(app.info.uid, pid);
        } else {
            try {
                // 觸發ActivityThread.scheduleExit方法,終止主線程
                thread.scheduleExit();
            } catch (Exception e) {
                // Ignore exceptions.
            }
        }
        return false;
    }
    
    // 省略 ···
}

attachApplicationLocked方法中首先從緩存集合中取出在啓動進程前保存的ProcessRecord,當ProcessRecord有效的情況下,才認爲應用進程啓動成功。

其中handleProcessStartedLocked方法對ProcessRecord進行檢查:
[ActivityManagerService.java]

private boolean handleProcessStartedLocked(ProcessRecord app, int pid, boolean usingWrapper,
        long expectedStartSeq, boolean procAttached) {
    // 從待啓動集合中移除對應ProcessRecord
    mPendingStarts.remove(expectedStartSeq);
    // isProcStartValidLocked方法中會檢查是否有am指令殺死該進程、存在之前的ProcessRecord
    // 和當前的不一致、該ProcessRecord未被標記待啓動、ProcessRecord保存的啓動序列號不匹配。
    // 若檢查不過,將返回對應的原因。
    final String reason = isProcStartValidLocked(app, expectedStartSeq);
    if (reason != null) {
        Slog.w(TAG_PROCESSES, app + " start not valid, killing pid=" + pid
                + ", " + reason);
        app.pendingStart = false;
        // 殺死進程組
        Process.killProcessQuiet(pid);
        Process.killProcessGroup(app.uid, app.pid);
        return false;
    }
    // BatteryStatsService埋點統計
    mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
    checkTime(app.startTime, "startProcess: done updating battery stats");

    // 省略系統日誌和監視相關部分
    // ···
    // 省略髒ProcessRecord緩存的清理部分
    // ···
    
    synchronized (mPidsSelfLocked) {
        // 將ProcessRecord保存進mPidsSelfLocked緩存集合中
        this.mPidsSelfLocked.put(pid, app);
        
        // 省略超時監聽消息相關部分
        // ····
    }
    checkTime(app.startTime, "startProcess: done updating pids map");
    return true;
}

handleProcessStartedLocked方法中對ProcessRecord進行檢查,檢查通過後會保存進mPidsSelfLocked緩存,以便後續可以通過pid獲取。

回到ActivityManagerService.attachApplicationLocked方法中,在獲取到ProcessRecord後繼續往下執行。

2. APP進程死亡監聽

[ActivityManagerService.java]

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    // 省略 ···
    
    // If this application record is still attached to a previous
    // process, clean it up now.
    // 若此時ProcessRecord中持有IApplicationThread,意味着還保留着舊的應用進程的信息,
    // 需要清理和嘗試關閉應用進程組件。
    if (app.thread != null) {
        handleAppDiedLocked(app, true, true);
    }

    // Tell the process all about itself.

    if (DEBUG_ALL) Slog.v(
            TAG, "Binding process pid " + pid + " to record " + app);

    final String processName = app.processName;
    try {
        // 創建死亡訃告回調
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        // 設置監聽應用進程死亡通知
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        // 設置死亡監聽期間發送異常,重新執行startProcessLocked
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }
    
    // 省略 ···
}

ActivityManagerService中依賴Binder死亡監聽機制,監聽應用進程是否死亡。若應用進程被殺死,則會觸發AppDeathRecipient.binderDied回調,在該回調中調用appDiedLocked方法,執行清理動作。

3. 綁定到APP進程

[ActivityManagerService.java]

private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {
    // 省略 ···
       
    // 省略ProcessRecord內成員初始設置部分 ···
    // 省略超時消息相關部分 ···
    
    try {
        // 省略調試設置相關部分 ···
        // 省略適配設置相關部分 ···
        // ···
      
        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) {
            // instr類型爲ActiveInstrumentation,Instrument測試框架相關,可通過
            // AMS的startInstrumentation方法註冊ActiveInstrumentation。
            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 {
            // 調用IApplicationThread.bindApplication方法將信息傳給應用進程進行綁定
            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);
        }
    } catch (Exception e) {
        // 省略異常處理部分 ···
        return false;
    }
    
    // 省略檢查Activity、Service、Broadcast部分(當要啓動的目標組件所在進程未啓動情況下,會先啓動進程,之後再啓動組件) ···
    // 省略oom_adj更新部分 ···
    // ···
}

ActivityManagerService最終會將應用信息和各種配置信息通過IApplicationThread binder通信接口傳遞給APP進程。

其中getCommonServicesLocked方法還會將一些常用的系統服務IBinder保存在ArrayMap中,一併傳給APP進程,提高APP在使用這些服務時的效率。

bindApplication

回到APP進程,IApplicationThread.bindApplication方法將調用ActivityThread.bindApplication方法:
[ActivityThread.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) {

    // 若AMS傳來的常用Service不爲空,則添加進ServiceManager保存
    if (services != null) {
        // 省略日誌相關部分 ··· 
        // Setup the service cache in the ServiceManager
        ServiceManager.initServiceCache(services);
    }

    setCoreSettings(coreSettings);

    // 用AppBindData來包裝各種信息參數
    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;
    // 當前運行在binder線程中,通過mH發送到主線程處理AppBindData
    sendMessage(H.BIND_APPLICATION, data);
}

bindApplication方法中先保存了常用Service的Binder代理引用,然後將各種信息參數包裝進AppBindData,通過handler發送到主線程處理。

BIND_APPLICATION這個case下會調用handleBindApplication方法:
[ActivityThread.java]

private void handleBindApplication(AppBindData data) {
    // 省略設置敏感線程、調試相關部分相關部分
    
    // 保存設備、適配配置等信息
    mBoundApplication = data;
    mConfiguration = new Configuration(data.config);
    mCompatConfiguration = new Configuration(data.config);
    
    mProfiler = new Profiler();
    // 省略mProfiler配置相關部分
    
    // 設置進程名稱
    // send up app name; do this *before* waiting for debugger
    Process.setArgV0(data.processName);
    android.ddm.DdmHandleAppName.setAppName(data.processName,
                                            UserHandle.myUserId());
    VMRuntime.setProcessPackageName(data.appInfo.packageName);
    
    // 啓動性能監控
    if (mProfiler.profileFd != null) {
        mProfiler.startProfiling();
    }
    
    // 省略Message、ImageDecoder等版本兼容部分
    // 省略時區初始設置部分
    // 省略更新Configuration相關部分
    
    // 獲取LoadedApk對象
    data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
    
    // 省略density兼容、24Hour制、StrictMode設置等部分
    // 省略調試模式下waiting for debugger彈框相關部分
    // 省略systrace messages、http代理設置等相關部分
    // 省略InstrumentationInfo相關部分 ···
    
    // 創建ContextImpl
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
    
    // 省略isolated process相關部分
    // 省略NetworkSecurityConfigProvider相關部分
    
    // 創建Instrumentation,並使之持有ActivityThread引用
    mInstrumentation = new Instrumentation();
    mInstrumentation.basicInit(this);
    
    // 省略largeHeap設置相關部分
    
    // 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.
        // 創建Application對象
        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)) {
                // 初始化APP註冊的ContentProvider
                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 {
            // 調用Application.onCreate生命週期方法
            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);
        }
    }
    
    // 省略預加載字體資源部分
}

handleBindApplication方法中進行了一系列的應用初始化配置,並先後創建了LoadedApkContextImplInstrumentationApplication

makeApplication

在handleBindApplication方法中調用了LoadedApk的makeApplication方法來創建Application,進入這個方法看看內部創建的過程:

[LoadedApk.java]

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }

    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

    Application app = null;

    // 獲取Androidmanifest中定義的自定義Application的類名
    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        // 使用系統默認Application
        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
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        // 通過反射實例化Application,並調用Application的attach方法,attach方法中又調用
        // attachBaseContext方法,在attachBaseContext方法中將ContextImpl賦值給mBase。
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        // 使ContextImpl持有Application引用
        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;

    // 此時傳入的instrumentation爲null
    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;
}

總結

ActivityThread的main方法中在當前所在線程創建Looper,並將當前線程其指定爲主線程。之後實例化ActivityThread,並調用其attach方法。最後開啓Looper循環,不斷監聽處理主線程消息隊列中的消息。

在attach方法中,創建IApplicationThread binder通信接口,之後通過IActivityManager執行ActivityManagerService的attachApplication方法,並將IApplicationThread傳遞過去。

ActivityManagerService.attachApplication中對新啓動進程校驗通過後,通過IApplicationThread調用ActivityThread的bindApplication方法,並將應用信息參數傳遞過來。bindApplication方法中將信息參數打包發送到主線程執行handleBindApplication方法。

在handleBindApplication方法中,進行應用進程的初始配置,實例化LoadedApk、ContextImpl、Instrumentation、Application並設置互相持有引用,最後回調Application.onCreate生命週期方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章