Activity啓動過程全解析

文章出自:https://www.jianshu.com/p/6037f6fda285

前言

  • 一個App是怎麼啓動起來的?
  • App的程序入口到底是哪裏?
  • Launcher到底是什麼神奇的東西?
  • 聽說還有個AMS的東西,它是做什麼的?
  • Binder是什麼?他是如何進行IPC通信的?
  • Activity生命週期到底是什麼時候調用的?被誰調用的?
  • 等等...

你是不是還有很多類似的疑問一直沒有解決?沒關係,這篇文章將結合源碼以及大量的優秀文章,站在巨人的肩膀上,更加通俗的來試着解釋一些問題。但是畢竟源碼繁多、經驗有限,文中不免會出現一些紕漏甚至是錯誤,還懇請大家指出,互相學習。

學習目標

  1. 瞭解從手機開機第一個zygote進程創建,到點擊桌面上的圖標,進入一個App的完整流程,並且從源碼的角度瞭解到一個Activity的生命週期是怎麼回事
  2. 瞭解到ActivityManagerServices(即AMS)、ActivityStack、ActivityThread、Instrumentation等Android framework中非常重要的基礎類的作用,及相互間的關係
  3. 瞭解AMS與ActivityThread之間利用Binder進行IPC通信的過程,瞭解AMS和ActivityThread在控制Activity生命週期起到的作用和相互之間的配合
  4. 瞭解與Activity相關的framework層的其他瑣碎問題

寫作方式

這篇文章我決定採用一問一答的方式進行。

其實在這之前,我試過把每個流程的代碼調用過程,用粘貼源代碼的方式寫在文章裏,但是寫完一部分之後,發現由於代碼量太大,整篇文章和老太太的裹腳布一樣——又臭又長,雖然每個重要的操作可以顯示出詳細調用過程,但是太關注於細節反而導致從整體上不能很好的把握。所以在原來的基礎之上進行了修改,對關鍵的幾個步驟進行重點介紹,力求語言簡潔,重點突出,從而讓大家在更高的層次上對framework層有個認識,然後結合後面我給出的參考資料,大家就可以更加快速,更加高效的瞭解這一塊的整體架構。

主要對象功能介紹

我們下面的文章將圍繞着這幾個類進行介紹。可能你第一次看的時候,印象不深,不過沒關係,當你跟隨者我讀完這篇文章的時候,我會在最後再次列出這些對象的功能,相信那時候你會對這些類更加的熟悉和深刻。

  • ActivityManagerServices,簡稱AMS,服務端對象,負責系統中所有Activity的生命週期
  • ActivityThread,App的真正入口。當開啓App之後,會調用main()開始運行,開啓消息循環隊列,這就是傳說中的UI線程或者叫主線程。與ActivityManagerServices配合,一起完成Activity的管理工作
  • ApplicationThread,用來實現ActivityManagerService與ActivityThread之間的交互。在ActivityManagerService需要管理相關Application中的Activity的生命週期時,通過ApplicationThread的代理對象與ActivityThread通訊。
  • ApplicationThreadProxy,是ApplicationThread在服務器端的代理,負責和客戶端的ApplicationThread通訊。AMS就是通過該代理與ActivityThread進行通信的。
  • Instrumentation,每一個應用程序只有一個Instrumentation對象,每個Activity內都有一個對該對象的引用。Instrumentation可以理解爲應用進程的管家,ActivityThread要創建或暫停某個Activity時,都需要通過Instrumentation來進行具體的操作。
  • ActivityStack,Activity在AMS的棧管理,用來記錄已經啓動的Activity的先後關係,狀態信息等。通過ActivityStack決定是否需要啓動新的進程。
  • ActivityRecord,ActivityStack的管理對象,每個Activity在AMS對應一個ActivityRecord,來記錄Activity的狀態以及其他的管理信息。其實就是服務器端的Activity對象的映像。
  • TaskRecord,AMS抽象出來的一個“任務”的概念,是記錄ActivityRecord的棧,一個“Task”包含若干個ActivityRecord。AMS用TaskRecord確保Activity啓動和退出的順序。如果你清楚Activity的4種launchMode,那麼對這個概念應該不陌生。

主要流程介紹

下面將按照App啓動過程的先後順序,一問一答,來解釋一些事情。

讓我們開始吧!

zygote是什麼?有什麼作用?

首先,你覺得這個單詞眼熟不?當你的程序Crash的時候,打印的紅色log下面通常帶有這一個單詞。

zygote意爲“受精卵“。Android是基於Linux系統的,而在Linux中,所有的進程都是由init進程直接或者是間接fork出來的,zygote進程也不例外。

在Android系統裏面,zygote是一個進程的名字。Android是基於Linux System的,當你的手機開機的時候,Linux的內核加載完成之後就會啓動一個叫“init“的進程。在Linux System裏面,所有的進程都是由init進程fork出來的,我們的zygote進程也不例外。

我們都知道,每一個App其實都是

  • 一個單獨的dalvik虛擬機
  • 一個單獨的進程

所以當系統裏面的第一個zygote進程運行之後,在這之後再開啓App,就相當於開啓一個新的進程。而爲了實現資源共用和更快的啓動速度,Android系統開啓新進程的方式,是通過fork第一個zygote進程實現的。所以說,除了第一個zygote進程,其他應用所在的進程都是zygote的子進程,這下你明白爲什麼這個進程叫“受精卵”了吧?因爲就像是一個受精卵一樣,它能快速的分裂,並且產生遺傳物質一樣的細胞!

SystemServer是什麼?有什麼作用?它與zygote的關係是什麼?

首先我要告訴你的是,SystemServer也是一個進程,而且是由zygote進程fork出來的。

知道了SystemServer的本質,我們對它就不算太陌生了,這個進程是Android Framework裏面兩大非常重要的進程之一——另外一個進程就是上面的zygote進程。

爲什麼說SystemServer非常重要呢?因爲系統裏面重要的服務都是在這個進程裏面開啓的,比如
ActivityManagerService、PackageManagerService、WindowManagerService等等,看着是不是都挺眼熟的?

那麼這些系統服務是怎麼開啓起來的呢?

在zygote開啓的時候,會調用ZygoteInit.main()進行初始化

public static void main(String argv[]) {
    
     ...ignore some code...
    
    //在加載首個zygote的時候,會傳入初始化參數,使得startSystemServer = true
     boolean startSystemServer = false;
     for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
            
            ...ignore some code...
            
         //開始fork我們的SystemServer進程
     if (startSystemServer) {
                startSystemServer(abiList, socketName);
         }

     ...ignore some code...

}

我們看下startSystemServer()做了些什麼

    /**留着這個註釋,就是爲了說明SystemServer確實是被fork出來的
     * Prepare the arguments and fork for the system server process.
     */
    private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
        
         ...ignore some code...
        
        //留着這段註釋,就是爲了說明上面ZygoteInit.main(String argv[])裏面的argv就是通過這種方式傳遞進來的
        /* Hardcoded command line to start the system server */
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
            "--capabilities=" + capabilities + "," + capabilities,
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };

        int pid;
        try {
            parsedArgs = new ZygoteConnection.Arguments(args);
            ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
            ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

        //確實是fuck出來的吧,我沒騙你吧~不對,是fork出來的 -_-|||
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            handleSystemServerProcess(parsedArgs);
        }

        return true;
    }

ActivityManagerService是什麼?什麼時候初始化的?有什麼作用?

ActivityManagerService,簡稱AMS,服務端對象,負責系統中所有Activity的生命週期。

ActivityManagerService進行初始化的時機很明確,就是在SystemServer進程開啓的時候,就會初始化ActivityManagerService。從下面的代碼中可以看到

public final class SystemServer {

    //zygote的主入口
    public static void main(String[] args) {
        new SystemServer().run();
    }

    public SystemServer() {
        // Check for factory test mode.
        mFactoryTestMode = FactoryTest.getMode();
    }
    
    private void run() {
        
        ...ignore some code...
        
        //加載本地系統服務庫,並進行初始化 
        System.loadLibrary("android_servers");
        nativeInit();
        
        // 創建系統上下文
        createSystemContext();
        
        //初始化SystemServiceManager對象,下面的系統服務開啓都需要調用SystemServiceManager.startService(Class<T>),這個方法通過反射來啓動對應的服務
        mSystemServiceManager = new SystemServiceManager(mSystemContext);
        
        //開啓服務
        try {
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        }
       
        ...ignore some code...
    
    }

    //初始化系統上下文對象mSystemContext,並設置默認的主題,mSystemContext實際上是一個ContextImpl對象。調用ActivityThread.systemMain()的時候,會調用ActivityThread.attach(true),而在attach()裏面,則創建了Application對象,並調用了Application.onCreate()。
    private void createSystemContext() {
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
    }

    //在這裏開啓了幾個核心的服務,因爲這些服務之間相互依賴,所以都放在了這個方法裏面。
    private void startBootstrapServices() {
        
        ...ignore some code...
        
        //初始化ActivityManagerService
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        
        //初始化PowerManagerService,因爲其他服務需要依賴這個Service,因此需要儘快的初始化
        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

        // 現在電源管理已經開啓,ActivityManagerService負責電源管理功能
        mActivityManagerService.initPowerManagement();

        // 初始化DisplayManagerService
        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
    
    //初始化PackageManagerService
    mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
       mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    
    ...ignore some code...
    
    }

}

經過上面這些步驟,我們的ActivityManagerService對象已經創建好了,並且完成了成員變量初始化。而且在這之前,調用createSystemContext()創建系統上下文的時候,也已經完成了mSystemContext和ActivityThread的創建。注意,這是系統進程開啓時的流程,在這之後,會開啓系統的Launcher程序,完成系統界面的加載與顯示。

你是否會好奇,我爲什麼說AMS是服務端對象?下面我給你介紹下Android系統裏面的服務器和客戶端的概念。

其實服務器客戶端的概念不僅僅存在於Web開發中,在Android的框架設計中,使用的也是這一種模式。服務器端指的就是所有App共用的系統服務,比如我們這裏提到的ActivityManagerService,和前面提到的PackageManagerService、WindowManagerService等等,這些基礎的系統服務是被所有的App公用的,當某個App想實現某個操作的時候,要告訴這些系統服務,比如你想打開一個App,那麼我們知道了包名和MainActivity類名之後就可以打開

Intent intent = new Intent(Intent.ACTION_MAIN);  
intent.addCategory(Intent.CATEGORY_LAUNCHER);              
ComponentName cn = new ComponentName(packageName, className);              
intent.setComponent(cn);  
startActivity(intent); 

但是,我們的App通過調用startActivity()並不能直接打開另外一個App,這個方法會通過一系列的調用,最後還是告訴AMS說:“我要打開這個App,我知道他的住址和名字,你幫我打開吧!”所以是AMS來通知zygote進程來fork一個新進程,來開啓我們的目標App的。這就像是瀏覽器想要打開一個超鏈接一樣,瀏覽器把網頁地址發送給服務器,然後還是服務器把需要的資源文件發送給客戶端的。

知道了Android Framework的客戶端服務器架構之後,我們還需要了解一件事情,那就是我們的App和AMS(SystemServer進程)還有zygote進程分屬於三個獨立的進程,他們之間如何通信呢?

App與AMS通過Binder進行IPC通信,AMS(SystemServer進程)與zygote通過Socket進行IPC通信。

那麼AMS有什麼用呢?在前面我們知道了,如果想打開一個App的話,需要AMS去通知zygote進程,除此之外,其實所有的Activity的開啓、暫停、關閉都需要AMS來控制,所以我們說,AMS負責系統中所有Activity的生命週期。

在Android系統中,任何一個Activity的啓動都是由AMS和應用程序進程(主要是ActivityThread)相互配合來完成的。AMS服務統一調度系統中所有進程的Activity啓動,而每個Activity的啓動過程則由其所屬的進程具體來完成。

這樣說你可能還是覺得比較抽象,沒關係,下面有一部分是專門來介紹AMS與ActivityThread如何一起合作控制Activity的生命週期的。

Launcher是什麼?什麼時候啓動的?

當我們點擊手機桌面上的圖標的時候,App就由Launcher開始啓動了。但是,你有沒有思考過Launcher到底是一個什麼東西?

Launcher本質上也是一個應用程序,和我們的App一樣,也是繼承自Activity

packages/apps/Launcher2/src/com/android/launcher2/Launcher.java

public final class Launcher extends Activity
        implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
                   View.OnTouchListener {
                   }

Launcher實現了點擊、長按等回調接口,來接收用戶的輸入。既然是普通的App,那麼我們的開發經驗在這裏就仍然適用,比如,我們點擊圖標的時候,是怎麼開啓的應用呢?如果讓你,你怎麼做這個功能呢?捕捉圖標點擊事件,然後startActivity()發送對應的Intent請求唄!是的,Launcher也是這麼做的,就是這麼easy!

那麼到底是處理的哪個對象的點擊事件呢?既然Launcher是App,並且有界面,那麼肯定有佈局文件呀,是的,我找到了佈局文件launcher.xml

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
    android:id="@+id/launcher">

    <com.android.launcher2.DragLayer
        android:id="@+id/drag_layer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <!-- Keep these behind the workspace so that they are not visible when
             we go into AllApps -->
        <include
            android:id="@+id/dock_divider"
            layout="@layout/workspace_divider"
            android:layout_marginBottom="@dimen/button_bar_height"
            android:layout_gravity="bottom" />

        <include
            android:id="@+id/paged_view_indicator"
            layout="@layout/scroll_indicator"
            android:layout_gravity="bottom"
            android:layout_marginBottom="@dimen/button_bar_height" />

        <!-- The workspace contains 5 screens of cells -->
        <com.android.launcher2.Workspace
            android:id="@+id/workspace"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingStart="@dimen/workspace_left_padding"
            android:paddingEnd="@dimen/workspace_right_padding"
            android:paddingTop="@dimen/workspace_top_padding"
            android:paddingBottom="@dimen/workspace_bottom_padding"
            launcher:defaultScreen="2"
            launcher:cellCountX="@integer/cell_count_x"
            launcher:cellCountY="@integer/cell_count_y"
            launcher:pageSpacing="@dimen/workspace_page_spacing"
            launcher:scrollIndicatorPaddingLeft="@dimen/workspace_divider_padding_left"
            launcher:scrollIndicatorPaddingRight="@dimen/workspace_divider_padding_right">

            <include android:id="@+id/cell1" layout="@layout/workspace_screen" />
            <include android:id="@+id/cell2" layout="@layout/workspace_screen" />
            <include android:id="@+id/cell3" layout="@layout/workspace_screen" />
            <include android:id="@+id/cell4" layout="@layout/workspace_screen" />
            <include android:id="@+id/cell5" layout="@layout/workspace_screen" />
        </com.android.launcher2.Workspace>

    ...ignore some code...

    </com.android.launcher2.DragLayer>
</FrameLayout>

爲了方便查看,我刪除了很多代碼,從上面這些我們應該可以看出一些東西來:Launcher大量使用<include/>標籤來實現界面的複用,而且定義了很多的自定義控件實現界面效果,dock_divider從佈局的參數聲明上可以猜出,是底部操作欄和上面圖標佈局的分割線,而paged_view_indicator則是頁面指示器,和App首次進入的引導頁下面的界面引導是一樣的道理。當然,我們最關心的是Workspace這個佈局,因爲註釋裏面說在這裏麪包含了5個屏幕的單元格,想必你也猜到了,這個就是在首頁存放我們圖標的那五個界面(不同的ROM會做不同的DIY,數量不固定)。

接下來,我們應該打開workspace_screen佈局,看看裏面有什麼東東。

workspace_screen.xml

<com.android.launcher2.CellLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:paddingStart="@dimen/cell_layout_left_padding"
    android:paddingEnd="@dimen/cell_layout_right_padding"
    android:paddingTop="@dimen/cell_layout_top_padding"
    android:paddingBottom="@dimen/cell_layout_bottom_padding"
    android:hapticFeedbackEnabled="false"
    launcher:cellWidth="@dimen/workspace_cell_width"
    launcher:cellHeight="@dimen/workspace_cell_height"
    launcher:widthGap="@dimen/workspace_width_gap"
    launcher:heightGap="@dimen/workspace_height_gap"
    launcher:maxGap="@dimen/workspace_max_gap" />

裏面就一個CellLayout,也是一個自定義佈局,那麼我們就可以猜到了,既然可以存放圖標,那麼這個自定義的佈局很有可能是繼承自ViewGroup或者是其子類,實際上,CellLayout確實是繼承自ViewGroup。在CellLayout裏面,只放了一個子View,那就是ShortcutAndWidgetContainer。從名字也可以看出來,ShortcutAndWidgetContainer這個類就是用來存放快捷圖標Widget小部件的,那麼裏面放的是什麼對象呢?

在桌面上的圖標,使用的是BubbleTextView對象,這個對象在TextView的基礎之上,添加了一些特效,比如你長按移動圖標的時候,圖標位置會出現一個背景(不同版本的效果不同),所以我們找到BubbleTextView對象的點擊事件,就可以找到Launcher如何開啓一個App了。

除了在桌面上有圖標之外,在程序列表中點擊圖標,也可以開啓對應的程序。這裏的圖標使用的不是BubbleTextView對象,而是PagedViewIcon對象,我們如果找到它的點擊事件,就也可以找到Launcher如何開啓一個App。

其實說這麼多,和今天的主題隔着十萬八千里,上面這些東西,你有興趣就看,沒興趣就直接跳過,不知道不影響這篇文章閱讀。

BubbleTextView的點擊事件在哪裏呢?我來告訴你:在Launcher.onClick(View v)裏面。

   /**
     * Launches the intent referred by the clicked shortcut
     */
    public void onClick(View v) {
    
          ...ignore some code...
            
         Object tag = v.getTag();
        if (tag instanceof ShortcutInfo) {
            // Open shortcut
            final Intent intent = ((ShortcutInfo) tag).intent;
            int[] pos = new int[2];
            v.getLocationOnScreen(pos);
            intent.setSourceBounds(new Rect(pos[0], pos[1],
                    pos[0] + v.getWidth(), pos[1] + v.getHeight()));
        //開始開啓Activity咯~
            boolean success = startActivitySafely(v, intent, tag);

            if (success && v instanceof BubbleTextView) {
                mWaitingForResume = (BubbleTextView) v;
                mWaitingForResume.setStayPressed(true);
            }
        } else if (tag instanceof FolderInfo) {
            //如果點擊的是圖標文件夾,就打開文件夾
            if (v instanceof FolderIcon) {
                FolderIcon fi = (FolderIcon) v;
                handleFolderClick(fi);
            }
        } else if (v == mAllAppsButton) {
        ...ignore some code...
        }
    }

從上面的代碼我們可以看到,在桌面上點擊快捷圖標的時候,會調用

startActivitySafely(v, intent, tag);

那麼從程序列表界面,點擊圖標的時候會發生什麼呢?實際上,程序列表界面使用的是AppsCustomizePagedView對象,所以我在這個類裏面找到了onClick(View v)。

com.android.launcher2.AppsCustomizePagedView.java

/**
 * The Apps/Customize page that displays all the applications, widgets, and shortcuts.
 */
public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
        View.OnClickListener, View.OnKeyListener, DragSource,
        PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener,
        LauncherTransitionable {
            
     @Override
    public void onClick(View v) {
       
         ...ignore some code...
       
        if (v instanceof PagedViewIcon) {
            mLauncher.updateWallpaperVisibility(true);
            mLauncher.startActivitySafely(v, appInfo.intent, appInfo);
        } else if (v instanceof PagedViewWidget) {
                 ...ignore some code..
         }
     }      
   }

可以看到,調用的是

mLauncher.startActivitySafely(v, appInfo.intent, appInfo);

和上面一樣!這叫什麼?這叫殊途同歸!

所以咱們現在又明白了一件事情:不管從哪裏點擊圖標,調用的都是Launcher.startActivitySafely()。

  • 下面我們就可以一步步的來看一下Launcher.startActivitySafely()到底做了什麼事情。
 boolean startActivitySafely(View v, Intent intent, Object tag) {
        boolean success = false;
        try {
            success = startActivity(v, intent, tag);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
        }
        return success;
    }

調用了startActivity(v, intent, tag)

 boolean startActivity(View v, Intent intent, Object tag) {
 
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            boolean useLaunchAnimation = (v != null) &&
                    !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
            
            if (useLaunchAnimation) {
                if (user == null || user.equals(android.os.Process.myUserHandle())) {
                    startActivity(intent, opts.toBundle());
                } else {
                    launcherApps.startMainActivity(intent.getComponent(), user,
                            intent.getSourceBounds(),
                            opts.toBundle());
                }
            } else {
                if (user == null || user.equals(android.os.Process.myUserHandle())) {
                    startActivity(intent);
                } else {
                    launcherApps.startMainActivity(intent.getComponent(), user,
                            intent.getSourceBounds(), null);
                }
            }
            return true;
        } catch (SecurityException e) {
        ...
        }
        return false;
    }

這裏會調用Activity.startActivity(intent, opts.toBundle()),這個方法熟悉嗎?這就是我們經常用到的Activity.startActivity(Intent)的重載函數。而且由於設置了

 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

所以這個Activity會添加到一個新的Task棧中,而且,startActivity()調用的其實是startActivityForResult()這個方法。

@Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

所以我們現在明確了,Launcher中開啓一個App,其實和我們在Activity中直接startActivity()基本一樣,都是調用了Activity.startActivityForResult()。

Instrumentation是什麼?和ActivityThread是什麼關係?

還記得前面說過的Instrumentation對象嗎?每個Activity都持有Instrumentation對象的一個引用,但是整個進程只會存在一個Instrumentation對象。當startActivityForResult()調用之後,實際上還是調用了mInstrumentation.execStartActivity()

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
        if (mParent == null) {
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
            if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            ...ignore some code...    
        } else {
            if (options != null) {
                 //當現在的Activity有父Activity的時候會調用,但是在startActivityFromChild()內部實際還是調用的mInstrumentation.execStartActivity()
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
         ...ignore some code...    
    }

下面是mInstrumentation.execStartActivity()的實現

 public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options) {
        IApplicationThread whoThread = (IApplicationThread) contextThread;
            ...ignore some code...
      try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess();
            int result = ActivityManagerNative.getDefault()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
        }
        return null;
    }

所以當我們在程序中調用startActivity()的 時候,實際上調用的是Instrumentation的相關的方法。

Instrumentation意爲“儀器”,我們先看一下這個類裏面包含哪些方法吧

我們可以看到,這個類裏面的方法大多數和Application和Activity有關,是的,這個類就是完成對Application和Activity初始化和生命週期的工具類。比如說,我單獨挑一個callActivityOnCreate()讓你看看

public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        activity.performCreate(icicle);
        postPerformCreate(activity);
    }

對activity.performCreate(icicle);這一行代碼熟悉嗎?這一行裏面就調用了傳說中的Activity的入口函數onCreate(),不信?接着往下看

Activity.performCreate()

final void performCreate(Bundle icicle) {
        onCreate(icicle);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }

沒騙你吧,onCreate在這裏調用了吧。但是有一件事情必須說清楚,那就是這個Instrumentation類這麼重要,爲啥我在開發的過程中,沒有發現他的蹤跡呢?

是的,Instrumentation這個類很重要,對Activity生命週期方法的調用根本就離不開他,他可以說是一個大管家,但是,這個大管家比較害羞,是一個女的,管內不管外,是老闆娘~

那麼你可能要問了,老闆是誰呀?
老闆當然是大名鼎鼎的ActivityThread了!

ActivityThread你都沒聽說過?那你肯定聽說過傳說中的UI線程吧?是的,這就是UI線程。我們前面說過,App和AMS是通過Binder傳遞信息的,那麼ActivityThread就是專門與AMS的外交工作的。

AMS說:“ActivityThread,你給我暫停一個Activity!”
ActivityThread就說:“沒問題!”然後轉身和Instrumentation說:“老婆,AMS讓暫停一個Activity,我這裏忙着呢,你快去幫我把這事辦了把~”
於是,Instrumentation就去把事兒搞定了。

所以說,AMS是董事會,負責指揮和調度的,ActivityThread是老闆,雖然說家裏的事自己說了算,但是需要聽從AMS的指揮,而Instrumentation則是老闆娘,負責家裏的大事小事,但是一般不拋頭露面,聽一家之主ActivityThread的安排。

如何理解AMS和ActivityThread之間的Binder通信?

前面我們說到,在調用startActivity()的時候,實際上調用的是

mInstrumentation.execStartActivity()

但是到這裏還沒完呢!裏面又調用了下面的方法

ActivityManagerNative.getDefault()
                .startActivity

這裏的ActivityManagerNative.getDefault返回的就是ActivityManagerService的遠程接口,即ActivityManagerProxy。

怎麼知道的呢?往下看

public abstract class ActivityManagerNative extends Binder implements IActivityManager
{

//從類聲明上,我們可以看到ActivityManagerNative是Binder的一個子類,而且實現了IActivityManager接口
 static public IActivityManager getDefault() {
        return gDefault.get();
    }

 //通過單例模式獲取一個IActivityManager對象,這個對象通過asInterface(b)獲得
 private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
        protected IActivityManager create() {
            IBinder b = ServiceManager.getService("activity");
            if (false) {
                Log.v("ActivityManager", "default service binder = " + b);
            }
            IActivityManager am = asInterface(b);
            if (false) {
                Log.v("ActivityManager", "default service = " + am);
            }
            return am;
        }
    };
}


//最終返回的還是一個ActivityManagerProxy對象
static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
    
     //這裏面的Binder類型的obj參數會作爲ActivityManagerProxy的成員變量保存爲mRemote成員變量,負責進行IPC通信
        return new ActivityManagerProxy(obj);
    }


}

再看ActivityManagerProxy.startActivity(),在這裏面做的事情就是IPC通信,利用Binder對象,調用transact(),把所有需要的參數封裝成Parcel對象,向AMS發送數據進行通信。

 public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(callingPackage);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo);
        data.writeString(resultWho);
        data.writeInt(requestCode);
        data.writeInt(startFlags);
        if (profilerInfo != null) {
            data.writeInt(1);
            profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
        } else {
            data.writeInt(0);
        }
        if (options != null) {
            data.writeInt(1);
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

Binder本質上只是一種底層通信方式,和具體服務沒有關係。爲了提供具體服務,Server必須提供一套接口函數以便Client通過遠程訪問使用各種服務。這時通常採用Proxy設計模式:將接口函數定義在一個抽象類中,Server和Client都會以該抽象類爲基類實現所有接口函數,所不同的是Server端是真正的功能實現,而Client端是對這些函數遠程調用請求的包裝。

爲了更方便的說明客戶端和服務器之間的Binder通信,下面以ActivityManagerServices和他在客戶端的代理類ActivityManagerProxy爲例。

ActivityManagerServices和ActivityManagerProxy都實現了同一個接口——IActivityManager。

class ActivityManagerProxy implements IActivityManager{}

public final class ActivityManagerService extends ActivityManagerNative{}

public abstract class ActivityManagerNative extends Binder implements IActivityManager{}

雖然都實現了同一個接口,但是代理對象ActivityManagerProxy並不會對這些方法進行真正地實現,ActivityManagerProxy只是通過這種方式對方法的參數進行打包(因爲都實現了相同接口,所以可以保證同一個方法有相同的參數,即對要傳輸給服務器的數據進行打包),真正實現的是ActivityManagerService。

但是這個地方並不是直接由客戶端傳遞給服務器,而是通過Binder驅動進行中轉。其實我對Binder驅動並不熟悉,我們就把他當做一箇中轉站就OK,客戶端調用ActivityManagerProxy接口裏面的方法,把數據傳送給Binder驅動,然後Binder驅動就會把這些東西轉發給服務器的ActivityManagerServices,由ActivityManagerServices去真正的實施具體的操作。

但是Binder只能傳遞數據,並不知道是要調用ActivityManagerServices的哪個方法,所以在數據中會添加方法的唯一標識碼,比如前面的startActivity()方法:

public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
       
        ...ignore some code...
       
        mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
        reply.readException();
        int result = reply.readInt();
        reply.recycle();
        data.recycle();
        return result;
    }

上面的START_ACTIVITY_TRANSACTION就是方法標示,data是要傳輸給Binder驅動的數據,reply則接受操作的返回值。

客戶端:ActivityManagerProxy =====>Binder驅動=====> ActivityManagerService:服務器

而且由於繼承了同樣的公共接口類,ActivityManagerProxy提供了與ActivityManagerService一樣的函數原型,使用戶感覺不出Server是運行在本地還是遠端,從而可以更加方便的調用這些重要的系統服務。

但是!這裏Binder通信是單方向的,即從ActivityManagerProxy指向ActivityManagerService的,如果AMS想要通知ActivityThread做一些事情,應該咋辦呢?

還是通過Binder通信,不過是換了另外一對,換成了ApplicationThread和ApplicationThreadProxy。

客戶端:ApplicationThread <=====Binder驅動<===== ApplicationThreadProxy:服務器

他們也都實現了相同的接口IApplicationThread

  private class ApplicationThread extends ApplicationThreadNative {}
  
  public abstract class ApplicationThreadNative extends Binder implements IApplicationThread{}
  
  class ApplicationThreadProxy implements IApplicationThread {}

剩下的就不必多說了吧,和前面一樣。

AMS接收到客戶端的請求之後,會如何開啓一個Activity?

OK,至此,點擊桌面圖標調用startActivity(),終於把數據和要開啓Activity的請求發送到了AMS了。說了這麼多,其實這些都在一瞬間完成了,下面咱們研究下AMS到底做了什麼。

注:前方有高能的方法調用鏈,如果你現在累了,請先喝杯咖啡或者是上趟廁所休息下

AMS收到startActivity的請求之後,會按照如下的方法鏈進行調用

調用startActivity()

@Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
            resultWho, requestCode, startFlags, profilerInfo, options,
            UserHandle.getCallingUserId());
    }

調用startActivityAsUser()

 @Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
            
            ...ignore some code...
            
        return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, options, userId, null, null);
    }

在這裏又出現了一個新對象ActivityStackSupervisor,通過這個類可以實現對ActivityStack的部分操作。

  final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
            Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask) {
            
            ...ignore some code...
            
              int res = startActivityLocked(caller, intent, resolvedType, aInfo,
                    voiceSession, voiceInteractor, resultTo, resultWho,
                    requestCode, callingPid, callingUid, callingPackage,
                    realCallingPid, realCallingUid, startFlags, options,
                    componentSpecified, null, container, inTask);
            
            ...ignore some code...
            
            }

繼續調用startActivityLocked()

 final int startActivityLocked(IApplicationThread caller,
            Intent intent, String resolvedType, ActivityInfo aInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode,
            int callingPid, int callingUid, String callingPackage,
            int realCallingPid, int realCallingUid, int startFlags, Bundle options,
            boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,
            TaskRecord inTask) {
         
              err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
              startFlags, true, options, inTask);
        if (err < 0) {
            notifyActivityDrawnForKeyguard();
        }
        return err;
    }

調用startActivityUncheckedLocked(),此時要啓動的Activity已經通過檢驗,被認爲是一個正當的啓動請求。

終於,在這裏調用到了ActivityStack的startActivityLocked(ActivityRecord r, boolean newTask,boolean doResume, boolean keepCurTransition, Bundle options)。

ActivityRecord代表的就是要開啓的Activity對象,裏面分裝了很多信息,比如所在的ActivityTask等,如果這是首次打開應用,那麼這個Activity會被放到ActivityTask的棧頂,

final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
            boolean doResume, Bundle options, TaskRecord inTask) {
            
            ...ignore some code...
            
            targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
            
            ...ignore some code...
            
             return ActivityManager.START_SUCCESS;
            }

調用的是ActivityStack.startActivityLocked()

 final void startActivityLocked(ActivityRecord r, boolean newTask,
            boolean doResume, boolean keepCurTransition, Bundle options) {
        
        //ActivityRecord中存儲的TaskRecord信息
        TaskRecord rTask = r.task;
      
         ...ignore some code...
      
        //如果不是在新的ActivityTask(也就是TaskRecord)中的話,就找出要運行在的TaskRecord對象
     TaskRecord task = null;
        if (!newTask) {
            boolean startIt = true;
            for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
                task = mTaskHistory.get(taskNdx);
                if (task.getTopActivity() == null) {
                    // task中的所有Activity都結束了
                    continue;
                }
                if (task == r.task) {
                    // 找到了
                    if (!startIt) {
                        task.addActivityToTop(r);
                        r.putInHistory();
                        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
                                r.userId, r.info.configChanges, task.voiceSession != null,
                                r.mLaunchTaskBehind);
                        if (VALIDATE_TOKENS) {
                            validateAppTokensLocked();
                        }
                        ActivityOptions.abort(options);
                        return;
                    }
                    break;
                } else if (task.numFullscreen > 0) {
                    startIt = false;
                }
            }
        }

      ...ignore some code...

        // Place a new activity at top of stack, so it is next to interact
        // with the user.
        task = r.task;
        task.addActivityToTop(r);
        task.setFrontOfTask();

        ...ignore some code...

         if (doResume) {
            mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
        }
    }

靠!這來回折騰什麼呢!從ActivityStackSupervisor到ActivityStack,又調回ActivityStackSupervisor,這到底是在折騰什麼玩意啊!!!

淡定...淡定...我知道你也在心裏罵娘,世界如此美妙,你卻如此暴躁,這樣不好,不好...

來來來,咱們繼續哈,剛纔說到哪裏了?哦,對,咱們一起看下StackSupervisor.resumeTopActivitiesLocked(this, r, options)

 boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
            Bundle targetOptions) {
        if (targetStack == null) {
            targetStack = getFocusedStack();
        }
        // Do targetStack first.
        boolean result = false;
        if (isFrontStack(targetStack)) {
            result = targetStack.resumeTopActivityLocked(target, targetOptions);
        }
        
          ...ignore some code...
        
        return result;
    }

我...已無力吐槽了,又調回ActivityStack去了...

ActivityStack.resumeTopActivityLocked()

final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
        if (inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }

        boolean result = false;
        try {
            // Protect against recursion.
            inResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            inResumeTopActivity = false;
        }
        return result;
    }

咱們堅持住,看一下ActivityStack.resumeTopActivityInnerLocked()到底進行了什麼操作

  final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
  
          ...ignore some code...
      //找出還沒結束的首個ActivityRecord
     ActivityRecord next = topRunningActivityLocked(null);
    
    //如果一個沒結束的Activity都沒有,就開啓Launcher程序
    if (next == null) {
            ActivityOptions.abort(options);
            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");
            if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
            // Only resume home if on home display
            final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
                    HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
            return isOnHomeDisplay() &&
                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
        }
        
        //先需要暫停當前的Activity。因爲我們是在Lancher中啓動mainActivity,所以當前mResumedActivity!=null,調用startPausingLocked()使得Launcher進入Pausing狀態
          if (mResumedActivity != null) {
            pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
            if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);
        }
  
  }

在這個方法裏,prev.app爲記錄啓動Lancher進程的ProcessRecord,prev.app.thread爲Lancher進程的遠程調用接口IApplicationThead,所以可以調用prev.app.thread.schedulePauseActivity,到Lancher進程暫停指定Activity。

 final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
            boolean dontWait) {
        if (mPausingActivity != null) {
            completePauseLocked(false);
        }
       
       ...ignore some code...    

        if (prev.app != null && prev.app.thread != null) 
          try {
                mService.updateUsageStats(prev, false);
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);
            } catch (Exception e) {
                mPausingActivity = null;
                mLastPausedActivity = null;
                mLastNoHistoryActivity = null;
            }
        } else {
            mPausingActivity = null;
            mLastPausedActivity = null;
            mLastNoHistoryActivity = null;
        }

      ...ignore some code...  

 }

在Lancher進程中消息傳遞,調用ActivityThread.handlePauseActivity(),最終調用ActivityThread.performPauseActivity()暫停指定Activity。接着通過前面所說的Binder通信,通知AMS已經完成暫停的操作。

ActivityManagerNative.getDefault().activityPaused(token).

上面這些調用過程非常複雜,源碼中各種條件判斷讓人眼花繚亂,所以說如果你沒記住也沒關係,你只要記住這個流程,理解了Android在控制Activity生命週期時是如何操作,以及是通過哪幾個關鍵的類進行操作的就可以了,以後遇到相關的問題之道從哪塊下手即可,這些過程我雖然也是擼了一遍,但還是記不清。

最後來一張高清無碼大圖,方便大家記憶:

請戳這裏(圖片3.3M,請用電腦觀看)

送給你們的彩蛋

不要使用 startActivityForResult(intent,RESULT_OK)

這是因爲startActivity()是這樣實現的

public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            // Note we want to go through this call for compatibility with
            // applications that may have overridden the method.
            startActivityForResult(intent, -1);
        }
    }

 public static final int RESULT_OK  = -1;

所以

startActivityForResult(intent,RESULT_OK) = startActivity()

你不可能從onActivityResult()裏面收到任何回調。而這個問題是相當難以被發現的,就是因爲這個坑,我工作一年多來第一次加班到9點 (ˇˍˇ)

一個App的程序入口到底是什麼?

是ActivityThread.main()。

整個App的主線程的消息循環是在哪裏創建的?

是在ActivityThread初始化的時候,就已經創建消息循環了,所以在主線程裏面創建Handler不需要指定Looper,而如果在其他線程使用Handler,則需要單獨使用Looper.prepare()和Looper.loop()創建消息循環。

 public static void main(String[] args) {
 
          ...ignore some code...    

      Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        AsyncTask.init();

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();
        
          ...ignore some code...    
        
 }

Application是在什麼時候創建的?onCreate()什麼時候調用的?

也是在ActivityThread.main()的時候,再具體點呢,就是在thread.attach(false)的時候。

看你的表情,不信是吧!凱子哥帶你溜溜~

我們先看一下ActivityThread.attach()

private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        //普通App進這裏
        if (!system) {
        
            ...ignore some code...    
        
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                // Ignore
            }
           } else {
             //這個分支在SystemServer加載的時候會進入,通過調用
             // private void createSystemContext() {
             //    ActivityThread activityThread = ActivityThread.systemMain();
             //} 
             
             // public static ActivityThread systemMain() {
        //        if (!ActivityManager.isHighEndGfx()) {
        //            HardwareRenderer.disable(true);
        //        } else {
        //            HardwareRenderer.enableForegroundTrimming();
        //        }
        //        ActivityThread thread = new ActivityThread();
        //        thread.attach(true);
        //        return thread;
        //    }       
           }
    }

這裏需要關注的就是mgr.attachApplication(mAppThread),這個就會通過Binder調用到AMS裏面對應的方法

@Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }

然後就是

 private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
            
            
             thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
                    mCoreSettingsObserver.getCoreSettingsLocked());
            
            
            }

thread是IApplicationThread,實際上就是ApplicationThread在服務端的代理類ApplicationThreadProxy,然後又通過IPC就會調用到ApplicationThread的對應方法

private class ApplicationThread extends ApplicationThreadNative {

  public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
                Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
                Bundle coreSettings) {
                
                 ...ignore some code...    
                
             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.enableOpenGlTrace = enableOpenGlTrace;
            data.restrictedBackupMode = isRestrictedBackupMode;
            data.persistent = persistent;
            data.config = config;
            data.compatInfo = compatInfo;
            data.initProfilerInfo = profilerInfo;
            sendMessage(H.BIND_APPLICATION, data);
                
           }

}

我們需要關注的其實就是最後的sendMessage(),裏面有函數的編號H.BIND_APPLICATION,然後這個Messge會被H這個Handler處理

 private class H extends Handler {
 
      ...ignore some code... 
 
     public static final int BIND_APPLICATION        = 110;
 
    ...ignore some code... 
 
     public void handleMessage(Message msg) {
          switch (msg.what) {
        ...ignore some code... 
         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;
        ...ignore some code... 
        }
 }

最後就在下面這個方法中,完成了實例化,撥那個企鵝通過mInstrumentation.callApplicationOnCreate實現了onCreate()的調用。

 private void handleBindApplication(AppBindData data) {
 
 try {
           
           ...ignore some code... 
           
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;

           ...ignore some code... 
           
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            catch (Exception e) {
            }
            try {
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {            }
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
 }

data.info是一個LoadeApk對象。
LoadeApk.data.info.makeApplication()

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

        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();
            }
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {        }
        mActivityThread.mAllApplications.add(app);
        mApplication = app;

    //傳進來的是null,所以這裏不會執行,onCreate在上一層執行
        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
               
            }
        }
        ...ignore some code... 
              
       }

        return app;
    }

所以最後還是通過Instrumentation.makeApplication()實例化的,這個老闆娘真的很厲害呀!

static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

而且通過反射拿到Application對象之後,直接調用attach(),所以attach()調用是在onCreate()之前的。

參考文章

下面的這些文章都是這方面比較精品的,希望你抽出時間研究,這可能需要花費很長時間,但是如果你想進階爲中高級開發者,這一步是必須的。

再次感謝下面這些文章的作者的分享精神。

Binder

zygote

ActivityThread、Instrumentation、AMS

Launcher

結語

OK,到這裏,這篇文章算是告一段落了,我們再回頭看看一開始的幾個問題,你還困惑嗎?

  • 一個App是怎麼啓動起來的?
  • App的程序入口到底是哪裏?
  • Launcher到底是什麼神奇的東西?
  • 聽說還有個AMS的東西,它是做什麼的?
  • Binder是什麼?他是如何進行IPC通信的?
  • Activity生命週期到底是什麼時候調用的?被誰調用的?

再回過頭來看看這些類,你還迷惑嗎?

  • ActivityManagerServices,簡稱AMS,服務端對象,負責系統中所有Activity的生命週期
  • ActivityThread,App的真正入口。當開啓App之後,會調用main()開始運行,開啓消息循環隊列,這就是傳說中的UI線程或者叫主線程。與ActivityManagerServices配合,一起完成Activity的管理工作
  • ApplicationThread,用來實現ActivityManagerService與ActivityThread之間的交互。在ActivityManagerService需要管理相關Application中的Activity的生命週期時,通過ApplicationThread的代理對象與ActivityThread通訊。
  • ApplicationThreadProxy,是ApplicationThread在服務器端的代理,負責和客戶端的ApplicationThread通訊。AMS就是通過該代理與ActivityThread進行通信的。
  • Instrumentation,每一個應用程序只有一個Instrumentation對象,每個Activity內都有一個對該對象的引用。Instrumentation可以理解爲應用進程的管家,ActivityThread要創建或暫停某個Activity時,都需要通過Instrumentation來進行具體的操作。
  • ActivityStack,Activity在AMS的棧管理,用來記錄已經啓動的Activity的先後關係,狀態信息等。通過ActivityStack決定是否需要啓動新的進程。
  • ActivityRecord,ActivityStack的管理對象,每個Activity在AMS對應一個ActivityRecord,來記錄Activity的狀態以及其他的管理信息。其實就是服務器端的Activity對象的映像。
  • TaskRecord,AMS抽象出來的一個“任務”的概念,是記錄ActivityRecord的棧,一個“Task”包含若干個ActivityRecord。AMS用TaskRecord確保Activity啓動和退出的順序。如果你清楚Activity的4種launchMode,那麼對這個概念應該不陌生。

如果你還感到迷惑的話,就把這篇文章多讀幾遍吧,信息量可能比較多,需要慢慢消化~



作者:裸奔的凱子哥
鏈接:https://www.jianshu.com/p/6037f6fda285
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。


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