Android 7.0 ActivityManagerService(4) 啟動Activity的過程:三

之前的博客中提到過,在啟動一個新Activity時,如果界面還存在其它的Activity,那麼必須先中斷其它的Activity。
因此,除瞭第一個啟動的Home界面對應的Activity外,其它的Activity均需要進行此操作,詳細過程在啟動Activity的過程:一的第六部分進行瞭描述。

現在我們可以分析一下,這段之前略去的代碼流程。

一、startPausingLocked函數

根據啟動Activity的過程:一, 我們知道在啟動Activity的過程中,當已經將Activity對應的Task移動到前臺,同時將待啟動的Activity放置到棧頂後,將會調用ActivityStack中的resumeTopActivityInnerLocked函數,在該函數中:

private boolean resumeTopActivityInnerLocked(......) {
    ...........
    //mResumedActivity保存者當前在前臺顯示的Activity
    if (mResumedActivity != null) {
        .............
        //調用startPausingLocked函數,中斷正在顯示的Activity
        pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
    }
    if (pausing) {
        ..........
        return true;
    } ..........
    ............
} 

此處,跟進一下startPausingLocked函數:

//Start pausing the currently resumed activity.
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
        boolean dontWait) {
    .................
    //mResumedActivity保存著當前正在顯示的Activity
    ActivityRecord prev = mResumedActivity;
    .................
    mResumedActivity = null;
    //mPausingActivity保存準備中斷的Activity
    mPausingActivity = prev;
    ................
    //更新狀態
    prev.state = ActivityState.PAUSING;
    ................
    if (prev.app != null && prev.app.thread != null) {
        ................
        try {
            ............
            //通知該Activity所在的進程,調用schedulePauseActivity函數
            prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                    userLeaving, prev.configChangeFlags, dontWait);
        } catch (Exception e) {
            ...............
        }
    } else {
        ..............
    }

    // If we are not going to sleep, we want to ensure the device is
    // awake until the next activity is started.
    if (!uiSleeping && !mService.isSleepingOrShuttingDownLocked()) {
        //在啟動Activity的第二部分中提過
        //該WakeLock防止在Activity切換過程中,系統發生休眠
        //當Activity切換成功後,將會釋放該WakeLock
        mStackSupervisor.acquireLaunchWakelock();
    }

    if (mPausingActivity != null) {
        // Have the window manager pause its key dispatching until the new
        // activity has started.  If we're pausing the activity just because
        // the screen is being turned off and the UI is sleeping, don't interrupt
        // key dispatch; the same activity will pick it up again on wakeup.
        if (!uiSleeping) {
            //暫停輸入事件的派發
            prev.pauseKeyDispatchingLocked();
        } ........
        .........

        if (dontWait) {
            // If the caller said they don't want to wait for the pause, then complete
            // the pause now.
            completePauseLocked(false);
            return false;
        } else {
            // Schedule a pause timeout in case the app doesn't respond.
            // We don't give it much time because this directly impacts the
            // responsiveness seen by the user.
            Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
            msg.obj = prev;
            prev.pauseTime = SystemClock.uptimeMillis();
            //延遲時間500ms,當這個消息被處理時,也會調用completePauseLocked函數
            mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
        }
    } else {
        .............
    }
}

容易看出,這段代碼最主要的操作是與應用進程的ApplicationThread進行Binder通信,調用其schedulePauseActivity函數。
與之前的流程一樣,ApplicationThread僅作為通信接口,它將發送消息觸發進程的ActivityThread調用handlePauseActivity進行實際的操作。

二、handlePauseActivity函數

private void handlePauseActivity(IBinder token, boolean finished,
        boolean userLeaving, int configChanges, boolean dontReport, int seq) {
    ActivityClientRecord r = mActivities.get(token);
    ..............
    if (r != null) {
        ..............
        r.activity.mConfigChangeFlags |= configChanges;
        //執行pause的實際操作
        performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
        ..............
        // Tell the activity manager we have paused.
        if (!dontReport) {
            try {
                //通知AMS
                ActivityManagerNative.getDefault().activityPaused(token);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
        mSomeActivitiesChanged = true;
    }
}

這段代碼比較簡單,就是調用performPauseActivity完成中斷Activity的實際工作,然後再通過Binder通信通知AMS中斷完成。
我們稍微看一下performPauseActivity函數:

final Bundle performPauseActivity(IBinder token, boolean finished,
        boolean saveState, String reason) {
    ActivityClientRecord r = mActivities.get(token);
    return r != null ? performPauseActivity(r, finished, saveState, reason) : null;
}

final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
        boolean saveState, String reason) {
    ................
    // Next have the activity save its current state and managed dialogs...
    if (!r.activity.mFinished && saveState) {
        //完成調用Activity的onSaveInstanceState接口等操作
        callCallActivityOnSaveInstanceState(r);
    }

    //調用Activity的onPause接口
    performPauseActivityIfNeeded(r, reason);

    // Notify any outstanding on paused listeners
    ArrayList listeners;
    synchronized (mOnPauseListeners) {
        //ActivityThread提供瞭對外接口registerOnActivityPausedListener
        //可以註冊觀察者監聽某個Activity進入paused狀態
        listeners = mOnPauseListeners.remove(r.activity);
    }

    int size = (listeners != null ? listeners.size() : 0);
    for (int i = 0; i < size; i++) {
        //回調
        listeners.get(i).onPaused(r.activity);
    }

    return !r.activity.mFinished && saveState ? r.state : null;
}

performPauseActivity整體的邏輯很清晰,就是調用Activity生命周期中對應的接口,同時通知觀察者Activity paused。

現在我們將視線移回到AMS,看看定義於其中的activityPaused函數。

public final void activityPaused(IBinder token) {
    final long origId = Binder.clearCallingIdentity();
    synchronized(this) {
        ActivityStack stack = ActivityRecord.getStackLocked(token);
        if (stack != null) {
            stack.activityPausedLocked(token, false);
        }
    }
    Binder.restoreCallingIdentity(origId);
}

從上面的代碼可以看出,activityPaused的主要工作將交給ActivityStack的activityPausedLocked函數:

final void activityPausedLocked(IBinder token, boolean timeout) {
    ...............
    final ActivityRecord r = isInStackLocked(token);
    if (r != null) {
        //從消息隊列中移除該事件
        mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
        if (mPausingActivity == r) {
            ..............
            completePauseLocked(true);
            return;
        } else {
            ................
        }
    }
    ...............
}

上述代碼中的completePauseLocked函數,將負責完成本次中斷Activity的剩餘的工作,同時重新進入啟動Activity的流程。

//此處resumeNext的值為true
private void completePauseLocked(boolean resumeNext) {
    ActivityRecord prev = mPausingActivity;
    ..................
    if (prev != null) {
        final boolean wasStopping = prev.state == ActivityState.STOPPING;
        prev.state = ActivityState.PAUSED;
        if (prev.finishing) {
            ................
            //如果已經進入finishing狀態,調用finishCurrentActivityLocked(本流程中,Activity還沒有finishing)
            //此處參數為FINISH_AFTER_VISIBLE,僅將Activity加入到mStoppingActivities中
            prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
        } else if (prev.app != null) {
            .................
            //將Activity從等待可見的Activity中移除
            if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
                ...................
            }
            if (prev.deferRelaunchUntilPaused) {
                .............
            } else if (wasStopping) {
                .............
            } else if ((!prev.visible && !hasVisibleBehindActivity())
                    || mService.isSleepingOrShuttingDownLocked()) {
                // If we were visible then resumeTopActivities will release resources before
                // stopping.
                //如果Activity變為不可見時,才會進入此分支,本流程實際上不會直接進入該分支
                //但當Activity真的不見瞭,ActivityStack將調用makeInvisible,重新對中斷Activity調用addToStopping函數
                //將暫停的Activity保存mStoppingActivities中
                addToStopping(prev, true /* immediate */);
            }
        } else {
            ..................
        }
        ..........

        //將mPausingActivity置為null
        mPausingActivity = null;
    }

    if (resumeNext) {
        final ActivityStack topStack = mStackSupervisor.getFocusedStack();
        if (!mService.isSleepingOrShuttingDownLocked()) {
            //將重新開始啟動前臺棧頂的Activity,由於此時mResumedActivity為null,於是進入到啟動目標Activity的流程
            mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
        } else {
            ..............
        }
    }

    if (prev != null) {
        //將啟動新的Activity,可以恢復事件分發
        prev.resumeKeyDispatchingLocked();
        ..................
    }
    ................
}

這部分代碼的主要工作是:
1、若中斷的Activity變為不可見時,調用addToStopping函數,將中斷的Activity加入到mStoppingActivities;
2、將mPausingActivity置為null後,重新進入啟動目標Activity的流程。

雖然本流程不會直接調用addToStopping函數,但我們還是進一步看看,中斷之後的Activity變為不可見後將如何被AMS處理。

三、addToStopping函數

//此流程中immediate的值為true
private void addToStopping(ActivityRecord r, boolean immediate) {
    if (!mStackSupervisor.mStoppingActivities.contains(r)) {
        mStackSupervisor.mStoppingActivities.add(r);
    }

    // If we already have a few activities waiting to stop, then give up
    // on things going idle and start clearing them out. Or if r is the
    // last of activity of the last task the stack will be empty and must
    // be cleared immediately.
    // 原生中MAX_STOPPING_TO_FORCE的值為3
    boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE
            || (r.frontOfTask && mTaskHistory.size() <= 1);

    if (immediate || forceIdle) {
        ............
        //ActivityStackSupervisor發送消息IDLE_NOW_MSG,最終由activityIdleInternalLocked函數處理
        mStackSupervisor.scheduleIdleLocked();
    } else {
        ................
    }
}

從上面的代碼,可以看出啟動Activity和中斷Activity的最後一部均是調用activityIdleInternalLocked函數,
我們看看該函數中處理中斷的Activity相關的流程:

//中斷Activity時,fromTimeout的值為true
final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
        Configuration config) {
    ...............
    ActivityRecord r = ActivityRecord.forTokenLocked(token);
    if (r != null) {
        .........
        if (fromTimeout) {
            //該函數中也會調用mService.notifyAll(),因此會喚醒等待Activity啟動的ActivityStarter
            //但ActivityStarter會檢測到目標Activity還未可見,因此會重新進入等待狀態
            reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
        }
        .........
    }
    .........
    // Atomically retrieve all of the other things to do.
    final ArrayList stops = processStoppingActivitiesLocked(true);
    NS = stops != null ? stops.size() : 0;
    ..........
    // Stop any activities that are scheduled to do so but have been
    // waiting for the next one to start.
    for (int i = 0; i < NS; i++) {
        r = stops.get(i);
        final ActivityStack stack = r.task.stack;
        if (stack != null) {
            if (r.finishing) {
                stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
            } else {
                //調用ActivityStack的stopActivityLocked函數
                stack.stopActivityLocked(r);
            }
        }
    }
    //AMS處理無用的進程等
    ...............
}

跟進一下ActivityStack的stopActivityLocked函數:

final void stopActivityLocked(ActivityRecord r) {
    ..............
    //如果Activity攜帶瞭FLAG_ACTIVITY_NO_HISTORY,那麼當這個Activity結束時,將從Task中被移除掉
    if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
            || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
        if (!r.finishing) {
            if (!mService.isSleepingLocked()) {
                ...........
                //將destroy該Activity
                if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
                        "stop-no-history", false)) {
                    ...............
                }
            } else {
                ..........
            }
        }
    }


    if (r.app != null && r.app.thread != null) {
        ...........
        try {
            ...................
            r.stopped = false;
            //狀態更新為stopping
            r.state = ActivityState.STOPPING;
            ...................
            //調用ApplicationThread的scheduleStopActivity接口
            //將由ActivityThread的handleStopActivity函數進行實際的操作
            r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
            .............
            //發送超時信息,處理該消息時,將調用activityStoppedLocked函數
            Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
            mHandler.sendMessageDelayed(msg, STOP_TIMEOUT);
        } catch (Exception e) {
            .......
        }
    }
}

這一部分最終還是需要依賴於進程的ActivityThread的handleStopActivity函數:

private void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) {
    ActivityClientRecord r = mActivities.get(token);
    .............
    //StopInfo是一個Runnable對象
    StopInfo info = new StopInfo();
    //調用Activity的onStop等接口
    performStopActivityInner(r, info, show, true, "handleStopActivity");
    .............
    //更新可見性
    updateVisibility(r, show);
    .............
    //StopInfo的run函數將被調用
    mH.post(info);
    mSomeActivitiesChanged = true;
}

private static class StopInfo implements Runnable {
    ............
    @Override public void run() {
        // Tell activity manager we have been stopped.
        try {
            ..........
            //通知AMS進行掃尾工作
            ActivityManagerNative.getDefault().activityStopped(
                    activity.token, state, persistentState, description);
        } catch (RemoteException ex) {
            ..........
        }
    }
}

最後看一下AMS的activityStopped函數:

public final void activityStopped(.....) {
    ...........
    synchronized (this) {
        ActivityRecord r = ActivityRecord.isInStackLocked(token);
        if (r != null) {
            //調用ActivityStack的activityStoppedLocked函數
            r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);
        }
    }

    //移除無用進程
    trimApplications();
    ...........
}

跟進ActivityStack的activityStoppedLocked函數:

final void activityStoppedLocked(........) {
    ........
    if (!r.stopped) {
        ............
        mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
        r.stopped = true;
        //變為stopped狀態
        r.state = ActivityState.STOPPED;
        ............
    }
}

由此可見,當中斷的Activity變為完全不可見後,它的onStop函數才會被調用。

四、總結

startPausingLocked的分析告一段落,這部分內容在瞭解整個Activity的啟動流程後,還是比較好理解的。
主要就是調用前一個Activity的onPause等接口,使其處於中斷狀態,然後再進入到啟動新Activity的流程中。
此外,當被中斷的Activity變為完全不可見,將調用其onStop接口。

You May Also Like