Activity 啟動(dòng)流程分析(Android10)

概覽

Activity 啟動(dòng)流程比較復(fù)雜,分析起來很容易陷入復(fù)雜的代碼中去,所以我這篇分析文章不會(huì)深入的分析代碼細(xì)節(jié),盡量拋開不重要的東西把啟動(dòng)流程按照重點(diǎn)分成幾個(gè)部分來分析。
下圖是 Activity 啟動(dòng)流程的總覽。

(上圖紅色方塊是與 WMS 關(guān)聯(lián)的部分,后面會(huì)從這里開始介紹 WMS)
后面我們將以 Android 29 為例,按照上圖步驟逐步分析。

Intent 解析到 Activity

調(diào)用 startActivity 之后,經(jīng)過幾步輾轉(zhuǎn)最終會(huì)調(diào)用到 AMS 中,而 AMS 又會(huì)調(diào)用 ActivityStarter 來啟動(dòng) Activity。
解析 Intent 的任務(wù)將由PackageManagerService#resolveIntent方法來處理。
Intent 匹配規(guī)則太負(fù)責(zé)了,我本意是想學(xué)習(xí)啟動(dòng)流程,所以就沒深入進(jìn)去看代碼,就這樣吧。

通過 Zygote 創(chuàng)建進(jìn)程

如果目標(biāo)進(jìn)程未啟動(dòng),則會(huì)先啟動(dòng)進(jìn)程,這里先把啟動(dòng)進(jìn)程的方法調(diào)用棧放上來,方便后面分析。

ActivityStackSupervisor#startSpecificActivityLocked
ActivityManagerService$LocalService#startProcess
ProcessList#startProcessLocked
Process#start
ZygoteProcess#start

方法最終是走到了 ZygoteProcess 中,這個(gè)類負(fù)責(zé)創(chuàng)建進(jìn)程,我們知道 Android 系統(tǒng)的進(jìn)程由 Zygote 創(chuàng)建,而 ZygoteProcess 實(shí)際上是負(fù)責(zé)與 Zygote 進(jìn)行通信的類。

ZygoteProcess#attemptUsapSendArgsAndGetResult方法中打開了一個(gè) LocalSocket 連接,通過這個(gè) Socket 與 Zygote 進(jìn)行通信。

該 LocalSocket 服務(wù)端在 ZygoteServer 中,我們?cè)倏聪路?wù)端具體是如何做的。

我們主要關(guān)注ZygoteServer#runSelectLoop方法,里面最重要的兩行代碼如下:

ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);

那我們?cè)偬?code>ZygoteConnection#processOneCommand中看看。

Runnable processOneCommand(ZygoteServer zygoteServer) {
    ...
    //處理并應(yīng)用參數(shù)
    args = Zygote.readArgumentList(mSocketReader);
    parsedArgs = new ZygoteArguments(args);
    Zygote.applyUidSecurityPolicy(parsedArgs, peer);
    ...
    pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
            parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
            parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
            parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);
    ...
    if (pid == 0) {
        return handleChildProc(parsedArgs, descriptors, childPipeFd,
                parsedArgs.mStartChildZygote);
    } else {
        handleParentProc(pid, descriptors, serverPipeFd);
        return null;
    }
}

看到?jīng)],找了半天,終于找到了 Zygote,這里主要通過Zygote.forkAndSpecialize方法來孵化進(jìn)程,并獲取 pid。

forkAndSpecialize 方法主要就是調(diào)用了Zygote.nativeForkAndSpecialize方法,根據(jù)名字可以看出來這是一個(gè)原生方法,我們就到此為止吧,不繼續(xù)了。

我們?cè)倩氐?code>ZygoteConnection#processOneCommand方法中,進(jìn)程創(chuàng)建完成后,還會(huì)繼續(xù)調(diào)用 handleChildProc 方法,我們順著這個(gè)方法繼續(xù)看下去。

private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
                                 FileDescriptor pipeFd, boolean isZygote) {
    closeSocket();
    //省略...
    if (parsedArgs.mInvokeWith != null) {
    //省略...
    } else {
        if (!isZygote) {
            //isZygote 一般為 false
            return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mRemainingArgs, null /* classLoader */);
        } else {
            return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
                    parsedArgs.mRemainingArgs, null /* classLoader */);
        }
    }
}

最后調(diào)用了ZygoteInit.zygoteInit方法,這個(gè)方法是用來進(jìn)程進(jìn)行初始化操作的,上面進(jìn)程創(chuàng)建完成后,還需要對(duì)其進(jìn)行初始化操作才能讓整個(gè) APP 運(yùn)轉(zhuǎn)起來。

實(shí)際上 zygoteInit 方法就是通過反射找到ActivityThread.main方法并調(diào)用。關(guān)于這個(gè)方法后面會(huì)介紹。

ActivityThread

ActivityThread 實(shí)際上并不是個(gè)線程,他并沒有繼承 Thread 類,我們下面來分析下這個(gè)類到底是個(gè)什么鬼。

上面說到 Zygote 最后會(huì)調(diào)用Activity.main方法,main 方法也就是程序的入口,一個(gè) Android 軟件也就是從這里開始的。

public static void main(String[] args) {
    //省略...
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}

上面是 main 函數(shù)的部分代碼,主要做了如下幾件事:

  • 實(shí)例化 ActivityThread
  • 調(diào)用 ActivityThread#attach 方法
  • 啟動(dòng) Loop 消息循環(huán)隊(duì)列

著重看一下 attach 方法,其中主要做了一些程序啟動(dòng)的前置準(zhǔn)其中的方法調(diào)用順序如下:

ActivityThread#attach
ActivityManagerService#attachApplication
ActivityThread$ApplicationThread#bindApplication
ActivityThread#handleBindApplication

ApplicationThread 跟 ActivityThread 一樣,都不是一個(gè)線程,我們直接看ActivityThread#handleBindApplication方法好了,另外幾個(gè)都是一些亂七八糟的判斷和參數(shù)組織之類的。

handleBindApplication 這個(gè)方法比較長(zhǎng),主要就是一些前置準(zhǔn)備、檢查、初始化等操作,例如:

  • 調(diào)試模式下啟動(dòng) APP 時(shí)顯示 waiting for debugger 的等待對(duì)話框
  • 初始化分辨率
  • 設(shè)置時(shí)間格式
  • 初始化包名、依賴庫(kù)路徑、資源文件路徑
  • 創(chuàng)建并初始化 Instrumentation,這個(gè)類很重要
  • 調(diào)用 LoadApk#makeApplication 創(chuàng)建 Application 實(shí)例

如果未指定程序的 Application 則使用默認(rèn)的 Application 類,否則使用我們指定的,然后獲取到 ClassLoader 并調(diào)用 Instrumentation#newApplication 方法,Application 創(chuàng)建完成后繼續(xù)回調(diào) Application#onCreate 方法。

Activity#onCreate

我們上面看到 ActivityThread#main 中開啟了消息循環(huán),主線程所有的操作都將通過 Handler 來分發(fā)。

關(guān)于生命周期的調(diào)用鏈也比較復(fù)雜,有個(gè)專門的 ClientLifecycleManager 類負(fù)責(zé)管理生命周期,這個(gè)類最終也是通過 Handler 的方式來控制生命周期。具體的調(diào)用鏈這里就不貼了,挺復(fù)雜的,也沒必要,不是本文的重點(diǎn),我們只需要知道最終調(diào)用到了ActivityThread#performLaunchActivity方法就行了。

這個(gè)方法將會(huì)創(chuàng)建目標(biāo) Activity 實(shí)例,并回調(diào) attach 及 onCreate 方法,我們來看下:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    java.lang.ClassLoader cl = appContext.getClassLoader();
    //通過 Instrumentation 實(shí)例化 Activity 對(duì)象
    Activity activity = mInstrumentation.newActivity(
            cl, component.getClassName(), r.intent);
    if (activity != null) {
        CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
        //回調(diào) attach 方法,設(shè)置 title 等等
        activity.attach(appContext, this, getInstrumentation(), r.token,
                r.ident, app, r.intent, r.activityInfo, title, r.parent,
                r.embeddedID, r.lastNonConfigurationInstances, config,
                r.referrer, r.voiceInteractor, window, r.configCallback,
                r.assistToken);
        int theme = r.activityInfo.getThemeResource();
        if (theme != 0) {
            //設(shè)置樣式
            activity.setTheme(theme);
        }
        //回調(diào) Activity#onCreate
        if (r.isPersistable()) {
            mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
        } else {
            mInstrumentation.callActivityOnCreate(activity, r.state);
        }
    }
    return activity;
}

(上面代碼只是簡(jiǎn)寫版,中間省略了很多)
重點(diǎn)都在注釋里面了。

Activity#attach

attach 方法也比較重要,這是 Activity 初始化方法,除了基本設(shè)置之外,還負(fù)責(zé)創(chuàng)建 Window 對(duì)象,為后面的顯示頁(yè)面做好準(zhǔn)備。

final void attach(Context context, ActivityThread aThread,
                  Instrumentation instr, IBinder token, int ident,
                  Application application, Intent intent, ActivityInfo info,
                  CharSequence title, Activity parent, String id,
                  NonConfigurationInstances lastNonConfigurationInstances,
                  Configuration config, String referrer, IVoiceInteractor voiceInteractor,
                  Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
    //初始化 FragmentManager
    mFragments.attachHost(null /*parent*/);

    //實(shí)例化 Window,一般為 PhoneWindow
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(this);
    //設(shè)置 Window.Callback 回調(diào),用于接收各種輸入事件
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    mUiThread = Thread.currentThread();

    mMainThread = aThread;
    mApplication = application;
    mActivityInfo = info;
    mTitle = title;
    //設(shè)置 WindowManager
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
}

這個(gè)重點(diǎn)也寫在注釋里了,主要就是創(chuàng)建 PhoneWindow 并設(shè)置回調(diào),關(guān)于 Window 系列的東西我的下一篇文章會(huì)繼續(xù)介紹,這里先把他們互相調(diào)用的接口留出來。

ActivityThread#handleResumeActivity

onCreate 回調(diào)完成后就開始準(zhǔn)備顯示頁(yè)面然后回調(diào) onResume。這個(gè)操作從 handleResumeActivity 方法開始。

@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                                 String reason) {
    //通過 performResumeActivity 方法獲取到 Activity,該方法還會(huì)調(diào)用 Activity#onCreate 方法
    final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
    final Activity a = r.activity;

    //是否需要顯示
    boolean willBeVisible = ActivityManager.getService().willActivityBeVisible(
            a.getActivityToken());
    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        //獲取 DecorView,這里的 DecorView 是在 setContentView 時(shí) Window 創(chuàng)建好的
        View decor = r.window.getDecorView();
        decor.setVisibility(View.INVISIBLE);
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        a.mDecor = decor;
        l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
        l.softInputMode |= forwardBit;
        if (!a.mWindowAdded) {
            a.mWindowAdded = true;
            //將 DecorView 添加到 WindowManager 中
            wm.addView(decor, l);
        } else {
            a.onWindowAttributesChanged(l);
        }
    } else if (!willBeVisible) {
        r.hideForNow = true;
    }

    //調(diào)用 Activity#makeVisible 方法使其可見
    if (r.activity.mVisibleFromClient) {
        r.activity.makeVisible();
    }
}

該方法主要做了如下幾件事:

  • 回調(diào)Activity#onCreate
  • 將 DecorView 添加到 WindowManager 中
  • 調(diào)用Activity#makeVisible方法使 Activity 可見

還有一些其他的操作這里就不介紹了,上面代碼也省略了很多本文不關(guān)心的部分。

Activity#makeVisible方法其實(shí)很簡(jiǎn)單,看上面代碼,再把 DecorView 添加到 WM 之前會(huì)先調(diào)用decor.setVisibility(View.INVISIBLE)方法使其不可見,而Activity#makeVisible方法就是調(diào)用了mDecor.setVisibility(View.VISIBLE)使其變成可見狀態(tài)。

好了,關(guān)于 Activity 的啟動(dòng)流程就這么多了,關(guān)于具體 Activity 如何顯示的屬于 WindowManagerService 部分,我們上面也說了是哪里調(diào)用了 WMS,下一篇文章將會(huì)從本文提到的幾個(gè) WMS 的接口方法開始說起,一直到 Window 如何被加載顯示等等。

如果覺得還不錯(cuò)的話,歡迎關(guān)注我的個(gè)人公眾號(hào):zhangke_blog

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容