Android系統源碼分析--Activity的finish過程

上一篇咱們分析了Activity的啓動流程,因爲代碼量很大,仍是沒有分析的很詳細,可是基本流程都出來了,更詳細的東西仍是要去看源碼,源碼在我文章的最後有給出,裏面有我添加的詳細的註釋。這一章來分析Activity的finish過程,這個問題在兩年前我去面試金山的時候曾經被問到過,那時候對源碼基本沒什麼瞭解,因此當時根本是不瞭解的,今天咱們就來分析一下finish的過程到底作了哪些處理,最後對Activity的整個啓動過程以及finish過程繪製流程圖,以方便咱們記憶。java

finish代碼分析

首先先貼一張時序圖:git

Activity的finish方法就是調用的父類的finish方法:github

Step1.Activity.finish

public void finish() {
        finish(DONT_FINISH_TASK_WITH_ACTIVITY);
    }
複製代碼

這裏調用finish方法,傳入參數DONT_FINISH_TASK_WITH_ACTIVITY,這個參數是在finish掉Activity的時候不finish掉Task。面試

Step2.Activity.finish

private void finish(int finishTask) {
        ...
                if (ActivityManagerNative.getDefault()
                        .finishActivity(mToken, resultCode, resultData, finishTask)) {
                    mFinished = true;
                }
        ...
    }
複製代碼

ActivityManagerNative.getDefault()方法其實咱們在前面文章提到過,獲得的是AMP(ActivityManagerProxy)。微信

Step3.AMP.finishActivity

public boolean finishActivity(IBinder token, int resultCode, Intent resultData, int finishTask) throws RemoteException {
        ...
        mRemote.transact(FINISH_ACTIVITY_TRANSACTION, data, reply, 0);
        ...
    }
複製代碼

經過Binder調用AMS的finishActivity方法。app

Step4.AMS.finishActivity

public final boolean finishActivity(IBinder token, int resultCode, Intent resultData, int finishTask) {
        ...
        synchronized (this) {
            // 根據token(IBinder)獲取Activity的對象封裝ActivityRecord
            ActivityRecord r = ActivityRecord.isInStackLocked(token);
            if (r == null) {
                return true;
            }
            // Keep track of the root activity of the task before we finish it
            TaskRecord tr = r.task;
            // 從棧底部獲取第一沒有被finish的Activity對象封裝
            ActivityRecord rootR = tr.getRootActivity();
            ...
            if (mController != null) {
                // Find the first activity that is not finishing.
                // 獲取第一個沒有被回收的Activity
                ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
                if (next != null) {
                    ...
                }
            }
            final long origId = Binder.clearCallingIdentity();
            try {
                // 傳入的finishTask是DONT_FINISH_TASK_WITH_ACTIVITY,因此下面參數是false
                final boolean finishWithRootActivity =
                        finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
                // 這裏if中條件爲false因此走else語句
                if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
                        || (finishWithRootActivity && r == rootR)) {
                    res = removeTaskByIdLocked(tr.taskId, false, finishWithRootActivity);
                    ...
                } else {
                    res = tr.stack.requestFinishActivityLocked(token, resultCode,
                            resultData, "app-request", true);
                    ...
                }
                return res;
            } finally {
               ...
            }
        }
    }
複製代碼

上面try語句中會走else語句中的方法也就是ActivityStack.requestFinishActivityLockedide

Step5.ActivityStack.requestFinishActivityLocked

final boolean requestFinishActivityLocked(IBinder token, int resultCode, Intent resultData, String reason, boolean oomAdj) {
        ActivityRecord r = isInStackLocked(token);
        ...

        finishActivityLocked(r, resultCode, resultData, reason, oomAdj);
        return true;
    }
複製代碼

調用finishActivityLocked方法工具

Step6.ActivityStack.finishActivityLocked

final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData, String reason, boolean oomAdj) {
        if (r.finishing) {// 若是要清理的的正在finish,則不須要再清理
            Slog.w(TAG, "Duplicate finish request for " + r);
            return false;
        }

        // 標記開始finish
        r.makeFinishingLocked();
        ...

        // 中止鍵盤分發事件
        r.pauseKeyDispatchingLocked();

        adjustFocusedActivityLocked(r, "finishActivity");

        finishActivityResultsLocked(r, resultCode, resultData);

        // 若是任務中沒有了Activity要結束任務
        final boolean endTask = index <= 0;
        final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;
        if (mResumedActivity == r) {// 若是當前顯示的Activity就是要結束的Activity

            ...

            if (mPausingActivity == null) {
                // 開始暫停Activity
                startPausingLocked(false, false, null, false);
            }

            if (endTask) {// 若是任務中沒有了Activity,則移除任務
                mStackSupervisor.removeLockedTaskLocked(task);
            }
        } else if (r.state != ActivityState.PAUSING) {// 若是要移除的Activity不是Pausing狀態而且不是正在顯示的Activity
            ...
            return finishCurrentActivityLocked(r, (r.visible || r.nowVisible) ?
                    FINISH_AFTER_VISIBLE : FINISH_AFTER_PAUSE, oomAdj) == null;
        } else {
            ...
        }

        return false;
    }
複製代碼

這裏首先調用ActivityRecord.makeFinishingLocked標記開始結束Activity,而後調用ActivityRecord.pauseKeyDispatchingLocked方法中止鍵盤事件分發。而後調用adjustFocusedActivityLocked方法,調整Activity的焦點狀體。開發工具

Step7.ActivityStack.adjustFocusedActivityLocked

private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
        // 若是當前棧沒有焦點,或者當前Activity也不是當前有焦點的Activity,返回
        if (!mStackSupervisor.isFocusedStack(this) || mService.mFocusedActivity != r) {
            return;
        }

        // 獲取棧頂正在運行的Activity
        final ActivityRecord next = topRunningActivityLocked();
        final String myReason = reason + " adjustFocus";
        if (next != r) {// 若是棧頂正在運行的不是當前要結束的Activity
            if (next != null && StackId.keepFocusInStackIfPossible(mStackId) && isFocusable()) {
                mService.setFocusedActivityLocked(next, myReason);
                return;
            } else {
                final TaskRecord task = r.task;
                if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
                    final int taskToReturnTo = task.getTaskToReturnTo();
                    if (!mFullscreen
                            && adjustFocusToNextFocusableStackLocked(taskToReturnTo, myReason)) {
                        return;
                    }
                    if (mStackSupervisor.moveHomeStackTaskToTop(taskToReturnTo, myReason)) {
                        return;
                    }
                }
            }
        }

        mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked(), myReason);
    }
複製代碼

當前Activity要finish掉,就找找到下一個應該獲取焦點的Activity,在該Activity被finish掉以後顯示出來。ui

Step8.ActivityStack.finishActivityResultsLocked

final void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
        // send the result
        ActivityRecord resultTo = r.resultTo;
        if (resultTo != null) {
            ...
            resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
                    resultData);
            r.resultTo = null;
        } else if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "No result destination from " + r);

        ...
    }
複製代碼

若是要接收Result的Activity描述對象ActivityRecord還存在,就將result相關信息封裝成ActivityResult對象放到ActivityResult列表中保存起來。而後置空該Activity對應的ActivityRecord對象中的信息。

Step9.ActivityStack.startPausingLocked

final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, ActivityRecord resuming, boolean dontWait) {
        if (mPausingActivity != null) {
            Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
                    + " state=" + mPausingActivity.state);
            if (!mService.isSleepingLocked()) {// 若是沒有在睡眠,則完成Pause狀態
                completePauseLocked(false, resuming);
            }
        }
        // prev指向源Activity
        ActivityRecord prev = mResumedActivity;
        if (prev == null) {
            if (resuming == null) {
                Slog.wtf(TAG, "Trying to pause when nothing is resumed");
                mStackSupervisor.resumeFocusedStackTopActivityLocked();
            }
            return false;
        }

        if (mActivityContainer.mParentActivity == null) {
            // Top level stack, not a child. Look for child stacks.
            // 暫停全部子棧的Activity
            mStackSupervisor.pauseChildStacks(prev, userLeaving, uiSleeping, resuming, dontWait);
        }

        ...
        // 改變狀態
        prev.state = ActivityState.PAUSING;
        ...
        // 獲取正在啓動的Activity組件
        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
        ...

        if (prev.app != null && prev.app.thread != null) {
            ...
                // 通知源Activity組件,暫停源Activity以便有機會執行一些數據保存操做,
                // 這裏若是目標sdk<11會調用onSaveInstanceState,而後調用onPause
                prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
                        userLeaving, prev.configChangeFlags, dontWait);
            ...
        } else {
            ...
        }

        ...
    }
複製代碼

這裏主要是在finish以前pause該Activity,若是狀態正常會調用schedulePauseActivity方法,最終調用Activity的onPause方法,這個過程咱們在前面講過幾回了,這裏就再也不分析,比較簡單。咱們接着看核心的代碼。

Step10.ActivityStack.finishCurrentActivityLocked

final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj) {
        // 若是當前要finish的Activity正在顯示,而複用的Activity尚未顯示,那麼延遲finish,
        // 直到複用Activity顯示

        // 獲取頂部正在運行的Activity
        final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();

        // 若是是顯示後在finish,而且要結束的正在顯示或者將要顯示,而且頂部運行的存在並且沒有顯示
        if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible)
                && next != null && !next.nowVisible) {
            // 若是當前要結束的Activity不在正在中止列表中則添加到中止列表中
            if (!mStackSupervisor.mStoppingActivities.contains(r)) {
                addToStopping(r, false /* immediate */);
            }
            ...
            return r;
        }

        // make sure the record is cleaned out of other places.
        // 從各個列表中清理這個將要被finish的Activity
        ...
        final ActivityState prevState = r.state;// 存儲清理以前的狀態
        r.state = ActivityState.FINISHING;// 設置爲正在finish狀態
        // 判斷當前正在清理的Activity是否在當前獲取焦點的棧中
        final boolean finishingActivityInNonFocusedStack
                = r.task.stack != mStackSupervisor.getFocusedStack()
                && prevState == ActivityState.PAUSED && mode == FINISH_AFTER_VISIBLE;

        if (mode == FINISH_IMMEDIATELY
                || (prevState == ActivityState.PAUSED
                && (mode == FINISH_AFTER_PAUSE || mStackId == PINNED_STACK_ID))
                || finishingActivityInNonFocusedStack
                || prevState == ActivityState.STOPPED
                || prevState == ActivityState.INITIALIZING) {
            ...
            // 銷燬Activity
            boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");

            ...
            return activityRemoved ? null : r;
        }

        ...
        return r;
    }
複製代碼

這裏是開始銷燬Activity,首先要保存狀態,而後標記開始finish,而後調用destroyActivityLocked方法開始銷燬。

Step11.ActivityStack.destroyActivityLocked

final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
        ...

        // 清理Activity
        cleanUpActivityLocked(r, false, false);

        final boolean hadApp = r.app != null;

        if (hadApp) {
           ...

            boolean skipDestroy = false;

            try {
                r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
                        r.configChangeFlags);
            } catch (Exception e) {
                ...
            }

            ...

        return removedFromHistory;
    }
複製代碼

這裏主要有兩部操做,第一步是cleanUpActivityLocked,第二步是scheduleDestroyActivity。咱們先看第一步。

Step12.ActivityStack.cleanUpActivityLocked

final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) {
        if (mResumedActivity == r) {
            mResumedActivity = null;
        }
        if (mPausingActivity == r) {
            mPausingActivity = null;
        }
        mService.resetFocusedActivityIfNeededLocked(r);

        ...

        // Make sure this record is no longer in the pending finishes list.
        // This could happen, for example, if we are trimming activities
        // down to the max limit while they are still waiting to finish.
        mStackSupervisor.mFinishingActivities.remove(r);
        mStackSupervisor.mWaitingVisibleActivities.remove(r);

        ...

        if (cleanServices) {// 是否清理服務
            cleanUpActivityServicesLocked(r);
        }

        ...
    }
複製代碼

這裏主要是將指向該銷燬的Activity的引用都置空,進行釋放,而後將該Activity描述對象從列表中移除該對象,最後是判斷是否清理服務,其實主要是綁定該Activity的服務,若是有綁定則解除綁定。

Step13.ActivityManagerService.resetFocusedActivityIfNeededLocked

// 從新設置獲取焦點的Activity,若是被清理的不是獲取焦點的,那麼不處理,不然將焦點移動到另一個Activity
    final void resetFocusedActivityIfNeededLocked(ActivityRecord goingAway) {
        ...

        // Try to move focus to another activity if possible.
        // 若是容許,將焦點移動到另一個Activity
        if (setFocusedActivityLocked(
                focusedStack.topRunningActivityLocked(), "resetFocusedActivityIfNeeded")) {
            return;
        }

        ...
    }
複製代碼

這裏調用setFocusedActivityLocked方法判斷該Activity是否是容許容許將焦點移除。

Step14.ActivityManagerService.setFocusedActivityLocked

boolean setFocusedActivityLocked(ActivityRecord r, String reason) {
        if (r == null || mFocusedActivity == r) {// 若是傳入的焦點Activity不存在或者就是顯示在有焦點的Activity則不須要處理了
            return false;
        }

        if (!r.isFocusable()) {// 若是沒有獲取焦點,返回
            return false;
        }

        ...

        // 獲取以前有焦點的Activity
        final ActivityRecord last = mFocusedActivity;
        mFocusedActivity = r;// 設置傳入的Activity爲當前焦點Activity
        if (r.task.isApplicationTask()) {// 當前焦點Activity所在任務是應用任務(不是桌面和最近應用界面)
            if (mCurAppTimeTracker != r.appTimeTracker) {
                ...
            } else {
                startTimeTrackingFocusedActivityLocked();
            }
        } else {
            r.appTimeTracker = null;
        }
        ...
        // 將要啓動的Activity移動到前臺
        if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
            mWindowManager.setFocusedApp(r.appToken, true);
        }
        ...
        return true;
    }
複製代碼

這裏看一下注釋,主要是判斷該Activity是否有焦點,是否容許切換焦點。所以要結束的Activity就要把焦點釋放掉。

Step15.ActivityStack.cleanUpActivityServicesLocked

final void cleanUpActivityServicesLocked(ActivityRecord r) {
        // Throw away any services that have been bound by this activity.
        if (r.connections != null) {
            Iterator<ConnectionRecord> it = r.connections.iterator();
            while (it.hasNext()) {
                ConnectionRecord c = it.next();
                mService.mServices.removeConnectionLocked(c, null, r);
            }
            r.connections = null;
        }
    }
複製代碼

上面咱們提到這個方法主要是釋放綁定的服務,若是沒有則不須要釋放。下面咱們回到Step11中提到的第二步。

Step16.ApplicationThreadNative.scheduleDestroyActivity

public final void scheduleDestroyActivity(IBinder token, boolean finishing, int configChanges) throws RemoteException {
        ...
        mRemote.transact(SCHEDULE_FINISH_ACTIVITY_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
        ..
    }
複製代碼

這個很熟悉了。

Step17.ApplicationThread.scheduleDestroyActivity

public final void scheduleDestroyActivity(IBinder token, boolean finishing, int configChanges) {
            sendMessage(H.DESTROY_ACTIVITY, token, finishing ? 1 : 0,
                    configChanges);
        }
複製代碼

經過發送消息到Handler中來處理。

Step18.ActivityThread.H.handleMessage

public void handleMessage(Message msg) {
            switch (msg.what) {
            ...
                case DESTROY_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
                    handleDestroyActivity((IBinder) msg.obj, msg.arg1 != 0,
                            msg.arg2, false);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
            ...
複製代碼

Step19.ActivityThread.handleDestroyActivity

private void handleDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance) {
        ActivityClientRecord r = performDestroyActivity(token, finishing,
                configChanges, getNonConfigInstance);
        ...
        if (finishing) {
            try {
                ActivityManagerNative.getDefault().activityDestroyed(token);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
        mSomeActivitiesChanged = true;
    }
複製代碼

Step20.ActivityThread.performDestroyActivity

private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing, int configChanges, boolean getNonConfigInstance) {
        ActivityClientRecord r = mActivities.get(token);
        Class<? extends Activity> activityClass = null;
        if (localLOGV) Slog.v(TAG, "Performing finish of " + r);
        if (r != null) {
            ...

            performPauseActivityIfNeeded(r, "destroy");

            ...
            
            try {
                r.activity.mCalled = false;
                mInstrumentation.callActivityOnDestroy(r.activity);
                ...
            } catch (SuperNotCalledException e) {
                throw e;
            } catch (Exception e) {
                ...
            }
        }
        ...
        return r;
    }
複製代碼

執行performPauseActivityIfNeeded,而後執行Instrumentation.callActivityOnDestroy方法結束。

Step21.ActivityThread.performPauseActivityIfNeeded

private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
        if (r.paused) {
            // You are already paused silly...
            return;
        }

        try {
            r.activity.mCalled = false;
            mInstrumentation.callActivityOnPause(r.activity);
            ...
        } catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
            ...
        }
        r.paused = true;
    }
複製代碼

若是已經paused了,則直接返回,不然調用Instrumentation.callActivityOnPause方法。

Step22.Instrumentation.callActivityOnPause

public void callActivityOnPause(Activity activity) {
        activity.performPause();
    }
複製代碼

Step23.Activity.performPause

final void performPause() {
        ..
        onPause();
        ...
    }
複製代碼

Step24.Activity.onPause

protected void onPause() {
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this);
        getApplication().dispatchActivityPaused(this);
        mCalled = true;
    }
複製代碼

這裏就是調用了Activity的onPause方法了。

Step25.Activity.performStop

final void performStop(boolean preserveWindow) {
        ...

        if (!mStopped) {
            ...

            mCalled = false;
            mInstrumentation.callActivityOnStop(this);
            ...
        }
        mResumed = false;
    }
複製代碼

這裏調用Instrumentation.callActivityOnStop方法,這裏原本還有Fragment的處理,我略掉了,本身看看。

Step26.Instrumentation.callActivityOnStop

public void callActivityOnStop(Activity activity) {
        activity.onStop();
    }
複製代碼

這裏調用了Activity的onStop方法。代碼略了。

Step28.Instrumentation.callActivityOnDestroy

public void callActivityOnDestroy(Activity activity) {
      ...
      
      activity.performDestroy();
      
      ...
   }
複製代碼

調用Activity的performDestroy方法

Step29.Activity.performDestroy

final void performDestroy() {
        ...
        onDestroy();
        ...
    }
複製代碼

這裏終於看到了onDestroy方法。這裏還有Fragment的處理,我沒有顯示出來,本身看看。咱們再回到Step20中的第二個方法中。

Step31.AMP.activityDestroyed

public void activityDestroyed(IBinder token) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(token);
        mRemote.transact(ACTIVITY_DESTROYED_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
        reply.readException();
        data.recycle();
        reply.recycle();
    }
複製代碼

而後調用AMS中的activityDestroyed方法。

Step32.AMS.activityDestroyed

public final void activityDestroyed(IBinder token) {
        synchronized (this) {
            ActivityStack stack = ActivityRecord.getStackLocked(token);
            if (stack != null) {
                stack.activityDestroyedLocked(token, "activityDestroyed");
            }
        }
    }
複製代碼

Step33.ActivityStack.activityDestroyedLocked

final void activityDestroyedLocked(IBinder token, String reason) {
        final long origId = Binder.clearCallingIdentity();
        try {
            ActivityRecord r = ActivityRecord.forTokenLocked(token);
            ...

            if (isInStackLocked(r) != null) {
                if (r.state == ActivityState.DESTROYING) {
                    cleanUpActivityLocked(r, true, false);
                    removeActivityFromHistoryLocked(r, null, reason);
                }
            }
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
複製代碼

這裏主要是兩步,第一個是調用cleanUpActivityLocked方法,清理Activity,前面Step12咱們分析過了,再也不分析。而後是調用removeActivityFromHistoryLocked方法,就是將該結束的Activity從歷史列表中刪除.

Step35.ActivityStack.removeActivityFromHistoryLocked

// 從歷史記錄移除
    private void removeActivityFromHistoryLocked( ActivityRecord r, TaskRecord oldTop, String reason) {
        mStackSupervisor.removeChildActivityContainers(r);
        finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
        ...
        if (task != null && task.removeActivity(r)) {
            if (mStackSupervisor.isFocusedStack(this) && task == topTask &&
                    task.isOverHomeStack()) {
                mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(), reason);
            }
            removeTask(task, reason);
        }
        cleanUpActivityServicesLocked(r);
        r.removeUriPermissionsLocked();
    }
複製代碼

調用finishActivityResultsLocked方法處理Result,前面提到了。調用ActivityStackSupervisor.moveHomeStackTaskToTop將Home屬性的Activity所在任務棧放到頂部。調用cleanUpActivityServicesLocked清理綁定的服務。

Step39.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked

boolean resumeFocusedStackTopActivityLocked() {
        return resumeFocusedStackTopActivityLocked(null, null, null);
    }
複製代碼

這裏咱們在上一章Activity的啓動時已經分析過了。這裏再也不分析。到這裏Activity的finish就分析完了,從這裏咱們主要學到的是finish的過程,以及finish過程當中系統作了哪些處理,咱們在寫代碼過程當中應該作那些處理。

流程圖:

代碼地址:

直接拉取導入開發工具(Intellij idea或者Android studio)

Android_Framework_Source

注:

首發地址:www.codemx.cn

Android開發羣:192508518

微信公衆帳號:Code-MX

注:本文原創,轉載請註明出處,多謝。

相關文章
相關標籤/搜索