Activity相关学习-finish activity

前言

前面大致整理了startActivity的相关流程,下面整理下Activity finish相关的流程

Activity finish流程

Activity#finish

首先客户端调用finish方法,触发finish的流程

/**
 * Finishes the current activity and specifies whether to remove the task associated with this
 * activity.
 */
private void finish(int finishTask) {
    if (mParent == null) {
        int resultCode;
        Intent resultData;
        synchronized (this) {
            resultCode = mResultCode;
            resultData = mResultData;
        }
        if (false) Log.v(TAG, "Finishing self: token=" + mToken);
        try {
            if (resultData != null) {
                resultData.prepareToLeaveProcess(this);
            }
            if (ActivityManager.getService()
                    .finishActivity(mToken, resultCode, resultData, finishTask)) {
                mFinished = true;
            }
        } catch (RemoteException e) {
            // Empty
        }
    } else {
        mParent.finishFromChild(this);
    }

    // Activity was launched when user tapped a link in the Autofill Save UI - Save UI must
    // be restored now.
    if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
        getAutofillManager().onPendingSaveUi(AutofillManager.PENDING_UI_OPERATION_RESTORE,
                mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN));
    }
}

ActivityManagerService#finishActivity


/**
 * This is the internal entry point for handling Activity.finish().
 *
 * @param token The Binder token referencing the Activity we want to finish.
 * @param resultCode Result code, if any, from this Activity.
 * @param resultData Result data (Intent), if any, from this Activity.
 * @param finishTask Whether to finish the task associated with this Activity.
 *
 * @return Returns true if the activity successfully finished, or false if it is still running.
 */
@Override
public final boolean finishActivity(IBinder token, int resultCode, Intent resultData,
        int finishTask) {
    // Refuse possible leaked file descriptors
    if (resultData != null && resultData.hasFileDescriptors() == true) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }

    synchronized(this) {
        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.getTask();
        ActivityRecord rootR = tr.getRootActivity();
        if (rootR == null) {
            Slog.w(TAG, "Finishing task with all activities already finished");
        }
        // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
        // finish.
        if (mLockTaskController.activityBlockedFromFinish(r)) {
            return false;
        }

        if (mController != null) {  
            // Find the first activity that is not finishing.
            ActivityRecord next = r.getStack().topRunningActivityLocked(token, 0);
            if (next != null) {
                // ask watcher if this is allowed
                boolean resumeOK = true;
                try {
                    resumeOK = mController.activityResuming(next.packageName);
                } catch (RemoteException e) {
                    mController = null;
                    Watchdog.getInstance().setActivityController(null);
                }

                if (!resumeOK) {
                    Slog.i(TAG, "Not finishing activity because controller resumed");
                    return false;
                }
            }
        }
        final long origId = Binder.clearCallingIdentity();
        try {
            boolean res;
            final boolean finishWithRootActivity =
                    finishTask == Activity.FINISH_TASK_WITH_ROOT_ACTIVITY;
            if (finishTask == Activity.FINISH_TASK_WITH_ACTIVITY
                    || (finishWithRootActivity && r == rootR)) { //这里是finishTask with Activity或者with root Activity
                // If requested, remove the task that is associated to this activity only if it
                // was the root activity in the task. The result code and data is ignored
                // because we don't support returning them across task boundaries. Also, to
                // keep backwards compatibility we remove the task from recents when finishing
                // task with root activity.
                res = mStackSupervisor.removeTaskByIdLocked(tr.taskId, false,
                        finishWithRootActivity, "finish-activity"); //因为finish Activity导致的remove task
                if (!res) {
                    Slog.i(TAG, "Removing task failed to finish activity");
                }
            } else {
                res = tr.getStack().requestFinishActivityLocked(token, resultCode,
                        resultData, "app-request", true); //调用ActiviyStack的requestFinishActivityLocked
                if (!res) {
                    Slog.i(TAG, "Failed to finish by app-request");
                }
            }
            return res;
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
}

ActivityStack#requestFinishActivityLocked

3583    /**
3584     * @return Returns true if the activity is being finished, false if for
3585     * some reason it is being left as-is.
3586     */
3587    final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3588            Intent resultData, String reason, boolean oomAdj) {
3589        ActivityRecord r = isInStackLocked(token);
3590        if (DEBUG_RESULTS || DEBUG_STATES) Slog.v(TAG_STATES,
3591                "Finishing activity token=" + token + " r="
3592                + ", result=" + resultCode + ", data=" + resultData
3593                + ", reason=" + reason);
3594        if (r == null) {
3595            return false;
3596        }
3597
3598        finishActivityLocked(r, resultCode, resultData, reason, oomAdj);
3599        return true;
3600    }

ActivityStack#finishActivityLocked

/**
 * See {@link #finishActivityLocked(ActivityRecord, int, Intent, String, boolean, boolean)}
 */
final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
        String reason, boolean oomAdj) {
    return finishActivityLocked(r, resultCode, resultData, reason, oomAdj, !PAUSE_IMMEDIATELY);
}
/**
 * @return Returns true if this activity has been removed from the history
 * list, or false if it is still in the list and will be removed later.
 */
final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData,
        String reason, boolean oomAdj, boolean pauseImmediately) {
    if (r.finishing) {
        Slog.w(TAG, "Duplicate finish request for " + r);
        return false;
    }

    mWindowManager.deferSurfaceLayout();
    try {
        r.makeFinishingLocked(); //将Ativity对应的finishing属性置为true
        final TaskRecord task = r.getTask();
        EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                r.app != null ? r.app.pid : 0, System.identityHashCode(r),
                task.taskId, r.shortComponentName, reason); //打印event log
        final ArrayList<ActivityRecord> activities = task.mActivities;
        final int index = activities.indexOf(r);
        if (index < (activities.size() - 1)) { //如果要finish的Activity不是task顶部的Activity
            task.setFrontOfTask();
            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
                // If the caller asked that this activity (and all above it)
                // be cleared when the task is reset, don't lose that information,
                // but propagate it up to the next activity.
                ActivityRecord next = activities.get(index+1);
                next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
            }
        }

        r.pauseKeyDispatchingLocked();

        adjustFocusedActivityStack(r, "finishActivity"); //调整focus activityStack(当前stack 调用topRunningActivityLocked为null,即当前stack中的所有task中的Activity没有正在running的,那么此Activity不能再做前台,要移到后面)

        finishActivityResultsLocked(r, resultCode, resultData);  //如果要finish的Activity有resultTo,向其传递result

        final boolean endTask = index <= 0 && !task.isClearingToReuseTask(); //是否要销毁task(当要销毁的Activity在task中的index<=0)
        final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE;
        if (mResumedActivity == r) {
            if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                    "Prepare close transition: finishing " + r);
            if (endTask) {
                mService.mTaskChangeNotificationController.notifyTaskRemovalStarted(
                        task.taskId);
            }
            mWindowManager.prepareAppTransition(transit, false);

            // Tell window manager to prepare for this one to be removed.
            r.setVisibility(false);

            if (mPausingActivity == null) {
                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
                if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                        "finish() => pause with userLeaving=false");
                startPausingLocked(false, false, null, pauseImmediately); //调用startPausingLocked,finish之前需要先pause,注意resuming为null
            }

            if (endTask) {
                mService.getLockTaskController().clearLockedTask(task);
            }
        } else if (!r.isState(PAUSING)) { //这种情况是finish的不是resumed Activity的情况
            // If the activity is PAUSING, we will complete the finish once
            // it is done pausing; else we can just directly finish it here.
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
            if (r.visible) {
                prepareActivityHideTransitionAnimation(r, transit);
            }

            final int finishMode = (r.visible || r.nowVisible) ? FINISH_AFTER_VISIBLE
                    : FINISH_AFTER_PAUSE;
            final boolean removedActivity = finishCurrentActivityLocked(r, finishMode, oomAdj,
                    "finishActivityLocked") == null; //也是调用finishCurrentActivityLocked

            // The following code is an optimization. When the last non-task overlay activity
            // is removed from the task, we remove the entire task from the stack. However,
            // since that is done after the scheduled destroy callback from the activity, that
            // call to change the visibility of the task overlay activities would be out of
            // sync with the activitiy visibility being set for this finishing activity above.
            // In this case, we can set the visibility of all the task overlay activities when
            // we detect the last one is finishing to keep them in sync.
            if (task.onlyHasTaskOverlayActivities(true /* excludeFinishing */)) {
                for (ActivityRecord taskOverlay : task.mActivities) {
                    if (!taskOverlay.mTaskOverlay) {
                        continue;
                    }
                    prepareActivityHideTransitionAnimation(taskOverlay, transit);
                }
            }
            return removedActivity;
        } else {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
        }

        return false;
    } finally {
        mWindowManager.continueSurfaceLayout();
    }
}
ActivityStack#adjustFocusedActivityStack
private void adjustFocusedActivityStack(ActivityRecord r, String reason) {
    if (!mStackSupervisor.isFocusedStack(this) ||
            ((mResumedActivity != r) && (mResumedActivity != null))) {
        return;
    }

    final ActivityRecord next = topRunningActivityLocked();
    final String myReason = reason + " adjustFocus";

    if (next == r) {
        mStackSupervisor.moveFocusableActivityStackToFrontLocked(
                mStackSupervisor.topRunningActivityLocked(), myReason);
        return;
    }

    if (next != null && isFocusable()) { //当stack中没有top running Activity的情况时才需要移动focus Activity Stack
        // Keep focus in stack if we have a top running activity and are focusable.
        return;
    }

    // Task is not guaranteed to be non-null. For example, destroying the
    // {@link ActivityRecord} will disassociate the task from the activity.
    final TaskRecord task = r.getTask();

    if (task == null) {
        throw new IllegalStateException("activity no longer associated with task:" + r);
    }

    // Move focus to next focusable stack if possible.
    if (adjustFocusToNextFocusableStack(myReason)) { //将focus焦点移到下一个focusable stack上
        return;
    }

    // Whatever...go home.
    mStackSupervisor.moveHomeStackTaskToTop(myReason);
}

调用了startPausingLocked完成要finish的Activity的pause操作,此时其状态为PAUSING,然后
调用activityPaused,completePauseLocked这里逻辑(可能pause超时,也可能未超时,都会调用到completePauseLocked):

ActivityStack#completePauseLocked

private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
    ActivityRecord prev = mPausingActivity;
    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);

    if (prev != null) {
        prev.setWillCloseOrEnterPip(false);
        final boolean wasStopping = prev.isState(STOPPING);
        prev.setState(PAUSED, "completePausedLocked"); //变为paused状态
        if (prev.finishing) {
            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
            prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
                    "completedPausedLocked"); //如果是在finish的流程中的话,会调用到这里
        }
   ...
  }
  ...
  //调用完 finishCurrentActivityLocked之后,还需要接着调用completePauseLocked,保证finish Activity之后有一个新的resumed Activity
  if (resumeNext) {
    final ActivityStack topStack = mStackSupervisor.getFocusedStack();
    if (!topStack.shouldSleepOrShutDownActivities()) {
        mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
    } else {
        checkReadyForSleep();
        ActivityRecord top = topStack.topRunningActivityLocked();
        if (top == null || (prev != null && top != prev)) {
            // If there are no more activities available to run, do resume anyway to start
            // something. Also if the top activity on the stack is not the just paused
            // activity, we need to go ahead and resume it to ensure we complete an
            // in-flight app switch.
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
        }
    }
}

ActivityStack#finishCurrentActivityLocked

finish top Activity时,先将其通过addToStopping加入到mStackSupervisor.mStoppingActivities队列中,后续会再次调用activityIdleInternalLocked中再次调用finishCurrentActivityLocked,从而走到destroyActivityLocked中

final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj,
        String reason) {
    // First things first: if this activity is currently visible,
    // and the resumed activity is not yet visible, then hold off on
    // finishing until the resumed one becomes visible.

    // The activity that we are finishing may be over the lock screen. In this case, we do not
    // want to consider activities that cannot be shown on the lock screen as running and should
    // proceed with finishing the activity if there is no valid next top running activity.
    final ActivityRecord next = mStackSupervisor.topRunningActivityLocked(
            true /* considerKeyguardState */); //next = MainActivity

    if (mode == FINISH_AFTER_VISIBLE && (r.visible || r.nowVisible)
                 && next != null && !next.nowVisible) {
        if (!mStackSupervisor.mStoppingActivities.contains(r)) {
            addToStopping(r, false /* scheduleIdle */, false /* idleDelayed */); //调用到这里,将被finish的Activity放到mstoppingActivties中,发送IDLE_NOW_MSG消息
        }
        if (DEBUG_STATES) Slog.v(TAG_STATES,
                "Moving to STOPPING: "+ r + " (finish requested)");

        if (mActivityPluginDelegate != null && getWindowingMode() != WINDOWING_MODE_UNDEFINED) {
            mActivityPluginDelegate.activitySuspendNotification
                (r.appInfo.packageName, getWindowingMode() == WINDOWING_MODE_FULLSCREEN, false);
        }

        r.setState(STOPPING, "finishCurrentActivityLocked"); //finish Activity变为stopping模式
        if (oomAdj) {
            mService.updateOomAdjLocked();
        }
        return r;
    }

    // make sure the record is cleaned out of other places.
    mStackSupervisor.mStoppingActivities.remove(r);
    mStackSupervisor.mGoingToSleepActivities.remove(r);
    mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(r);
    final ActivityState prevState = r.getState();
    if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);

    if (mActivityPluginDelegate != null && getWindowingMode() != WINDOWING_MODE_UNDEFINED) {
        mActivityPluginDelegate.activitySuspendNotification
            (r.appInfo.packageName, getWindowingMode() == WINDOWING_MODE_FULLSCREEN, false);
    }

    r.setState(FINISHING, "finishCurrentActivityLocked");
    final boolean finishingActivityInNonFocusedStack
            = r.getStack() != mStackSupervisor.getFocusedStack()
            && prevState == PAUSED && mode == FINISH_AFTER_VISIBLE;

    if (mode == FINISH_IMMEDIATELY
            || (prevState == PAUSED
                && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
            || finishingActivityInNonFocusedStack
            || prevState == STOPPING
            || prevState == STOPPED
            || prevState == ActivityState.INITIALIZING) {
        r.makeFinishingLocked();
        boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason);

        if (finishingActivityInNonFocusedStack) {
            // Finishing activity that was in paused state and it was in not currently focused
            // stack, need to make something visible in its place.
            mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
                    false /* markFrozenIfConfigChanged */, true /* deferResume */);
        }
        if (activityRemoved) {
            mStackSupervisor.resumeFocusedStackTopActivityLocked();
        }
        if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
                "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
                " destroy returned removed=" + activityRemoved);
        return activityRemoved ? null : r;
    }

    // Need to go through the full pause cycle to get this
    // activity into the stopped state and then finish it.
   //第三种情况,加入到mStackSupervisor.mFinishingActivities队列;看注释是先pause,stop再finish,走完整个流程
    if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
    mStackSupervisor.mFinishingActivities.add(r);
    r.resumeKeyDispatchingLocked();
    mStackSupervisor.resumeFocusedStackTopActivityLocked();
    return r;
}

刚刚把要finish的Activity加入到mStopping队列中了,通过activityIdleInternalLocked处理(有3种调用可能,如当新resume的Activity不在idle状态时,addToStopping中发送的IDLE_NOW_MSG消息也可以调用activityIdleInternalLocked)

ActivityStackSupervisor#activityIdleInternalLocked

当resume Activity进程的ActviityThread处于idle状态调用activityIdleInternalLocked时,其参数token不为null;当AMS的ActviityManager线程执行消息时,token的值为null

2015    // Checked.
2016    @GuardedBy("mService")
2017    final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
2018            boolean processPausingActivities, Configuration config) {
2019        if (DEBUG_ALL) Slog.v(TAG, "Activity idle: " + token);
2020
2021        ArrayList<ActivityRecord> finishes = null;
2022        ArrayList<UserState> startingUsers = null;
2023        int NS = 0;
2024        int NF = 0;
2025        boolean booting = false;
2026        boolean activityRemoved = false;
2027
2028        ActivityRecord r = ActivityRecord.forTokenLocked(token);
2029        if (r != null) {
2030            if (DEBUG_IDLE) Slog.d(TAG_IDLE, "activityIdleInternalLocked: Callers="
2031                    + Debug.getCallers(4));
2032            mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
2033            r.finishLaunchTickingLocked();
2034            if (fromTimeout) {
2035                reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
2036            }
2037
2038            // This is a hack to semi-deal with a race condition
2039            // in the client where it can be constructed with a
2040            // newer configuration from when we asked it to launch.
2041            // We'll update with whatever configuration it now says
2042            // it used to launch.
2043            if (config != null) {
2044                r.setLastReportedGlobalConfiguration(config);
2045            }
2046
2047            // We are now idle.  If someone is waiting for a thumbnail from
2048            // us, we can now deliver.
2049            r.idle = true;
2050
2051            //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
2052            if (isFocusedStack(r.getStack()) || fromTimeout) {
2053                booting = checkFinishBootingLocked();
2054            }
2055        }
2056
2057        if (allResumedActivitiesIdle()) {
2058            if (r != null) {
2059                mService.scheduleAppGcsLocked();
2060            }
2061
2062            if (mLaunchingActivity.isHeld()) {
2063                mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
2064                if (VALIDATE_WAKE_LOCK_CALLER &&
2065                        Binder.getCallingUid() != Process.myUid()) {
2066                    throw new IllegalStateException("Calling must be system uid");
2067                }
2068                mLaunchingActivity.release();
2069            }
2070            ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
2071        }
2072
2073        // Atomically retrieve all of the other things to do.
2074        final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r,
2075                true /* remove */, processPausingActivities); 
2076        NS = stops != null ? stops.size() : 0;
2077        if ((NF = mFinishingActivities.size()) > 0) {
2078            finishes = new ArrayList<>(mFinishingActivities);
2079            mFinishingActivities.clear();
2080        }
2081
2082        if (mStartingUsers.size() > 0) {
2083            startingUsers = new ArrayList<>(mStartingUsers);
2084            mStartingUsers.clear();
2085        }
2086
2087        // Stop any activities that are scheduled to do so but have been
2088        // waiting for the next one to start.
2089        for (int i = 0; i < NS; i++) {
2090            r = stops.get(i);
2091            final ActivityStack stack = r.getStack();
2092            if (stack != null) {
2093                if (r.finishing) {
2094                    stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
2095                            "activityIdleInternalLocked"); //再次调用finishCurrentActivityLocked方法
2096                } else {
2097                    stack.stopActivityLocked(r);
2098                }
2099            }
2100        }
2101
2102        // Finish any activities that are scheduled to do so but have been
2103        // waiting for the next one to start.
2104        for (int i = 0; i < NF; i++) {
2105            r = finishes.get(i);
2106            final ActivityStack stack = r.getStack();
2107            if (stack != null) {
2108                activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle");
2109            }
2110        }
2111
2112        if (!booting) {
2113            // Complete user switch
2114            if (startingUsers != null) {
2115                for (int i = 0; i < startingUsers.size(); i++) {
2116                    mService.mUserController.finishUserSwitch(startingUsers.get(i));
2117                }
2118            }
2119        }
2120
2121        mService.trimApplications();
2122        //dump();
2123        //mWindowManager.dump();
2124
2125        if (activityRemoved) {
2126            resumeFocusedStackTopActivityLocked();
2127        }
2128
2129        return r;
2130    }

第二次调用finishCurrentActivityLocked时会走到

if (mode == FINISH_IMMEDIATELY //这个条件就已经满足了
        || (prevState == PAUSED
            && (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
        || finishingActivityInNonFocusedStack
        || prevState == STOPPING
        || prevState == STOPPED
        || prevState == ActivityState.INITIALIZING) {
    r.makeFinishingLocked();
    boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm:" + reason);
   //调用destroyActivityLocked方法

    if (finishingActivityInNonFocusedStack) {
        // Finishing activity that was in paused state and it was in not currently focused
        // stack, need to make something visible in its place.
        mStackSupervisor.ensureVisibilityAndConfig(next, mDisplayId,
                false /* markFrozenIfConfigChanged */, true /* deferResume */); 
    }
    if (activityRemoved) {
        mStackSupervisor.resumeFocusedStackTopActivityLocked();
    }
    if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
            "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
            " destroy returned removed=" + activityRemoved);
    return activityRemoved ? null : r;
}

ActivityStack#destroyActivityLocked

/**
 * Destroy the current CLIENT SIDE instance of an activity.  This may be
 * called both when actually finishing an activity, or when performing
 * a configuration switch where we destroy the current client-side object
 * but then create a new client-side object for this same HistoryRecord.
 */
final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
    if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(TAG_SWITCH,
            "Removing activity from " + reason + ": token=" + r
                    + ", app=" + (r.app != null ? r.app.processName : "(null)"));

    if (r.isState(DESTROYING, DESTROYED)) {
        if (DEBUG_STATES) Slog.v(TAG_STATES, "activity " + r + " already destroying."
                + "skipping request with reason:" + reason);
        return false;
    }

    EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
            r.app != null ? r.app.pid : 0, System.identityHashCode(r),
            r.getTask().taskId, r.shortComponentName, reason);

    boolean removedFromHistory = false;

    cleanUpActivityLocked(r, false, false); //第一次调用cleanServices = false; setState = false;

    final boolean hadApp = r.app != null;

    if (hadApp) { 
        if (removeFromApp) {  //将activity从其依赖的进程中删除
            r.app.activities.remove(r);
            if (mService.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) {
                mService.mHeavyWeightProcess = null;
                mService.mHandler.sendEmptyMessage(
                        ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG);
            }
            if (r.app.activities.isEmpty()) {
                // Update any services we are bound to that might care about whether
                // their client may have activities.
                mService.mServices.updateServiceConnectionActivitiesLocked(r.app); 
                // No longer have activities, so update LRU list and oom adj.
                mService.updateLruProcessLocked(r.app, false, null);
                mService.updateOomAdjLocked(); //进程中的app的Activity空了,要重新调整进程优先级
            }
        }

        boolean skipDestroy = false;

        try {
            if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
            mService.getLifecycleManager().scheduleTransaction(r.app.thread, r.appToken,
                    DestroyActivityItem.obtain(r.finishing, r.configChangeFlags)); //执行DestroyActivityItem的excute
        } catch (Exception e) {
            // We can just ignore exceptions here...  if the process
            // has crashed, our death notification will clean things
            // up.
            //Slog.w(TAG, "Exception thrown during finish", e);
            if (r.finishing) {
                removeActivityFromHistoryLocked(r, reason + " exceptionInScheduleDestroy");
                removedFromHistory = true;
                skipDestroy = true;
            }
        }

        r.nowVisible = false; //nowVisible属性置为false

        // If the activity is finishing, we need to wait on removing it
        // from the list to give it a chance to do its cleanup.  During
        // that time it may make calls back with its token so we need to
        // be able to find it on the list and so we don't want to remove
        // it from the list yet.  Otherwise, we can just immediately put
        // it in the destroyed state since we are not removing it from the
        // list.
        if (r.finishing && !skipDestroy) {
            if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYING: " + r
                    + " (destroy requested)");
            r.setState(DESTROYING,
                    "destroyActivityLocked. finishing and not skipping destroy"); //将Activity的state属性设为destorying
            Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG, r);
            mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT); //为activity设置超时处理操作
        } else {
            if (DEBUG_STATES) Slog.v(TAG_STATES,
                    "Moving to DESTROYED: " + r + " (destroy skipped)");
            r.setState(DESTROYED,
                    "destroyActivityLocked. not finishing or skipping destroy");
            if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + r);
            r.app = null;
        }
    } else {
        // remove this record from the history.
        if (r.finishing) {
            resumeTopActivityInnerLocked(r, reason + " hadNoApp");
            removedFromHistory = true;
        } else {
            if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + r + " (no app)");
            r.setState(DESTROYED, "destroyActivityLocked. not finishing and had no app");
            if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + r);
            r.app = null;
        }
    }

    r.configChangeFlags = 0;

    if (!mLRUActivities.remove(r) && hadApp) {
        Slog.w(TAG, "Activity " + r + " being finished, but not in LRU list");
    }

    return removedFromHistory;
}
ActivityStack#cleanUpActivityLocked

Perform the common clean-up of an activity record 两种情况下可能调用 1. destroyActivityLocked 2. Activity宿主进程消失(被杀)

/**
 * Perform the common clean-up of an activity record.  This is called both
 * as part of destroyActivityLocked() (when destroying the client-side
 * representation) and cleaning things up as a result of its hosting
 * processing going away, in which case there is no remaining client-side
 * state to destroy so only the cleanup here is needed.
 *
 * Note: Call before #removeActivityFromHistoryLocked.
 */
private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) { 
    onActivityRemovedFromStack(r);

    r.deferRelaunchUntilPaused = false;
    r.frozenBeforeDestroy = false;

    if (setState) {
        if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + r + " (cleaning up)");
        r.setState(DESTROYED, "cleanupActivityLocked");
        if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + r);
        r.app = null;
    }

    // Inform supervisor the activity has been removed.
    mStackSupervisor.cleanupActivity(r);


    // Remove any pending results.
    if (r.finishing && r.pendingResults != null) {
        for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
            PendingIntentRecord rec = apr.get();
            if (rec != null) {
                mService.cancelIntentSenderLocked(rec, false);
            }
        }
        r.pendingResults = null;
    }

    if (cleanServices) {
        cleanUpActivityServicesLocked(r);
    }

    // Get rid of any pending idle timeouts.
    removeTimeoutsForActivityLocked(r);
    // Clean-up activities are no longer relaunching (e.g. app process died). Notify window
    // manager so it can update its bookkeeping.
    mWindowManager.notifyAppRelaunchesCleared(r.appToken);
}
ActivityStack#onActivityRemovedFromStack

当Activity从stack移除前都要调用

/**
 * Remove any state associated with the {@link ActivityRecord}. This should be called whenever
 * an activity moves away from the stack.
 */
void onActivityRemovedFromStack(ActivityRecord r) {
    removeTimeoutsForActivityLocked(r);

    if (mResumedActivity != null && mResumedActivity == r) {
        setResumedActivity(null, "onActivityRemovedFromStack");
    }
    if (mPausingActivity != null && mPausingActivity == r) {
        mPausingActivity = null;
    }
}
DestroyActivityItem#execute
public class DestroyActivityItem extends ActivityLifecycleItem {

    private boolean mFinished;
    private int mConfigChanges;

    @Override
    public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
        client.handleDestroyActivity(token, mFinished, mConfigChanges,
                false /* getNonConfigInstance */, "DestroyActivityItem");
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    }
ActivityThread#handleDestroyActivity
@Override
public void handleDestroyActivity(IBinder token, boolean finishing, int configChanges,
        boolean getNonConfigInstance, String reason) {
    ActivityClientRecord r = performDestroyActivity(token, finishing,
            configChanges, getNonConfigInstance, reason);
    if (r != null) {
        cleanUpPendingRemoveWindows(r, finishing);
        WindowManager wm = r.activity.getWindowManager();
        View v = r.activity.mDecor;
        if (v != null) {
            if (r.activity.mVisibleFromServer) {
                mNumVisibleActivities--;
            }
            IBinder wtoken = v.getWindowToken();
            if (r.activity.mWindowAdded) {
                if (r.mPreserveWindow) {
                    // Hold off on removing this until the new activity's
                    // window is being added.
                    r.mPendingRemoveWindow = r.window;
                    r.mPendingRemoveWindowManager = wm;
                    // We can only keep the part of the view hierarchy that we control,
                    // everything else must be removed, because it might not be able to
                    // behave properly when activity is relaunching.
                    r.window.clearContentView();
                } else {
                    wm.removeViewImmediate(v);
                }
            }
            if (wtoken != null && r.mPendingRemoveWindow == null) {
                WindowManagerGlobal.getInstance().closeAll(wtoken,
                        r.activity.getClass().getName(), "Activity");
            } else if (r.mPendingRemoveWindow != null) {
                // We're preserving only one window, others should be closed so app views
                // will be detached before the final tear down. It should be done now because
                // some components (e.g. WebView) rely on detach callbacks to perform receiver
                // unregister and other cleanup.
                WindowManagerGlobal.getInstance().closeAllExceptView(token, v,
                        r.activity.getClass().getName(), "Activity");
            }
            r.activity.mDecor = null;
        }
        if (r.mPendingRemoveWindow == null) {
            // If we are delaying the removal of the activity window, then
            // we can't clean up all windows here.  Note that we can't do
            // so later either, which means any windows that aren't closed
            // by the app will leak.  Well we try to warning them a lot
            // about leaking windows, because that is a bug, so if they are
            // using this recreate facility then they get to live with leaks.
            WindowManagerGlobal.getInstance().closeAll(token,
                    r.activity.getClass().getName(), "Activity");
        }

        // Mocked out contexts won't be participating in the normal
        // process lifecycle, but if we're running with a proper
        // ApplicationContext we need to have it tear down things
        // cleanly.
        Context c = r.activity.getBaseContext();
        if (c instanceof ContextImpl) {
            ((ContextImpl) c).scheduleFinalCleanup(
                    r.activity.getClass().getName(), "Activity");
        }
    }
    if (finishing) {
        try {
            ActivityManager.getService().activityDestroyed(token); //调用AMS的activityDestroyed
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
    mSomeActivitiesChanged = true;
}

注意,当下方的activity重新resume时,还有机会调用activityIdleInternalLocked操作,但此时似乎没什么作用

ActivityManagerService#activityDestroyed
8347    @Override
8348    public final void activityDestroyed(IBinder token) {
8349        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "ACTIVITY DESTROYED: " + token);
8350        synchronized (this) {
8351            ActivityStack stack = ActivityRecord.getStackLocked(token);
8352            if (stack != null) {
8353                stack.activityDestroyedLocked(token, "activityDestroyed");
8354            }
8355        }
8356    }
ActivityStack#activityDestroyedLocked
4468    final void activityDestroyedLocked(IBinder token, String reason) {
4469        final long origId = Binder.clearCallingIdentity();
4470        try {
4471            activityDestroyedLocked(ActivityRecord.forTokenLocked(token), reason);
4472        } finally {
4473            Binder.restoreCallingIdentity(origId);
4474        }
4475    }
4477    /**
4478     * This method is to only be called from the client via binder when the activity is destroyed
4479     * AND finished.
4480     */
4481    final void activityDestroyedLocked(ActivityRecord record, String reason) {
4482        if (record != null) {
4483            mHandler.removeMessages(DESTROY_TIMEOUT_MSG, record);
4484        }
4485
4486        if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + record);
4487
4488        if (isInStackLocked(record) != null) {
4489            if (record.isState(DESTROYING, DESTROYED)) {
4490                cleanUpActivityLocked(record, true, false); //再次调用cleanUpActivityLocked;第二次调用cleanServices = true;setState = false
4491                removeActivityFromHistoryLocked(record, reason);
4492            }
4493        }
4494
4495        mStackSupervisor.resumeFocusedStackTopActivityLocked(); 
           //还会在调用一次resumeFocusedStackTopActivityLocked
4496    }

此时,cleanUpActivityLocked->cleanUpActivityServicesLocked

ActivityStack#cleanUpActivityServicesLocked
/**
 * Perform clean-up of service connections in an activity record.
 */
private 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;
    }
}
ActivityStack#removeActivityFromHistoryLocked
private void removeActivityFromHistoryLocked(ActivityRecord r, String reason) {
    finishActivityResultsLocked(r, Activity.RESULT_CANCELED, null);
    r.makeFinishingLocked();
    if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
            "Removing activity " + r + " from stack callers=" + Debug.getCallers(5));

    r.takeFromHistory();
    removeTimeoutsForActivityLocked(r);
    if (DEBUG_STATES) Slog.v(TAG_STATES,
            "Moving to DESTROYED: " + r + " (removed from history)");
    r.setState(DESTROYED, "removeActivityFromHistoryLocked"); //设为destoryed属性
    if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + r);
    r.app = null; //依赖app进程赋为空
    r.removeWindowContainer(); //将ActivityRecord的mWindowContainerController置为true
    final TaskRecord task = r.getTask();
    final boolean lastActivity = task != null ? task.removeActivity(r) : false; //如果要finish的Activity是task的root Activity
    // If we are removing the last activity in the task, not including task overlay activities,
    // then fall through into the block below to remove the entire task itself
    final boolean onlyHasTaskOverlays = task != null
            ? task.onlyHasTaskOverlayActivities(false /* excludingFinishing */) : false;

    if (lastActivity || onlyHasTaskOverlays) {
        if (DEBUG_STACK) {
            Slog.i(TAG_STACK,
                    "removeActivityFromHistoryLocked: last activity removed from " + this
                            + " onlyHasTaskOverlays=" + onlyHasTaskOverlays);
        }

        // The following block can be executed multiple times if there is more than one overlay.
        // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
        // of the task by id and exiting early if not found.
        if (onlyHasTaskOverlays) {
            // When destroying a task, tell the supervisor to remove it so that any activity it
            // has can be cleaned up correctly. This is currently the only place where we remove
            // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
            // state into removeTask(), we just clear the task here before the other residual
            // work.
            // TODO: If the callers to removeTask() changes such that we have multiple places
            //       where we are destroying the task, move this back into removeTask()
            mStackSupervisor.removeTaskByIdLocked(task.taskId, false /* killProcess */,
                    !REMOVE_FROM_RECENTS, PAUSE_IMMEDIATELY, reason);
        }

        // We must keep the task around until all activities are destroyed. The following
        // statement will only execute once since overlays are also considered activities.
        if (lastActivity) { //如果是最后一个activity,调用removeTask
            removeTask(task, reason, REMOVE_TASK_MODE_DESTROYING);
        }
    }
    cleanUpActivityServicesLocked(r);
    r.removeUriPermissionsLocked();
}
ActivityRecord#takeFromHistory
void takeFromHistory() {
    if (this.inHistory) {
        this.inHistory = false;
        if (this.task != null && !this.finishing) {
            --this.task.numActivities;
        }

        this.clearOptionsLocked();
    }

}
ActivityStack#removeTimeoutsForActivityLocked
void removeTimeoutsForActivityLocked(ActivityRecord r) {
    mStackSupervisor.removeTimeoutsForActivityLocked(r);
    mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
    mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
    mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
    r.finishLaunchTickingLocked();
}
ActivityStack#removeTask
/**
 * Removes the input task from this stack.
 * @param task to remove.
 * @param reason for removal.
 * @param mode task removal mode. Either {@link #REMOVE_TASK_MODE_DESTROYING},
 *             {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}.
 */
void removeTask(TaskRecord task, String reason, int mode) {
    for (ActivityRecord record : task.mActivities) {
        onActivityRemovedFromStack(record);
    }

    final boolean removed = mTaskHistory.remove(task); //从stack中的mTaskHistory中将task移除

    if (removed) {
        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, task.taskId, getStackId()); 
    }

    removeActivitiesFromLRUListLocked(task);
    updateTaskMovement(task, true);

    if (mode == REMOVE_TASK_MODE_DESTROYING && task.mActivities.isEmpty()) {
        // TODO: VI what about activity?
        final boolean isVoiceSession = task.voiceSession != null;
        if (isVoiceSession) {
            try {
                task.voiceSession.taskFinished(task.intent, task.taskId);
            } catch (RemoteException e) {
            }
        }
        if (task.autoRemoveFromRecents() || isVoiceSession) {
            // Task creator asked to remove this when done, or this task was a voice
            // interaction, so it should not remain on the recent tasks list.
            mStackSupervisor.mRecentTasks.remove(task);
        }

        task.removeWindowContainer();
    }

    if (mTaskHistory.isEmpty()) { //当stack中没有了task时
        if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
        // We only need to adjust focused stack if this stack is in focus and we are not in the
        // process of moving the task to the top of the stack that will be focused.
        if (isOnHomeDisplay() && mode != REMOVE_TASK_MODE_MOVING_TO_TOP
                && mStackSupervisor.isFocusedStack(this)) {
            String myReason = reason + " leftTaskHistoryEmpty";
            if (!inMultiWindowMode() || !adjustFocusToNextFocusableStack(myReason)) {
                mStackSupervisor.moveHomeStackToFront(myReason);
            }
        }
        if (isAttached()) {
            getDisplay().positionChildAtBottom(this); //将stack放到display底部
        }
        if (!isActivityTypeHome()) {
            remove();
        }
    }

    task.setStack(null);

    // Notify if a task from the pinned stack is being removed (or moved depending on the mode)
    if (inPinnedWindowingMode()) {
        mService.mTaskChangeNotificationController.notifyActivityUnpinned();
    }
}
ActivityStackSupervisor#resumeFocusedStackTopActivityLocked
    boolean resumeFocusedStackTopActivityLocked() {
        return resumeFocusedStackTopActivityLocked(null, null, null);
    }
ActivityStackSupervisor#resumeFocusedStackTopActivityLocked
   boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {

        if (!readyToResume()) {
            return false;
        }

        // if resume one non-fullscreen task, also resume the other one
        boolean resumed = false;
        if (targetStack != null && isFocusedStack(targetStack)) {
            if (target != null && target.getState() == RESUMED && mNeedScheduleIdle) {
                scheduleIdleLocked();
                mNeedScheduleIdle = false;
                if (target.getTask().inMultiWindowMode()) {
                    return false;
                }
            }
            resumed = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        } else {
            ActivityStack recentsStack = getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_RECENTS);
            if (mLaunchRecentsFromGesture && recentsStack != null && !mHasResumeRecentsBehind
                    && !mStopLaunchRecentsBehind) {
                recentsStack.resumeTopActivityUncheckedLocked(null, null);
            } else {
                final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
                if (r == null || r.getState() != RESUMED) {
                    mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
                } else if (r.getState() == RESUMED) {
                    //此时下一个top Activity应该已经处于resumed的状态,直接返回false即可 
                    if (!r.getTask().inMultiWindowMode()) {
                        mFocusedStack.executeAppTransition(targetOptions);
                    }
                    if (mNeedScheduleIdle) {
                        scheduleIdleLocked();
                        mNeedScheduleIdle = false;
                    }
                    return false;
                }
            }
        }
        // resume non-fullscreen task
        if (mFocusedStack.topTask() != null && mFocusedStack.topTask().inMultiWindowMode()
                && !mService.isSleepingOrShuttingDownLocked()) {
            ActivityStack multiWindowStack = null;
            if (mFocusedStack.inSplitScreenPrimaryWindowingMode()) {
                multiWindowStack = mFocusedStack.getDisplay().getTopStackInWindowingMode(
                        WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
            } else if (mFocusedStack.inSplitScreenSecondaryWindowingMode()) {
                multiWindowStack = mFocusedStack.getDisplay().getTopStackInWindowingMode(
                        WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
            }

            if (multiWindowStack != null
                    && multiWindowStack.shouldBeVisible(null)) {
                final ActivityRecord r = multiWindowStack.topRunningActivityLocked();
                if (r != null && r.getState() != RESUMED && r.getTask().inMultiWindowMode()) {
                    multiWindowStack.resumeTopActivityUncheckedLocked(null, null);
                }
            }
        }
        return resumed;
    }
finish Activity.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容