天天看點

android N程序啟動流程(二)(上一個activity的暫停、程序啟動、綁定程序與建立application)android N程序啟動流程(二)(上一個activity的暫停、程序啟動、綁定程序與建立application)

android N程序啟動流程(二)(上一個activity的暫停、程序啟動、綁定程序與建立application)

第二部分将分為:上一個activity的暫停、程序啟動、綁定程序與建立application

5. 上一個activity的暫停

android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)

圖5.1 上一個activity的暫停

接着章節3.6的startActivityUnchecked中會調用最後有調用resumeFocusedStackTopActivityLocked,我們接下去從這裡開始講解。

5.1 resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java)

resumeFocusedStackTopActivityLocked恢複目前focus的堆棧stack中的頂端活動對象top activity

1) 上面章節3.6中setTaskFromReuseOrCreateNewTask->computeStackFocus->mSupervisor.getStack已經建立了mTargetStack,并将其添加到ActivityDisplay的mStack中去。

2) 章節3.6中moveToFront的insertTaskAtTop中也設定了需要啟動的應用如test2.com.myapplication成為堆棧頂端Top的程序

3) 章節4.2中setFocusStackUnchecked也設定了mTargetStack為test2

//上面章節3.6中setTaskFromReuseOrCreateNewTask已經建立了mTargetStack,
    //章節3.6中moveToFront的insertTaskAtTop中也設定了需要啟動的應用如test2.com.myapplication
    //成為堆棧頂端Top的程序
    boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (targetStack != null && isFocusedStack(targetStack)) {
            //targetStack不為null,而且isFocusedStack也是test2,故此處是會進來的
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        //...
    }
           

5.2 resumeTopActivityUncheckedLocked(ActivityStack.java)

resumeFocusedStackTopActivityLocked恢複目前focus堆棧stack中的頂端活動對象

1) 此處的stack this對象是test2上一章節5.1中說的mTargetStack

2) 此時是第一次看到resumeTopActivityInnerLocked,故是第一次進入,傳遞的prev是test2.com.myapplication我們先看第一次進入該函數的處理邏輯(第二次的請忽略先)

3) 此處邏輯依次是resumeTopActivityUncheckedLocked->resumeTopActivityInnerLocked->pauseBackStacks

4) 第一次進入由于在pauseBackStacks傳回有需要pause的應用,故pausing==true,pauseBackStacks做完不久就直接傳回了

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        //....
        result = resumeTopActivityInnerLocked(prev, options);
        //....
    }

    //第一次進來的時候prev是test2.com.myapplication(是以會先pause上一個應用如com.android.launcher);
    //第二次進來是prev是com.android.launcher,此時launcher已經pause了,
    //會進入下一個應用的resume流程(如test2.com.myapplication)
    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        //...
        //第一次進來topRunningActivityLocked是test2,第二次進來也是test2,
        //此處是在moveActivityStackToFront中已經設定過了
        final ActivityRecord next = topRunningActivityLocked();

        //...
        //此處allPausedActivitiesComplete是true,不會進入這裡,
        //說明之前已經沒有需要pause的應用(第一次進來mPausingActivity還沒有設定過==null)
        //或者pause完成(第二次進來)
        if (!mStackSupervisor.allPausedActivitiesComplete()) {
            …
            return false;
        }

        //...
        //是否有設定标志位在pausing的時候resume,預設沒有設定都是false
        final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != ;

        //此處判斷是否有需要pasue的程序(是所有stack而不僅僅是目前stack),
        //第一次進來會pause launcher(launcher的堆棧中有mResumedActivity,
        //但是章節4.2已經将焦點切換到test2)故回報pausing==true,第二次直接傳回pausing==false
        boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause);
        //mResumedActivity一直都是null(由于目前mTargetStack是新new出來的給程序test2使用),
        //隻有在test2 resume之後才會設定,如在minimalResumeActivityLocked之後設定,故不會走下面的邏輯
        if (mResumedActivity != null) {
            //...
        }

        //第一次走的pausing是true(代表有需要暫停的應用,如launcher),第二次pausing是false
        if (pausing) {
            //...
            //第一次進來到這裡就結束了
            return true;
        //此處一般都是不走的mResumedActivity == null,第二次pausing是false,
        //但是還是有activity繼續resume(allResumedActivitiesComplete傳回false)
        } else if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                mStackSupervisor.allResumedActivitiesComplete()) {
            ...
            return true;
        }

        //第二次時會進來這裡prev != next,此處next代表test2.com.myapplication,
        //prev代表com.android.launcher
        if (prev != null && prev != next) {
            if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                    && next != null && !next.nowVisible) {
                //等待prev的界面launcher隐藏,此處在mStackSupervisor的
                //processStoppingActivitiesLocked時才會remove
                mStackSupervisor.mWaitingVisibleActivities.add(prev);
            } else {
            //...
        }
        //...
        //第二次進來時prev == com.android.launcher
        if (prev != null) {
            //launcher是沒有finishing的,不進入這裡
            if (prev.finishing) {
                //...
            //準備resume test2.com.myapplication時prev代表com.android.launcher,會進來這裡
            } else {
                //prev.task不等于next.task,mLaunchTaskBehind是false,
                //WMS中傳輸類型是TRANSIT_TASK_OPEN
                mWindowManager.prepareAppTransition(prev.task == next.task
                        ? TRANSIT_ACTIVITY_OPEN
                        : next.mLaunchTaskBehind
                                ? TRANSIT_TASK_OPEN_BEHIND
                                : TRANSIT_TASK_OPEN, false);
            }
        } else {
            //...
        }
        //...
        //此處next(test2.com.myapplication)程序都還沒有起來,不會進入這裡
        if (next.app != null && next.app.thread != null) {
            //...
        //next(test2.com.myapplication)進入的是else
        } else {
            //第一次啟動hasBeenLaunched肯定是false,是以會進入此處
            if (!next.hasBeenLaunched) {
                next.hasBeenLaunched = true;
            } else {
                ...
            }
            //這裡才是真正啟動test2程序的地方
            mStackSupervisor.startSpecificActivityLocked(next, true, true);
        }
        //...
    }
           

5.3 pauseBackStacks(ActivityStackSupervisor.java)

pauseBackStacks周遊ActivityDisplay顯示裝置中的所有棧,當循環到luancher的時候,由于launcher已經不是focus的stack棧,但是它的mResumedActivity仍然存在,代表這個activity需要進行pause暫停的操作。

boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) {
        //...
        //周遊stacks目前顯示裝置的所有堆棧
        final ActivityStack stack = stacks.get(stackNdx);
        //stack是launcher,isFocusedStack是false,mResumedActivity是launcher不等于null
        if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
            //launcher的stack進行pause的操作,注意resuming是true,dontWait是false,
            //userLeaving是true,在章節3.6 startActivityUnchecked->setInitialState中設定
            someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
                    dontWait);
        //...
    }
           

5.4 startPausingLocked(ActivityStack.java)

1) startPausingLocked這個函數是啟動應用暫停pause(如此處的是上一個應用launcher),設定目前狀态為pausing

2) 進入ActivityThread處理暫停任務之前會在eventlog中輸出am_pause_activity的資訊,表示将要開始該應用的暫停了

3) 不過最重要的函數還是ActivityThread的schedulePauseActivity,該函數會處理pause任務

//userLeaving==true, uiSleeping==false, resuming==true, dontWait==false
    final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
            boolean dontWait) {
        //第一次進來mPausingActivity是null,應用沒有暫停就沒有所謂的mPausingActivity
        if (mPausingActivity != null) {
            //...
        }

        //mResumedActivity是目前resume的activity,此處是launcher
        ActivityRecord prev = mResumedActivity;

        //注意此處pause之後将設定mResumedActivity==null,代表沒有該Stack沒有resume的activity了
        mResumedActivity = null;
        //launcher設定為正在pause的程序
        mPausingActivity = prev;
        //設定上一個暫停的應用
        mLastPausedActivity = prev;
        //标定該程序在PAUSING狀态
        prev.state = ActivityState.PAUSING;

        //此處next是test2,章節4.2的insertTaskAtTop已經設定過
        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();

        //pause應用會觸發cpu狀态更新,可以使用adb shell dumpsys cpuinfo查詢
        mService.updateCpuStats();

        //prev是launcher,裡面的app和thread都是已經建立的,所有此處會進入
        if (prev.app != null && prev.app.thread != null) {
            try {
                //event log中的am_pause_activity,代表應用的pause開始
                EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                        prev.userId, System.identityHashCode(prev),
                        prev.shortComponentName);
                //cpu前背景切換,用于耗電統計
                mService.updateUsageStats(prev, false);
                //ActivityThread裡面的方法是handle(異步),此處才是activity的真正的pause執行的地方
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);
            //...

        //mPausingActivity就是launcher,是以會進來此處。
        if (mPausingActivity != null) {
            //uiSleeping==false
            if (!uiSleeping) {
                //應用的pause的時候,會暫停接收輸入事件,此時系統觸摸了不回報給上層
                prev.pauseKeyDispatchingLocked();
            }

            //dontWait==false,章節5.2中設定dontWaitForPause
            if (dontWait) {
                //隻有當dontWait是true的時候才會走這裡,就是不等待pause完成
                completePauseLocked(false);
                return false;
            } else {
                //launcher的最後onpause會走到這裡來
                Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
                msg.obj = prev;
                prev.pauseTime = SystemClock.uptimeMillis();
                //設定pause的逾時時間為500ms
                mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
                //傳回ture,代表有響應的activity正在pausing,
                //故在章節5.2 resumeTopActivityInnerLocked運作完該函數後不久就傳回了
                return true;
            }

        } else {
        //...
    }
           

ps:上面也看到了pause的時候會限制輸入事件,如果應用一直重新開機又挂掉又重新開機,此時如果不停調用pause/finish的話會限制輸入事件的分發pauseKeyDispatchingLocked,當然這種情況隻是極端情況,一般不會出現

5.5 schedulePauseActivity(ActivityThread.java)

1) schedulePauseActivity這個是通過handler(一直想吐槽這個hander也類名也太簡潔了的點吧,一個”H”就搞定)在UI主線程裡面做的事情

2) 主要流程是schedulePauseActivity->PAUSE_ACTIVITY->handlePauseActivity->performPauseActivity->performPauseActivityIfNeeded

3) 我們主要關注performPauseActivityIfNeeded目前activity暫停(這部分本章節講解)、activityPaused通知AMS上一個activity暫停完成(這部分下一章裡講解)。

//ActivityThread給外部提供的接口,pause暫停是通過應用的主線程進行處理
    public final void schedulePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport) {
        int seq = getLifecycleSeq();
        //...
        //finished等于false,走的是PAUSE_ACTIVITY,userLeaving==true,dontReport==dontWait==false
        sendMessage(
                finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                token,
                (userLeaving ? USER_LEAVING : ) | (dontReport ? DONT_REPORT : ),
                configChanges,
                seq);
    }

    //handler傳遞,調用的是handlePauseActivity
    case PAUSE_ACTIVITY: {
        //...
        //進入pause的處理
        handlePauseActivity((IBinder) args.arg1, false,
                (args.argi1 & USER_LEAVING) != , args.argi2,
                (args.argi1 & DONT_REPORT) != , args.argi3);
        //...
    } break;

    //finished是false,userLeaving==true,dontReport==false
    private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport, int seq) {
        ActivityClientRecord r = mActivities.get(token);
        ...
        if (r != null) {
            //userLeaving一般都是true
            if (userLeaving) {
                //會進入此處,會調用activity.performUserLeaving,當離開使用者可視的時候會調用
                performUserLeavingActivity(r);
            }

            //...
            //此處是pause上一個應用launcher,isPreHoneycomb是android3.0之前用的,此處是false
            performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");

            //dontReport一般沒有設定都是false,故一般都是進入此處的
            if (!dontReport) {
                try {
                    //通知AMS上一個應用完成pause了,這裡接下去就會resume下一個應用(先啟動程序),
                    //下一章會講到
                    ActivityManagerNative.getDefault().activityPaused(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }
            mSomeActivitiesChanged = true;
        }
    }


    final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
            boolean saveState, String reason) {

        //saveState是false,不跑這裡
        if (!r.activity.mFinished && saveState) {
            callCallActivityOnSaveInstanceState(r);
        }

        //這裡才是pause activity的地方
        performPauseActivityIfNeeded(r, reason);

        // 将目前pause的應用的OnActivityPausedListener暫停監聽去除
        ArrayList<OnActivityPausedListener> listeners;
        synchronized (mOnPauseListeners) {
            listeners = mOnPauseListeners.remove(r.activity);
        }
        //...
        for (int i = ; i < size; i++) {
            //此處是調用注冊了該activity thread的監聽onPaused的回調,
            //如NfcAdapter.java中的ActivityThread.currentActivityThread()
            //.registerOnActivityPausedListener(activity,mForegroundDispatchListener);
            listeners.get(i).onPaused(r.activity);
        }
        //...
    }
           

5.6 performPauseActivityIfNeeded(ActivityThread.java)

1) 通過代理類Instrumentation調用callActivityOnPause,其調用的是activity的performPause(分别會調用mFragments.dispatchPause、activity的onPause,application的ActivityLifecycleCallback生命周期回調方法onActivityPaused)

2) OnPause調用完成後會在event log中寫入am_on_paused_called,代表activity的OnPause已經完成(如果你使用onpause有問題,可以從am_pause_activity到am_on_paused_called之間所花費的時間做初步判斷)

3) 注意OnPause完成之後paused會指派為true,代表目前是暫停狀态

private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
        if (r.paused) {
            //如果之前paused==true了就直接傳回,activitythread建立設定成false,
            //oncreate将設定成ture,onresume将設定成false
            //上一個activity的上一個狀态是onresume,正在pause,故此處是paused==false
            return;
        }

        try {
            //這裡解釋一下mCalled,這個值是用來判斷是否有調用activity生命周期的函數
            r.activity.mCalled = false;

            //這就就是具體調用activity的performPause的地方
            //(包括mFragments.dispatchPause、activity的onPause,
            //application的ActivityLifecycleCallback生命周期回調方法onActivityPaused),
            //運作完之後mCalled會設定成true
            mInstrumentation.callActivityOnPause(r.activity);

            //寫event log,am_on_paused_called,說明pause已經調用
            EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
                    r.activity.getComponentName().getClassName(), reason);
            //...
        //運作了之後設定标緻位paused==true
        r.paused = true;
    }
           

到目前為止基本上把上一個activity的OnPause流程講解完了。

6. 程序啟動(一)am_proc_start

講了一大堆,是不是發現我們需要啟動的程序test2怎麼還沒到呢,流程有點長,目前android的預設架構就是這樣,大家耐心的繼續看下去,我們這一章節就開始講到程序啟動(這部分應該很多文章都有提到,了解的同學可以不必細看)。

其實這些流程隻是學習作用,對我們了解android架構有一定幫助,解決問題(僅針對那些代碼不規範自己改出來的問題)時有幫助,不過這些都不是關注的重點,我們關注的是如何優化整個流程,如果沒有明确這個目的,對我們來說是沒有很大提升的。路漫漫其修遠,我們先把流程梳理清楚,一步步來…

android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)

圖6.1 程序啟動(一)

6.1 activityPaused(ActivityManagerService.java)

在章節5.5中的

ActivityManagerNative.getDefault().activityPaused(token)

,這個函數的意思是告訴AMS,上一個應用已經完成OnPause了,接下去的工作可以繼續下去。

public final void activityPaused(IBinder token) {
        //...
        //調用的是ActivityStack的activityPausedLocked,第二個參數timeout==false
        stack.activityPausedLocked(token, false);
        //...
    }
           

其中token是上一個應用的Ibinder對象,我們認為是launcher就行了

6.2 activityPausedLocked(ActivityStack.java)

1) 通知launcher自身Stack棧中的activityPausedLocked,目前已經完成pause暫停操作了,可以将之前章節5.4中說的PAUSE_TIMEOUT_MSG逾時去掉。

2) mPausingActivity也是在章節5.4開始暫停的時候設定的,如果發現真正暫停的應用和完成暫停的應用是一個,代表暫停完成,調用completePauseLocked,并傳遞resumeNext==true,代表需要resume下一個應用

//AMS調用的timeout==false
    final void activityPausedLocked(IBinder token, boolean timeout) {
        //代表該task仍在堆棧中,此時launcher是launcher的paused
        final ActivityRecord r = isInStackLocked(token);
        if (r != null) {
            //pause已經完成,不需要PAUSE_TIMEOUT_MSG了
            mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
            //之前在startPausingLocked的時候設定了目前pause的應用,
            //這個時候AMS傳回代表pause成功,會進入這裡
            if (mPausingActivity == r) {
                //pause成功,傳遞的參數是resumeNext==true,代表需要resume下一個應用
                completePauseLocked(true);
                return;
            } else {
            ...
    }
           

6.3 completePauseLocked(true)

1) mWaitingVisibleActivities這裡代表的是需要隐藏的可視界面,到目前為止我們沒有設定過,這個是在第二次進入章節5.2 resumeTopActivityInnerLocked的時候才會設定。(準備resume恢複下一個應用test2,上一個應用launcher就會放入等待隐藏的清單mWaitingVisibleActivities中)

2) 非睡眠或者關機狀态的時候會進入下一個activity的resume操作resumeFocusedStackTopActivityLocked

3) 最後ensureActivitiesVisibleLocked(ActivityStackSupervisor.java/ActivityStack.java)會更新界面相關操作,屬于WMS範疇,本文不過多涉及

{

//啟動程序後會更新界面,此處僅僅把流程列出來,由于這篇文章本身太長了,不想在額外增加内容
    ensureActivitiesVisibleLocked
        ->ensureActivityConfigurationLocked
        ->makeVisibleAndRestartIfNeeded->startSpecificActivityLocked()
        ->screenshotActivitiesLocked
        ->makeInvisible->addToStopping->scheduleIdleLocked
           

}

private void completePauseLocked(boolean resumeNext) {
        //prev,mPausingActivity是launcher
        ActivityRecord prev = mPausingActivity;
        //prev是不等于null的會進來這裡
        if (prev != null) {
            //state在startPausingLocked時設定了ActivityState.PAUSING,
            //是以一般情況wasStopping都是false
            final boolean wasStopping = prev.state == ActivityState.STOPPING;

            //重新設定标志位是ActivityState.PAUSED,這個是已經暫停的狀态
            prev.state = ActivityState.PAUSED;

            //一般情況launcher啟動應用,prev.finishing==false,故不會進入這裡面
            if (prev.finishing) {
                //...
            //prev.app是launcher
            } else if (prev.app != null) {
                //pause com.android.launcher時,此處會進來,prev就是com.android.launcher,
                //wasStopping==false,visible==true

               //第一次進來時mWaitingVisibleActivities還沒有prev(resumeTopActivityInnerLocked
               //第二次運作是才會設定),故不會進來這個
                if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
                    //...
                }

                //這個是在pause之後重新啟動,一般都是false
                if (prev.deferRelaunchUntilPaused) {
                    //...
                //wasStopping==false,也不走這裡
                } else if (wasStopping) {
                    //...
                //由于visible==true,也不是在睡眠狀态,這裡也不會進來
                } else if ((!prev.visible && !hasVisibleBehindActivity())
                        || mService.isSleepingOrShuttingDownLocked()) {
                    //...
                }
            } else {
                //這裡實在app在onpause過程中died掉才會進入,正常不會運作
                prev = null;
            }

            if (prev != null) {
                //如果界面是凍屏的話,由于界面不再可見,将移除凍屏狀态
                prev.stopFreezingScreenLocked(true /*force*/);
            }
            //mPausingActivity設定為null,此時pause已經全部完成
            mPausingActivity = null;
        }

        //上面都是AMS進來的activityPausedLocked,resumeNext == true
        if (resumeNext) {
            //之前的moveActivityStackToFront中有設定過focus stack為test2
            final ActivityStack topStack = mStackSupervisor.getFocusedStack();

            //非睡眠或者關機會進入這裡
            if (!mService.isSleepingOrShuttingDownLocked()) {
                //一般進入這裡,會resume 下一個應用(next),
                //同步的,執行了Process.start之後才會繼續往下跑
                mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
            } else {
            ...
        }

        if (prev != null) {
            //重新恢複接收輸入事件
            prev.resumeKeyDispatchingLocked();

            //如果是在使用電池
            if (prev.app != null && prev.cpuTimeAtResume > 
                    && mService.mBatteryStatsService.isOnBattery()) {
                //cpuTimeAtResume是在activity resume的時候設定的,
                //代表從resume到pause的時間,将作為前台運作時間
                long diff = mService.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid)
                        - prev.cpuTimeAtResume;
                //...
                //addForegroundTimeLocked這個是電量估算的時候用的,判斷該activity前台運作的時常
                if (ps != null) {
                    ps.addForegroundTimeLocked(diff);
                //...
            }
            //目前已經是onpause暫停了,清空進入resume的時間
            prev.cpuTimeAtResume = ;
        }

        //有界面可視的時候mAppVisibilitiesChangedSinceLastPause==true(setVisible時設定),
        //是以這裡會進來
        if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause) {
            //...
            //launcher已經pause,設定mAppVisibilitiesChangedSinceLastPause==false
            mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false;
        }

        //最後是更新顯示界面,這裡是第一次調用ensureActivitiesVisibleLocked,
        //周遊所有stack的ensureActivitiesVisibleLocked
        mStackSupervisor.ensureActivitiesVisibleLocked(null, , !PRESERVE_WINDOWS);
    }
           

6.4 resumeFocusedStackTopActivityLocked/startSpecificActivityLocked(ActivityStackSupervisor.java)

resumeFocusedStackTopActivityLocked在章節5.1-5.2已經看過,此處傳遞的targetStack是test2,pre是launcher,resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java) -> resumeTopActivityUncheckedLocked(ActivityStack.java) -> resumeTopActivityInnerLocked -> startSpecificActivityLocked(ActivityStackSupervisor.java),啟動的是next==test2

這裡就不翻回去講了,接下去講

startSpecificActivityLocked(ActivityStackSupervisor.java)

這個啟動應用的函數(注意此處是第一次進入,章節6.3提到的那一次是第二次進入,是在之後)

//r==test2,andResume==true,checkConfig==true
    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        //...
        //當程序都未啟動時不走這裡,thread肯定是null,熱啟動相關邏輯本次不讨論
        if (app != null && app.thread != null) {
            ...
        }
        //AMS中去啟動程序
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, ,
                "activity", r.intent.getComponent(), false, false, true);
    }
           

6.5 startProcessLocked(ActivityManagerService.java)

重要看到startProcessLocked啟動程序相關名字,這個是AMS的啟動程序的api。

先關注第一次進入的邏輯:

1) 建立一個程序對象的執行個體new ProcessRecord,該對象可以代表一個程序

2) 判斷應用是32位還是64位的,用于虛拟機參數配置

3) Process.start程序啟動

4) event log寫入am_proc_start,代表程序已經啟動,這句話出來的時候應用程序已經建立

//9個參數(r.processName==test2, r.info.applicationInfo, true, 0, 
    //"activity", r.intent.getComponent(), false, false, true)
    final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge) {
        //注意此處entryPoint==null
        return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
                hostingName, allowWhileBooting, isolated,  /* isolatedUid */, keepIfLarge,
                null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
                null /* crashHandler */);
    }

    //14個參數,建立ProcessRecord
    final ProcessRecord startProcessLocked(String processName, ...) {
        long startTime = SystemClock.elapsedRealtime();
        ProcessRecord app;
        //isolated(孤立應用)是false,knownToBeDead是true
        if (!isolated) {
            //第一次進來app肯定是null
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            //...

            //設定了背景運作,桌面啟動應用一般都不會走這裡
            if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != ) {
                ...
            } else {
                //重新計算崩潰次數(crash大于等于2次服務将不會再啟動)
                mAppErrors.resetProcessCrashTimeLocked(info);
                //...
            }
        }

        //這個是用來設定啟動程序時cpu的政策,可以加快app啟動速度
        //預設沒有用到,需要設定USE_SCHED_BOOST才會生效
        nativeMigrateToBoost();

        //3s鐘後會關閉啟動程序的cpu政策,同樣此處預設沒有用到
        mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);

        //第一次進入時沒有啟動過app/thread是null,pid是沒有的.
        //第二次進來時此處app是有了,pid也生成了,但是thread還沒有

        //第一次沒啟動不走這裡,第二次會進來
        if (app != null && app.pid > ) {
            //knownToBeDead是true,第二次進來app.thread還是null,故會進來,
            //第二次是從章節6.3中ensureActivitiesVisibleLocked調用過來的
            if ((!knownToBeDead && !app.killed) || app.thread == null) {
                //第二次程序已經建立了,直接傳回
                //...
                return app;
            }
            //...
        }

        //...
        //第一次走這裡,app是null
        if (app == null) {
            //這個是google的,用于調試卡頓的,不過除了特别有問題一般情況不會出現問題,
            //50ms去掉系統或許更快,如果是給使用者的穩定版本可以考慮把這段調試代碼删除
            checkTime(startTime, "startProcess: creating new process record");

            //此處是new ProcessRecord
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
            //...
            //建立ProcessRecord完成,該監控操作(newProcessRecordLocked)完成
            checkTime(startTime, "startProcess: done creating new process record");
        }

        //監控程序啟動的時常是否逾時
        checkTime(startTime, "startProcess: stepping in to startProcess");
        //這裡才是真正的啟動程序的地方
        startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
        checkTime(startTime, "startProcess: done starting proc!");

        //如果有pid産生代表程序建立完成
        return (app.pid != ) ? app : null;
    }

    //真正啟動程序的地方
    private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        //...
        if (app.pid >  && app.pid != MY_PID) {//第一次啟動app.pid == -1,不走這裡
            ...
        }

        //...
        updateCpuStats();//啟動程序也會更新CPU狀态

        try {
            try {
                //用于檢測是否可以啟動,如:是否安裝,是否正在凍屏等
                AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
            }

            //isolated初始值是false
            if (!app.isolated) {
                //...
                //傳回應用使用者組的gid,如果是uid不一樣,同一個應用該值也會不一樣
                permGids = pm.getPackageGids(app.info.packageName,
                        MATCH_DEBUG_TRIAGED_MISSING, app.userId);

                MountServiceInternal mountServiceInternal = LocalServices.getService(
                        MountServiceInternal.class);

                //擷取應用讀寫外部存儲的權限
                //如果是孤立應用(uid是99000-99999)将傳回MOUNT_EXTERNAL_NONE;
                //能讀傳回MOUNT_EXTERNAL_READ,能寫傳回MOUNT_EXTERNAL_WRITE
                mountExternal = mountServiceInternal.getExternalStorageMountMode(uid,
                        app.info.packageName);
                //...
            }

            //...
            //android:multiArch="true"代表所有架構都支援,一般都不設定,
            //一般應用庫檔案需要判斷是否32位還算64位,判斷方法使用
            //com_android_internal_content_NativeLibraryHelper.cpp的findSupportedAbi
            //requiredAbi就是為了相容32位&64位系統設計的
            String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi;
            if (requiredAbi == null) {
                //此處如果應用沒有設定實在32位還是64位運作的化,
                //預設使用屬性值ro.product.cpu.abilist的第一個值arm64-v8a(64bit),
                //armeabi-v7a(32bit),armeabi(32bit)
                requiredAbi = Build.SUPPORTED_ABIS[];
            }

            String instructionSet = null;
            if (app.info.primaryCpuAbi != null) {
                //通過應用的庫檔案擷取虛拟機要使用那種參數
                instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
            }


            //上面傳遞的entryPoint==null,isActivityProcess==true
            boolean isActivityProcess = (entryPoint == null);

            //将ActivityThread作為應用預設的入口函數entryPoint
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";

            //此處才是調用Process.start啟動程序的地方
            Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);//此處才是調用Process.start啟動程序的地方

            //此處就是event log中am_proc_start
            EventLog.writeEvent(EventLogTags.AM_PROC_START,
                    UserHandle.getUserId(uid), startResult.pid, uid,
                    app.processName, hostingType,
                    hostingNameStr != null ? hostingNameStr : "");


            //設定程序的pid
            app.setPid(startResult.pid);

            //一般usingWrapper==false
            app.usingWrapper = startResult.usingWrapper;

            //代表正在運作
            app.removed = false;
            app.killed = false;

            //代表沒有給AMS殺死
            app.killedByAm = false;

            synchronized (mPidsSelfLocked) {
                //process start之後就會有pid了,此處是test2.com.myapplication的pid會生成
                //會将該pid放入AMS的pid清單中
                this.mPidsSelfLocked.put(startResult.pid, app);

                if (isActivityProcess) {//isActivityProcess==true
                    //10s沒有啟動将不再啟動,該app,Process.start虛拟機程序建立是同步的,
                    //但是attachApplicationLocked是異步的,在attachApplication的時候
                    //會remove這個逾時PROC_START_TIMEOUT_MSG
                    mHandler.sendMessageDelayed(msg, startResult.usingWrapper
                            ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
                ...
    }
           

7. 程序啟動(二)Process.start

Process.start這個是建立程序通用的系統方法,代碼位置:

frameworks/base/core/java/android/os/Process.java。

接下去從這個開始,這裡面大家熟悉的内容可能更多。

android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)

圖7.1 程序啟動(二)

7.1 Process.start(Process.java)

我們注意傳遞的參數processClass是android.app.ActivityThread,niceName是processName,debugFlags一般都是等于0,mountExternal代表是否可讀寫外部存儲,targetSdkVersion是這個應用的targetSdkVersion,seInfo是簽名相關(預設是”default”),abi是這個應用要運作的cpu架構(32還是64位),instructionSet是指的是arm或者arm64,appDataDir一般指的是/data這個目錄,zygoteArgs==null。

後面這些參數都會有用到,對于了解流程有很大的幫助。

//processClass是android.app.ActivityThread,niceName是processName,
    //debugFlags一般都是等于0,mountExternal代表是否可讀寫外部存儲,
    //targetSdkVersion是這個應用的targetSdkVersion,seInfo是簽名相關(預設是”default”),
    //abi是這個應用要運作的cpu架構(32還是64位),instructionSet是指的是arm或者arm64,
    //appDataDir一般指的是/data這個目錄,zygoteArgs==null
    public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String abi,
                                  String instructionSet,
                                  String appDataDir,
                                  String[] zygoteArgs) {
        try {
            //通過虛拟機來建立新的程序
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, zygoteArgs);
        //...
    }
           

7.2 startViaZygote-> zygoteSendArgsAndGetResult

1) startViaZygote通将參數全部轉化成Zygote的數組String

2) openZygoteSocketIfNeeded/zygoteSocket.connect建立Socket連結,并擷取輸入輸出流對象

3) zygoteSendArgsAndGetResult通過Socket與底層互動,傳遞相應的事件内容,并擷取傳回的結果

private static ProcessStartResult startViaZygote(final String processClass,
        //...
        ArrayList<String> argsForZygote = new ArrayList<String>();
        //...添加虛拟機參數
        //最後添加的是ActivityThread應用的入口類
        argsForZygote.add(processClass);

        //extraArgs==null,是以後面沒有參數了
        if (extraArgs != null) {
            for (String arg : extraArgs) {
                argsForZygote.add(arg);
            }
        }

        //注意openZygoteSocketIfNeeded是connect Socket,
        //zygoteSendArgsAndGetResult是向Socket傳遞參數
        return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
    }

    private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
        if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
            try {
                //ZYGOTE_SOCKET的名字是"zygote",連接配接socket
                primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
            //...
    }

    public static ZygoteState connect(String socketAddress) throws IOException {
        //...
        try {
            //這裡是connect的地方,會通知相應的連結對象
            zygoteSocket.connect(new LocalSocketAddress(socketAddress,
                    LocalSocketAddress.Namespace.RESERVED));

            //輸入流,是用來讀東西的,例如裝置有資料輸出,然後我們讀取
            zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());

            //輸出流是用來寫東西的,例如寫東西然後輸出到什麼位置
            zygoteWriter = new BufferedWriter(new OutputStreamWriter(
                    zygoteSocket.getOutputStream()), );
        //...
    }

    private static ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            //...
           //第一個先寫的是參數大小
            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = ; i < sz; i++) {
                String arg = args.get(i);
                //傳遞設定參數
                writer.write(arg);
                writer.newLine();
            }

            //清空輸出流,并寫入,運作完成之後代表寫入成功,此時Socket會接受到相應消息
            writer.flush();

            //...
            //讀取傳回的pid資料
            result.pid = inputStream.readInt();
            //讀取傳回的usingWrapper資料
            result.usingWrapper = inputStream.readBoolean();
            ...
    }
           

7.3 ZygoteInit.main(ZygoteInit.java)

1) 開機運作app_process程序(init.zygote*.rc->app_process)->app_main.main->ZygoteInit.main,Zygote受精卵程序是由init程序建立,如下通過ps可知:init程序是Zygote64受精卵程序的父程序,而system_server是通過zygote64受精卵程序建立的。(pid是該程序的id,ppid是其父程序的id)

USER      PID   PPID  VSIZE  RSS   WCHAN              PC  NAME
root                    SyS_epoll_  S /init
root                poll_sched  S zygote64   //此處代表是64bit的
system            SyS_epoll_  S system_server
           

2) 擷取目前作業系統的32&64位架構abiList,這個在socket connect的時候用于

2) 注冊zygote的LocalServerSocket對象(Socket的服務端,可以給别人connect)

3) 啟動系統服務startSystemServer

4) 等待Socket消息的通知來執行相應的任務runSelectLoop

5) MethodAndArgsCaller的run方法

//開機運作app_process程序(init.zygote*.rc->app_process)->app_main.main->ZygoteInit.main
    public static void main(String argv[]) {
        //...
        try {
            //Socket的名字是zygote
            String socketName = "zygote";
            String abiList = null; 
            for (int i = ; i < argv.length; i++) {
                //第一次進來會設定startSystemServer==true
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    //讀的是系統屬性ro.product.cpu.abilist64或者ro.product.cpu.abilist32裡面的值
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                //...

            //android的Socket名字:ANDROID_SOCKET_ + zygote
            registerZygoteSocket(socketName);

            //event log中會出現boot_progress_preload_start
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());

            //重新加載Cache,Classes,Resources,OpenGL,SharedLibraries,
            //TextResources,WebView,AndroidKeyStoreProvider
            preload();

            //event log中會出現boot_progress_preload_end
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            //...
            //做GC,清除一些軟引用對象
            gcAndFinalize();
            //...

            //在初始化時unmount根目錄"/storage"
            Zygote.nativeUnmountStorageOnInit();

            //允許zygote建立程序
            ZygoteHooks.stopZygoteNoThreadCreation();

            //如果需要啟動系統服務則進入這裡
            if (startSystemServer) {
                //啟動系統服務system_server,先後調用fork順序是init
                //->zygote64(64位系統)->system_server,如果是系統程序的話,
                //這裡是永遠不會傳回的startSystemServer->handleSystemServerProcess
                //->RuntimeInit.zygoteInit->SystemServer.main/run->Looper.loop()
                //->(pollInner/epoll_wait)Looper.cpp,
                //這個除了Loop裡面調用mQueue.quit是不會退出的
                startSystemServer(abiList, socketName); 
            }

            //會跑下來的是zygote程序,zygote程序會一直在此運作
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            //對于此處zygote frok的子程序會進入此處,抛出MethodAndArgsCaller異常,
            //會執行run方法,其實是反射調用ActivityThread.main,這個後面會講到
            caller.run();
        //...
    }
           

ps: Zygote程序是用來fork各個子程序的,如system_server就是其建立的,其中zygote64是所有64位程序的父程序,zygote是所有32位程序的父程序。

7.4 runSelectLoop

runSelectLoop循環等待Socket的資料回報,這裡寫的是Select的Loop,目前androidN使用的方法是Os.poll不再有1024個Socket的限制(androidL和之前的版本使用的是select方法),後續android版本更新的話可能使用epoll(目前上層的Looper、MessageQueue就是使用epoll)

1) 循環周遊等待Socket緩沖區有可讀的資料

2) Socket.connect時會建立新的ZygoteConnection

3) ZygoteConnection執行runOnce

4) 建立子程序後,子程序退出循環,父程序繼續等待下一個Socket資料

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        //...

        // sServerSocket是AMS Process.java中的ZYGOTE_SOCKET連結的對象, 用來建立程序
        //sServerSocket是LocalServerSocket,代表整個socket
        //fds是所有zygote Socket相關的檔案描述符
        fds.add(sServerSocket.getFileDescriptor());

        //peers是ZygoteConnection對象,是zygote連結之後的對象
        peers.add(null);

        while (true) {
            //...
            //events代表等待的事件類型,POLLIN類型代表我們隻關心緩沖區是否有資料可讀
            pollFds[i].events = (short) POLLIN;

            //...
            try {
                //poll函數與select類似都是,可以監視多個描述符,-1代表永不逾時,
                //輪詢一遍之後等待,當裝置驅動發生自身資源可讀寫後,會喚醒其等待隊列上睡眠的程序
                Os.poll(pollFds, -);
            }
            //...

            for (int i = pollFds.length - ; i >= ; --i) {
                //revents域是檔案描述符的操作結果事件掩碼,POLLIN代表有資料可讀
                if ((pollFds[i].revents & POLLIN) == ) {
                    continue;
                }

                //i==0是就是外部有建立socket的時候,如Socket.connect,
                //這個時候Os.poll中LocalServerSocket會有資料傳回,
                //此時LocalServerSocket會accept并建立新的ZygoteConnection
                if (i == ) {
                    //建立新的受精卵的Socket連結ZygoteConnection
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    //添加到ZygoteConnection數組peers
                    peers.add(newPeer);
                    //添加到zygote Socket相關的檔案描述符數組中去
                    fds.add(newPeer.getFileDesciptor());

                //非第一次運作時,如果之前建立的Socket連結對象ZygoteConnection有資料可以讀,
                //如OutputStream(zygoteWriter就是輸出流)有寫入,那麼此處會有資料,
                //進入runOnce函數。
                } else {
                    //建立子程序會抛出MethodAndArgsCaller的異常,
                    //給ZygoteInit.main捕獲,然後運作ActivityThread的main函數,
                    //子程序抛出異常後退出該循環,但是Zygote父程序還算會繼續循環的
                    boolean done = peers.get(i).runOnce();

                    //建立子程序後,父程序也就是zygote程序才會進入這裡
                    //...
                }
            }
        }
    }
           

runSelectLoop函數就是在監聽Socket端是否有資料可以讀,如果有資料來了,那麼就是建立程序,這個Zygote程序主要作用就是建立程序(子程序的一些基本資訊都不用再初始化,因為Zygote已經初始過了,相當于優化了啟動程序的流程)。

7.5 runOnce(ZygoteConnection.java)

1) 讀取相應的參數清單

2) 建立子程序forkAndSpecialize(Zygote.forkAndSpecialize -> com_android_internal_os_Zygote_nativeForkAndSpecialize/ForkAndSpecializeCommon/fork(com_android_internal_os_Zygote.cpp)),通過jni調用com_android_internal_os_Zygote_nativeForkAndSpecialize,最後調用的是fork函數,該函數用于建立程序,具體在這裡不展開,具體可以參考之前的一篇文章

Android上層如何調用一個底層函數

的章節

2.1.3 com_android_internal_os_Zygote.cpp本地函數

裡面有關于fork的講解。最終子程序傳回的是pid==0,父程序傳回的是子程序的pid。

3) 處理父程序的内容handleParentProc,如傳回給AMS章節6.5中startProcessLocked的Process.start,其值是Process.ProcessStartResult startResult,包含子程序pid

4) 處理子程序的内容handleChildProc,這個放在下一節講解

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        ...
        try {
            //讀取相應的參數清單
            args = readArgumentList();
            descriptors = mSocket.getAncillaryFileDescriptors();
        }
        //...
        //invokeWith==null,目前沒有設定
        if (parsedArgs.invokeWith != null) {
            //...
        }

        //...
        int [] fdsToClose = { -, - };
        FileDescriptor fd = mSocket.getFileDescriptor();
        if (fd != null) {
            //用戶端的檔案描述符
            fdsToClose[] = fd.getInt$();
        }
        fd = ZygoteInit.getServerSocketFileDescriptor();
        if (fd != null) {
            //服務端的檔案描述符
            fdsToClose[] = fd.getInt$();
        }

        //調用native fork程序的地方
        //此處是fock程序(Zygote.forkAndSpecialize
        //->com_android_internal_os_Zygote_nativeForkAndSpecialize
        //->ForkAndSpecializeCommon/fork(com_android_internal_os_Zygote.cpp))
        pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                parsedArgs.appDataDir);
        //...
        try {
            //如果是子程序pid會等于0,父程序此處pid會傳回子程序的pid
            if (pid == ) {
                //...
                //處理子程序邏輯
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

                //子程序是永遠不會到這個位置來的,因為之前已經抛出MethodAndArgsCaller異常
                return true;
            } else {
                //...
                //處理父程序邏輯
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        ...
    }

    private String[] readArgumentList()
            throws IOException {
        //...
        try {
            //讀取第一個參數
            String s = mSocketReader.readLine();
            //第一個參數上面章節7.2 Process.java中zygoteSendArgsAndGetResult寫的就是參數個數
            argc = Integer.parseInt(s);
        }
        //傳遞的參數最多是1024個,超過的話系統可能受到DOS攻擊
        if (argc > MAX_ZYGOTE_ARGC) {
            throw new IOException("max arg count exceeded");
        }
        for (int i = ; i < argc; i++) {
            //讀出每一個參數傳回result數組中去
            result[i] = mSocketReader.readLine();
            ...
    }

    private boolean handleParentProc(int pid,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
        if (pid > ) {
            //如果傳回的pid大于0,說明子程序建立成功,此時設定子程序的pid
            setChildPgid(pid);
        }

        //...
        try {
            //傳遞pid回去,最後寫入章節7.2中zygoteSendArgsAndGetResult的result.pid
            mSocketOutStream.writeInt(pid);
            //傳遞是否wrapped程序,此處一般都是false
            mSocketOutStream.writeBoolean(usingWrapper);
        }
        //...
        return false;
    }
           

8. 綁定程序am_proc_bound

上一章節我們知道了Process.start用于建立程序,父程序會直接傳回子程序的pid,那麼接下去我們需要從子程序處理的内容開始分析,看看子程序是怎樣關聯到上層的application中去的,這裡講解第一步am_proc_bound

android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)

圖8.1 綁定程序

8.1 handleChildProc(ZygoteConnection.java)

1) 關閉相應的子程序Socket連結

2) 設定程序的名字,這個時候通過ps就可以看到程序名字變成應用聲明的程序(如果沒有定義

android:process

那麼預設該程序名字就是應用的包名)

3) RuntimeInit.zygoteInit子程序的初始化

private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
        //關閉自己的Socket
        closeSocket();
        //關閉ZygoteInit中服務端的Socket
        ZygoteInit.closeServerSocket();
        //...
        if (parsedArgs.niceName != null) {
            //自己設定自己的名字,此處設定程序名字為之前傳進來的processName
            Process.setArgV0(parsedArgs.niceName);
        }

        //這裡是不運作的
        if (parsedArgs.invokeWith != null) {
            //...
        //此處會進來
        } else {
            //運作初始化RuntimeInit中的程序(受精卵)初始化zygoteInit
            RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }
           

ps:Process.setArgV0會通過prctl(PR_SET_NAME…),裁剪後(process_name.c),隻保留processName後面15個字元(kernel實際還會裁剪到最後一個字元,其實是14個字元),設定程序名字(核心辨別程序的名字是task_struc->comm).

程序的名字在某些地方顯示不是無限長的,如在systrace顯示的程序名字就不超過15個字元。

8.2 zygoteInit(RuntimeInit.java)

1) log重定向redirectLogStreams

2) 通用設定初始化commonInit

3) 初始化zygote:nativeZygoteInit

4) 應用初始化applicationInit

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        //重新定向log的輸入地方,此處設定log輸出到Android log中
        redirectLogStreams();

        //一些通用設定的初始化
        commonInit();

        //初始化zygote,這裡AppRuntime繼承的是AndroidRuntime,運作的是啟動線程池startThreadPool
        nativeZygoteInit();

        //應用初始化,此處是接下來運作的地方
        applicationInit(targetSdkVersion, argv, classLoader);
    }

    private static final void commonInit() {
        //...
        //設定預設的異常捕獲
        Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
        TimezoneGetter.setInstance(new TimezoneGetter() {
            @Override
            public String getId() {
                //設定時區id
                return SystemProperties.get("persist.sys.timezone");
            }
        });
        //設定時區
        TimeZone.setDefault(null);
        LogManager.getLogManager().reset();
        //Android log相關初始化
        new AndroidConfig();
        String userAgent = getDefaultUserAgent();
        //網絡使用者代理初始化
        System.setProperty("http.agent", userAgent);
        //網絡Socket相關
        NetworkManagementSocketTagger.install();
        //...
        initialized = true;
    }
           

8.3 applicationInit

1) 設定虛拟機GC回收比例,正在使用的對象/堆棧大小 = 0.75

2) 設定虛拟機sdk的版本号

3) 擷取相應的參數,如args.startClass就是在章節7.2 startViaZygote設定的processClass(ActivityThread)

4) 通過反射查找ActivityThread的main函數,并将其作為MethodAndArgsCaller異常的參數

private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        //設定退出時不調用onExit()函數
        nativeSetExitWithoutCleanup(true);

        //設定GC回收後的比例,正在使用的對象/堆棧大小 = 0.75,對應于dalvik.vm.heaptargetutilization
        VMRuntime.getRuntime().setTargetHeapUtilization(f);
        //設定sdk的版本号,這個是程序啟動Process.start時就傳遞過來的
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

        //擷取相應的參數,如args.startClass就是第一個非"--"開頭的參數
        final Arguments args;
        try {
            args = new Arguments(argv);
        }

        //...
        //反射調用main函數,注意startClass是Process.start時傳遞進來的android.app.ActivityThread
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws ZygoteInit.MethodAndArgsCaller {
        //...
        //查找android.app.ActivityThread類
        cl = Class.forName(className, true, classLoader);

        //...
        //查找其中的main函數
        m = cl.getMethod("main", new Class[] { String[].class });

        //...
        //擷取函數的調用屬性
        int modifiers = m.getModifiers();

        //必須是靜态而且是public的方法,否則抛出RuntimeException異常
        if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
        }

        //抛出MethodAndArgsCaller異常
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }
           

在章節7.3 ZygoteInit.main方法裡面有捕獲MethodAndArgsCaller異常,并調用MethodAndArgsCaller的run方法。

8.4 MethodAndArgsCaller.run()

反射調用ActivityThread的main靜态函數

public static class MethodAndArgsCaller extends Exception
            implements Runnable {
        //...
        public MethodAndArgsCaller(Method method, String[] args) {
            //mMethod是ActivityThread的main方法
            mMethod = method;
            //mArgs一般都是null
            mArgs = args;
        }
        public void run() {
            try {
                //調用方法method,傳遞的是args參數,傳遞第一個參數是類對象為null,代表靜态函數
                mMethod.invoke(null, new Object[] { mArgs });
            //...
           

到這裡程序已經啟動完成,将進入應用相關流程

8.5 MethodAndArgsCaller.run()

1) 消息隊列初始化Looper.prepareMainLooper

2) 建立ActivityThread并附着thread.attach

3) 進入消息隊列的循環Looper.loop

public static void main(String[] args) {
        //預設是沒有用到SamplingProfilerIntegration的,
        //該類用于監聽性能資料,包含程序名字、應用資訊、線程啟動與關閉,
        //還有預設persist.sys.profiler_ms毫秒dump一次該程序堆棧資訊
        SamplingProfilerIntegration.start();

        //在嚴格模式或者調試的時候打開,預設不打卡
        CloseGuard.setEnabled(false);

        //初始化環境(這裡主要是儲存設備的環境,用user id初始化)
        Environment.initForCurrentUser();

        //主要是libcore中使用event log的方法,Reporter的report類似于EventLog.writeEvent
        EventLogger.setReporter(new EventLoggingReporter());

        //配置檔案目錄在/data/misc/user/1000
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());

        //設定認證相關的目錄cacerts-added,cacerts-removed
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        //設定程序名字為<pre-initialized>,這個很快在handleBindApplication時就會給修改
        Process.setArgV0("<pre-initialized>");

        //消息隊列初始化,主程序是不允許退出的,無法調用MessageQueue.quit退出
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        //建立一個ActivityThread并attach附着,這個跟接下去的attachApplication相關
        thread.attach(false);

        if (sMainThreadHandler == null) {
            //擷取thread的handler,将其作為應用的主線程
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            //使用者調試log,用于消息隊列Message的事件分發log輸出,
            //調試消息隊列的時候可以打開
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        //Looper.loop()裡面是個for (;;)死循環,隻要Message不為null,會一直運作
        //Looper.loop() -> MessageQueue.next() 
        //-> nativePollOnce(android_os_MessageQueue.cpp) 
        //->(pollOnce/pollInner/epoll_wait) Looper.cpp,
        //這個Message==null情況隻有調用MessageQueue.quit才會發生,
        //目前沒有看到主動調用MessageQueue.quit,故這個消息隊列循環是不會退出的
        Looper.loop();

        //如果進入到這裡代表程式出錯了,這裡程式正常運作是不會進來的
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
           

在調用靜态方法ActivityThread.main之後會建立一個ActivityThread對象,相當于該程序的主線程(UI線程),建立之後首先跑的就是ActivityThread的attach函數

8.6 attach

這裡我們主要關注attachApplication,也就是AMS的應用附着即可

private void attach(boolean system) {
        //...
        //是否system,應用啟動肯定不是system,會進入此處
        if (!system) {
            //...

            //設定ddms中的程序名字為"<pre-initialized>",臨時的
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId());

            //設定ApplicationObject為ActivityThread
            RuntimeInit.setApplicationObject(mAppThread.asBinder());

            final IActivityManager mgr = ActivityManagerNative.getDefault();
            try {
                //此處就是attachApplication
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }

            //Java允許在類中定義一個名為finalize()的方法。
            //它的工作原理是:一旦垃圾回收器準備好釋放對象占用的存儲空間,将首先調用其finalize()方法。
            //并且在下一次垃圾回收動作發生時,才會真正回收對象占用的記憶體
            //BinderInternal裡面實作的是Object finalize,
            //當資源釋放的時候會調用finalize,然後會調用
            BinderInternal.addGcWatcher(new Runnable() {
                //ActivityThread對象沒有再使用時會進行回收
                @Override public void run() {
                    if (!mSomeActivitiesChanged) {
                        return;
                    }
                    Runtime runtime = Runtime.getRuntime();

                    //這個是HeapGrowthLimit,正常應用虛拟機記憶體最大值dalvik.vm.heapgrowthlimit, 
                    //AndroidRuntime.cpp/runtime.cc/heap.cc
                    long dalvikMax = runtime.maxMemory();
                    long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();

                    //目前使用記憶體,如果最大記憶體的3/4将進行activity的釋放操作
                    if (dalvikUsed > ((*dalvikMax)/)) {
                        //...
                        mSomeActivitiesChanged = false;
                        try {
                            //此處釋放指的是activity的ondestroy,
                            //目前可以destroy的activity是處于onstop狀态的activity
                            mgr.releaseSomeActivities(mAppThread);
                        //...
        //讓DropBox在libcore可用
        DropBox.setReporter(new DropBoxReporter());

    }
           

8.7 attachApplication/attachApplicationLocked

1) 首先是ActivityManagerNative.java的attachApplication會傳遞ActivityThread和調用者的pid給到AMS的attachApplicationLocked

2) eventlog中設定服務綁定程序am_proc_bound,說明程序啟動完成,而且該程序的主線程ActivityThread已經建立,并且通知到AMS中

3) ActivityThread的綁定應用bindApplication, 這個會在下面章節講解

4) 由于我們這個例子是桌面啟動應用,那麼最後mStackSupervisor.attachApplicationLocked堆棧中的綁定應用會真正啟動activity活動對象,這個會在下面章節講解

//ActivityManagerNative.java
    public final void attachApplication(IApplicationThread thread) {
        ...
            attachApplicationLocked(thread, callingPid);
        ...

    //ActivityManagerService.java
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        //...
        ProcessRecord app;
        //調用者非系統程序,且調用者的pid大于0
        if (pid != MY_PID && pid >= ) {
            synchronized (mPidsSelfLocked) {
                //在程序啟動Process.start後就将pid添加進入mPidsSelfLocked了(父程序調用)
                //現在是子程序調用,這個時候已經添加
                app = mPidsSelfLocked.get(pid);
            //...

        //app.thread還沒有設定過,下面makeActive将進行設定,會将app.thread設定成
        //IApplicationThread(在ActivityThread中),app.thread不為null了
        if (app.thread != null) {
            //...
        }

        //...
        try {
            AppDeathRecipient adr = new AppDeathRecipient(
                    app, pid, thread);
            //設定binder died掉之後的的回調地方是binderDied
            thread.asBinder().linkToDeath(adr, );
            //設定目前誰在監控死亡狀态
            app.deathRecipient = adr;

        //...
        //eventlog中設定服務綁定am_proc_bound
        EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);

        //設定ProcessRecord的IApplicationThread(在ActivityThread中)
        app.makeActive(thread, mProcessStats);

        //預設設定一個adj
        app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
        //...

        //使用者更新電量估算mBatteryStatsService的FOREGROUND時間
        updateProcessForegroundLocked(app, false, false);
        //...
        //判斷是否解鎖
        app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);

        //去除程序啟動逾時的msg PROC_START_TIMEOUT_MSG,
        //此處有ActivityThread回傳,代表程序啟動完成
        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

        //一般情況normalMode都是true
        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);

        //generateApplicationProvidersLocked是開始建立應用的ContentProvider對象
        List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
        //...
        //一般不會進入這裡,這裡是自動化測試的時候會進來
        if (app.instrumentationClass != null) {
            //...
        }
        //...

        //應用相容性相關,該參數會傳入AcitiviyThread中
        app.compat = compatibilityInfoForPackageLocked(appInfo);

        //一般profilerInfo==null
        ProfilerInfo profilerInfo = profileFile == null ? null
                : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);

        //回到AcitiviyThread中的bindApplication,processName==test2,
        //instrument相關都等于null,mBinderTransactionTrackingEnabled/
        //enableTrackAllocation/isRestrictedBackupMode預設等于false,
        //normalMode預設是true,persistent代表是否常駐記憶體,compat是相容性相關,
        //isolated==false,getCommonServicesLocked是将PMS、WMS、ALARM相關服務傳入,
        //mCoreSettingsObserver用于監聽一些參數變化(長按逾時,12/24小時顯示時間變化,
        //調試界面屬性),bindApplication是異步的
        thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                app.instrumentationUiAutomationConnection, testMode,
                mBinderTransactionTrackingEnabled, enableTrackAllocation,
                isRestrictedBackupMode || !normalMode, app.persistent,
                new Configuration(mConfiguration), app.compat,
                getCommonServicesLocked(app.isolated),
                mCoreSettingsObserver.getCoreSettingsLocked());

        //将程序添加進入mLruProcesses中
        //mLruProcesses儲存的是正在運作應用的清單,第一個是最近使用的
        updateLruProcessLocked(app, false, null);

        //觸發GC的時間重新計算
        app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();

        //...
        //一般normalMode都是true
        if (normalMode) {
            try {
                //如果是activity導緻的程序啟動,activity從這裡開始啟動
                //此處用于am_restart_activity,此處設定了didSomething = true
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            //...

        //一般badApp==false
        if (!badApp) {
            try {
                //如果之前該程序有需要啟動的服務,此處開始啟動服務
                //啟動程序了之後才會去啟動服務
                didSomething |= mServices.attachApplicationLocked(app, processName);
        //...
        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
            try {
                //如果該程序之前有挂起的廣播,現在可以開始發送了
                didSomething |= sendPendingBroadcastsLocked(app);
           // ...
           

到目前為止綁定程序的邏輯已經講解完了,接下去我們僅需要關注thread.bindApplication和mStackSupervisor.attachApplicationLocked這2個函數

9 建立application

這一章節将會講到application的執行個體化、application程序上下文context的建立、application的OnCreate

android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)android N程式啟動流程(二)(上一個activity的暫停、程式啟動、綁定程式與建立application)

圖9.1 建立application

9.1 bindApplication(ActivityThread.java)

我們關注的重點:

1) getPackageInfoNoCheck建立new LoadedApk,該類用于加載apk

2) makeApplication建立一個Application對象new newApplication(這裡面會createAppContext建立application的程序上下文context)

3) callApplicationOnCreate調用Application的OnCreate

private void handleBindApplication(AppBindData data) {
        //設定art實時編譯更加敏感,更新art配置相關資訊的計數count會乘10=((10000/500)/2),
        //會讓art更容易更新配置(如做實時編譯還是解釋執行等)
        VMRuntime.registerSensitiveThread();

        //...
        //設定process的啟動時間,這個主要是給上層調用的
        Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());

        //AMS傳遞進來的參數全部放在data上
        mBoundApplication = data;

        //程序啟動時如果你沒有設定固定方向或者手動改變方向,這個config就是AMS中的mConfiguration
        mConfiguration = new Configuration(data.config);
        mCompatConfiguration = new Configuration(data.config);

        mProfiler = new Profiler();
        //一般情況initProfilerInfo都是null,除了使用instrumentation(如自動化測試相關會使用到)
        if (data.initProfilerInfo != null) {
            ...
        }

        //此處會通過prctl(PR_SET_NAME...),裁剪後(process_name.c)
        //隻保留processName後面15個字元(kernel實際還會裁剪到最後一個字元,其實是14個字元),
        //設定程序名字(核心辨別程序的名字是task_struc->comm).
        Process.setArgV0(data.processName);

        //此處設定的是ddms調試使用的名字
        android.ddm.DdmHandleAppName.setAppName(data.processName,
                                                UserHandle.myUserId());

        //常駐記憶體的程序
        if (data.persistent) {
            //如果在不能使用GPU加速(如低記憶體裝置
            //或者顯示定義config_avoidGfxAccel為ture的情況都會進來)
            if (!ActivityManager.isHighEndGfx()) {
                //目前程序停止使用硬體渲染,這裡的作用主要是為了減少運存RAM的消耗,
                //對于低記憶體手機,這個是有幫助的
                ThreadedRenderer.disable(false);
            }
        }

        //...
        //回複系統預設時區
        TimeZone.setDefault(null);
        //設定預設的語言
        LocaleList.setDefault(data.config.getLocales());

        //...
        //建立new LoadedApk,該類用于加載apk
        data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);

        //...
        //可以通過config對分辨率進行設定,預設是沒有設定的
        updateDefaultDensity();

        //設定是否24小時
        final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
        DateFormat.set24HourTimePref(is24Hr);

        //...
        //網絡代理相關設定
        final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
        if (b != null) {
            final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
            try {
                final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
                Proxy.setHttpProxySystemProperty(proxyInfo);

        //...
        //建立一個appContext
        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);

        //...
        //應用一般是isIsolated == false,這裡講的不是系統程序,是普通app的程序的啟動,故會進入此處
        if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) {
            //擷取應用緩存目錄,如("/data/user_de/0/com.android.settings/cache")
            final File cacheDir = appContext.getCacheDir();

            //...
            //擷取應用代碼緩存目錄,"/data/user_de/0/com.android.settings/code_cache"
            //此處主要是存放的opengl和renderscript部分的緩存代碼
            //類似于com.android.opengl.shaders_cache、com.android.renderscript.cache這樣的資料
            final File codeCacheDir = deviceContext.getCodeCacheDir();
        }

        //...
        //ii非自動化測試一般都是null
        if (ii != null) {
            ...
        } else {
            //一般情況下走的是這裡
            mInstrumentation = new Instrumentation();
        }

        //設定虛拟機堆棧最大能增長到的記憶體是多少,根據largeHeap屬性判斷是否大應用
        if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != ) {
            //如果是大應用的話,應用虛拟機記憶體可以增長到堆棧大小dalvik.vm.heapsize
            dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
        } else {
            //預設隻能增長到dalvik.vm.heapgrowthlimit受限制的堆棧大小
            dalvik.system.VMRuntime.getRuntime().clampGrowthLimit();
        }

        // allowThreadDiskWrites在應用oncreate的時候允許寫的操作,
        //傳回的值是就得政策,此處僅用于臨時修改
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
        try {
            //restrictedBackupMode是flase,data.info是上面new的LoadedApk,
            //這裡面的createAppContext和上面的createAppContext傳遞的參數是一樣的
            //此處會建立一個Application對象new newApplication,此處是Application的執行個體化
            //此處傳遞的第二個參數instrumentation==null,故application不會在此處OnCreate
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);

            //儲存目前的Application對象
            mInitialApplication = app;

            //一般沒有限制備份模式,restrictedBackupMode == false
            if (!data.restrictedBackupMode) {
                //如果apk有provider就會進入這裡(如靜态注冊的providers)
                if (!ArrayUtils.isEmpty(data.providers)) {
                    //初始化app中的所有provider
                    installContentProviders(app, data.providers);
                    //...
                }
            }
            try {
                //如果沒有複寫Instrumentation,一般此處沒有做任何事情
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            //...
            try {
                //此處調用的就是Application的OnCreate方法,
                //activity的OnCreate後面會講到,這裡先調用的是Application的OnCreate
                mInstrumentation.callApplicationOnCreate(app);
            //...
    }
           

9.2 getPackageInfoNoCheck/getPackageInfo

getPackageInfoNoCheck/getPackageInfo傳回的是LoadedApk,用于加載apk

public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai,
            CompatibilityInfo compatInfo) {
        return getPackageInfo(ai, compatInfo, null, false, true, false);
    }

    //(ai, compatInfo, null, false, true, false);
    private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
            ClassLoader baseLoader, boolean securityViolation, boolean includeCode,
            boolean registerPackage) {
        //...

        //此處apk是包含代碼的,故是從mPackages取,第一次進來此處是null
        ref = mPackages.get(aInfo.packageName);
        LoadedApk packageInfo = ref != null ? ref.get() : null;

        //建立LoadedApk加載apk的類
        packageInfo =
            new LoadedApk(this, aInfo, compatInfo, baseLoader,
                    securityViolation, includeCode &&
                    (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != , registerPackage);

        //...
        //将建立的LoadedApk放到mPackages中
        mPackages.put(aInfo.packageName,
                new WeakReference<LoadedApk>(packageInfo));
        //...
        return packageInfo;
    }
           

9.3 makeApplication(LoadedApk.java)

1) 建立Application的程序上下文

2) 調用代理Instrumentation建立Application

3) Application執行個體化、Application設定程序上下文context

//LoadedApk.java
    //forceDefaultAppClass==false,instrumentation==null
    public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        //...
        Application app = null;

        //如果應用沒有重載Application類的話,直接使用預設的"android.app.Application"
        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            //...
            //建立Application的程序上下文
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //調用代理Instrumentation建立Application
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        }
        //...
        return app;
    }

    //Instrumentation.java
    public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }
    static public Application newApplication(Class<?> clazz, Context context)
            ... {
        //Application類的執行個體化,如類非靜态變量等會在此處生成
        Application app = (Application)clazz.newInstance();
        //調用Application的attach附着,用于設定程序上下文context
        app.attach(context);
        return app;
    }

    //Application.java
    final void attach(Context context) {
        //設定base應用基本的程序上下文
        attachBaseContext(context);
        //設定類的加載器
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }
           

現在有了Application這個對象,下面接着會進行Application的OnCreate

9.4 callApplicationOnCreate(Instrumentation.java)

callApplicationOnCreate這個函數通過代理調用Application的OnCreate

//Instrumentation.java
    public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }

    //Application.java
    public void onCreate() {
    }
           

程序啟動會先調用Application的OnCreate,這個也是算在應用啟動生命周期内的。

目前Application建立了,Application的OnCreate也調用了,接下去就是Activity相關的邏輯。