Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 223b6b3b authored by Craig Mautner's avatar Craig Mautner Committed by Android (Google) Code Review
Browse files

Merge "Begin switch over to task based history."

parents f025404a 5d9c7be8
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -471,6 +471,7 @@ final class ActivityRecord {
    void setTask(TaskRecord newTask, ThumbnailHolder newThumbHolder, boolean isRoot) {
        if (inHistory && !finishing) {
            if (task != null) {
                task.removeActivity(this);
                task.numActivities--;
            }
            if (newTask != null) {
@@ -505,6 +506,7 @@ final class ActivityRecord {
            inHistory = false;
            if (task != null && !finishing) {
                task.numActivities--;
                task = null;
            }
            clearOptionsLocked();
        }
@@ -539,7 +541,7 @@ final class ActivityRecord {
        ActivityResult r = new ActivityResult(from, resultWho,
        		requestCode, resultCode, resultData);
        if (results == null) {
            results = new ArrayList();
            results = new ArrayList<ResultInfo>();
        }
        results.add(r);
    }
@@ -950,6 +952,8 @@ final class ActivityRecord {
        StringBuilder sb = new StringBuilder(128);
        sb.append("ActivityRecord{");
        sb.append(Integer.toHexString(System.identityHashCode(this)));
        sb.append(" t");
        sb.append(task.taskId);
        sb.append(" u");
        sb.append(userId);
        sb.append(' ');
+329 −11
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -66,6 +67,7 @@ import android.os.UserHandle;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;

import java.io.FileDescriptor;
@@ -75,6 +77,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

/**
 * State and management of a single stack of activities.
@@ -98,6 +101,7 @@ final class ActivityStack {
    static final boolean DEBUG_APP = false;

    static final boolean VALIDATE_TOKENS = ActivityManagerService.VALIDATE_TOKENS;
    static final boolean VALIDATE_TASK_REPLACE = true;

    // How long we wait until giving up on the last activity telling us it
    // is idle.
@@ -138,6 +142,9 @@ final class ActivityStack {
    // is being started.
    static final boolean SHOW_APP_STARTING_PREVIEW = true;

    static final boolean FORWARD_ITERATOR = false;
    static final boolean REVERSE_ITERATOR = true;

    enum ActivityState {
        INITIALIZING,
        RESUMED,
@@ -161,6 +168,17 @@ final class ActivityStack {
     */
    private final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();

    /**
     * The back history of all previous (and possibly still
     * running) activities.  It contains #TaskRecord objects.
     */
    private ArrayList<TaskRecord> mTaskHistory = new ArrayList<TaskRecord>();

    /**
     * Mapping from taskId to TaskRecord
     */
    private SparseArray<TaskRecord> mTaskIdToTaskRecord = new SparseArray<TaskRecord>();

    /**
     * Used for validating app tokens with window manager.
     */
@@ -289,6 +307,12 @@ final class ActivityStack {
     */
    boolean mDismissKeyguardOnNextActivity = false;

    /** So we don't have to keep constructing a new object for utility non-nested use. */
    final ActivityIterator mTmpActivityIterator = new ActivityIterator(FORWARD_ITERATOR, true);

    /** So we don't have to keep constructing a new object for utility non-nested use. */
    final TaskIterator mTmpTaskIterator = new TaskIterator();

    /**
     * Save the most recent screenshot for reuse. This keeps Recents from taking two identical
     * screenshots, one for the Recents thumbnail and one for the pauseActivity thumbnail.
@@ -508,29 +532,68 @@ final class ActivityStack {
    }

    final ActivityRecord isInStackLocked(IBinder token) {
        ActivityRecord newAr = newIsInStackLocked(token);

        ActivityRecord r = ActivityRecord.forToken(token);
        if (mHistory.contains(r)) {
            if (VALIDATE_TASK_REPLACE && newAr != r) Slog.w(TAG,
                    "isInStackLocked: mismatch: newAr=" + newAr + " r=" + r);
            return r;
        }
        if (VALIDATE_TASK_REPLACE && newAr != null) Slog.w(TAG,
                "isInStackLocked: mismatch: newAr!=null");
        return null;
    }

    final ActivityRecord newIsInStackLocked(IBinder token) {
        final ActivityRecord r = ActivityRecord.forToken(token);
        if (r != null) {
            final TaskRecord task = r.task;
            if (mTaskHistory.contains(task) && task.mActivities.contains(r)) {
                return r;
            }
        }
        return null;
    }

    int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
        int newTaskId = newGetTaskForActivityLocked(token, onlyRoot);

        TaskRecord lastTask = null;
        final int N = mHistory.size();
        for (int i = 0; i < N; i++) {
            ActivityRecord r = mHistory.get(i);
            if (r.appToken == token) {
                if (!onlyRoot || lastTask != r.task) {
                    if (VALIDATE_TASK_REPLACE && newTaskId != r.task.taskId) Slog.w(TAG,
                            "getTaskForActivityLocked: mismatch: new=" + newTaskId
                            + " taskId=" + r.task.taskId);
                    return r.task.taskId;
                }
                if (VALIDATE_TASK_REPLACE && newTaskId != -1) Slog.w(TAG,
                    "getTaskForActivityLocked: mismatch: newTaskId=" + newTaskId + " not -1.");
                return -1;
            }
            lastTask = r.task;
        }

        if (VALIDATE_TASK_REPLACE && newTaskId != -1) Slog.w(TAG,
            "getTaskForActivityLocked: mismatch at end: newTaskId=" + newTaskId + " not -1.");
        return -1;
    }

    int newGetTaskForActivityLocked(IBinder token, boolean onlyRoot) {
        final ActivityRecord r = ActivityRecord.forToken(token);
        if (r == null) {
            return -1;
        }
        final TaskRecord task = r.task;
        switch (task.mActivities.indexOf(r)) {
            case -1: return -1;
            case 0: return task.taskId;
            default: return onlyRoot ? -1 : task.taskId;
        }
    }

    private final boolean updateLRUListLocked(ActivityRecord r) {
        final boolean hadit = mLRUActivities.remove(r);
@@ -624,17 +687,29 @@ final class ActivityStack {
     * @return whether there are any activities for the specified user.
     */
    final boolean switchUserLocked(int userId, UserStartedState uss) {
        if (VALIDATE_TOKENS) {
            validateAppTokensLocked();
        }
        final boolean newResult = newSwitchUserLocked(userId, uss);

        mCurrentUser = userId;
        mStartingUsers.add(uss);

        // Only one activity? Nothing to do...
        if (mHistory.size() < 2)
        if (mHistory.size() < 2) {
            if (VALIDATE_TASK_REPLACE && newResult) Slog.w(TAG,
                    "switchUserLocked: mismatch: " + newResult + " " + false);
            return false;
        }

        boolean haveActivities = false;
        // Check if the top activity is from the new user.
        ActivityRecord top = mHistory.get(mHistory.size() - 1);
        if (top.userId == userId) return true;
        if (top.userId == userId) {
            if (VALIDATE_TASK_REPLACE && !newResult) Slog.w(TAG,
                    "switchUserLocked: mismatch: " + newResult + " " + true);
            return true;
        }
        // Otherwise, move the user's activities to the top.
        int N = mHistory.size();
        int i = 0;
@@ -651,7 +726,44 @@ final class ActivityStack {
            }
        }
        // Transition from the old top to the new top
        if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
                "switchUserLocked: calling resumeTopActivity " + top);
        resumeTopActivityLocked(top);
        if (VALIDATE_TASK_REPLACE && (newResult != haveActivities)) Slog.w(TAG,
                    "switchUserLocked: mismatch: " + newResult + " " + haveActivities);
        return haveActivities;
    }

    /*
     * Move the activities around in the stack to bring a user to the foreground.
     * @return whether there are any activities for the specified user.
     */
    final boolean newSwitchUserLocked(int userId, UserStartedState uss) {
//        mStartingUsers.add(uss);
        if (mCurrentUser == userId) {
            return true;
        }
        mCurrentUser = userId;

        // Move userId's tasks to the top.
        boolean haveActivities = false;
        TaskRecord task = null;
        int index = mTaskHistory.size();
        for (int i = 0; i < index; ++i) {
            task = mTaskHistory.get(i);
            if (task.userId == userId) {
                haveActivities = true;
                mTaskHistory.remove(i);
                mTaskHistory.add(task);
                --index;
            }
        }

        // task is now the original topmost TaskRecord. Transition from the old top to the new top.
        ActivityRecord top = task != null ? task.getTopActivity() : null;
        if (VALIDATE_TASK_REPLACE) Slog.w(TAG,
                "newSwitchUserLocked: would call resumeTopActivity " + top);
//        resumeTopActivityLocked(top);
        return haveActivities;
    }

@@ -889,6 +1001,9 @@ final class ActivityStack {
            mGoingToSleep.release();
        }
        // Ensure activities are no longer sleeping.
        if (VALIDATE_TASK_REPLACE) {
            verifyActivityRecords();
        }
        for (int i=mHistory.size()-1; i>=0; i--) {
            ActivityRecord r = mHistory.get(i);
            r.setSleeping(false);
@@ -933,6 +1048,9 @@ final class ActivityStack {

            // Make sure any stopped but visible activities are now sleeping.
            // This ensures that the activity's onStop() is called.
            if (VALIDATE_TASK_REPLACE) {
                verifyActivityRecords();
            }
            for (int i=mHistory.size()-1; i>=0; i--) {
                ActivityRecord r = mHistory.get(i);
                if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
@@ -1077,6 +1195,9 @@ final class ActivityStack {
        ActivityRecord r = null;

        synchronized (mService) {
            if (VALIDATE_TASK_REPLACE) {
                verifyActivityRecords();
            }
            int index = indexOfTokenLocked(token);
            if (index >= 0) {
                r = mHistory.get(index);
@@ -1094,6 +1215,9 @@ final class ActivityStack {
        ActivityRecord r = null;

        synchronized (mService) {
            if (VALIDATE_TASK_REPLACE) {
                verifyActivityRecords();
            }
            int index = indexOfTokenLocked(token);
            if (index >= 0) {
                r = mHistory.get(index);
@@ -1306,6 +1430,9 @@ final class ActivityStack {

        // If the top activity is not fullscreen, then we need to
        // make sure any activities under it are now visible.
        if (VALIDATE_TASK_REPLACE) {
            verifyActivityRecords();
        }
        final int count = mHistory.size();
        int i = count-1;
        while (mHistory.get(i) != top) {
@@ -1868,6 +1995,7 @@ final class ActivityStack {
                            Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos,
                                    here);
                        }
                        r.task.addActivityToTop(r);
                        mHistory.add(addPos, r);
                        r.putInHistory();
                        mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
@@ -1907,6 +2035,7 @@ final class ActivityStack {
            here.fillInStackTrace();
            Slog.i(TAG, "Adding activity " + r + " to stack at " + addPos, here);
        }
        r.task.addActivityToTop(r);
        mHistory.add(addPos, r);
        r.putInHistory();
        r.frontOfTask = newTask;
@@ -1986,6 +2115,9 @@ final class ActivityStack {
        if (doResume) {
            resumeTopActivityLocked(null);
        }
        if (VALIDATE_TASK_REPLACE) {
            verifyActivityRecords();
        }
    }

    final void validateAppTokensLocked() {
@@ -2107,8 +2239,8 @@ final class ActivityStack {
                            if (mService.mCurTask <= 0) {
                                mService.mCurTask = 1;
                            }
                            target.setTask(new TaskRecord(mService.mCurTask, target.info, null),
                                    null, false);
                            target.setTask(createTaskRecord(mService.mCurTask, target.info, null,
                                    false), null, false);
                            target.task.affinityIntent = target.intent;
                            if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
                                    + " out to new task " + target.task);
@@ -2172,8 +2304,7 @@ final class ActivityStack {
                            // like these are all in the reply chain.
                            replyChainEnd = targetI+1;
                            while (replyChainEnd < mHistory.size() &&
                                    (mHistory.get(
                                                replyChainEnd)).task == task) {
                                    (mHistory.get(replyChainEnd)).task == task) {
                                replyChainEnd++;
                            }
                            replyChainEnd--;
@@ -2346,6 +2477,9 @@ final class ActivityStack {
            }
        }

        if (VALIDATE_TASK_REPLACE) {
            verifyActivityRecords();
        }
        return taskTop;
    }
    
@@ -3011,7 +3145,7 @@ final class ActivityStack {
                if (mService.mCurTask <= 0) {
                    mService.mCurTask = 1;
                }
                r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);
                r.setTask(createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                        + " in new task " + r.task);
            } else {
@@ -3075,7 +3209,7 @@ final class ActivityStack {
                N > 0 ? mHistory.get(N-1) : null;
            r.setTask(prev != null
                    ? prev.task
                    : new TaskRecord(mService.mCurTask, r.info, intent), null, true);
                    : createTaskRecord(mService.mCurTask, r.info, intent, true), null, true);
            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                    + " in new guessed " + r.task);
        }
@@ -4160,6 +4294,9 @@ final class ActivityStack {
            here.fillInStackTrace();
            Slog.i(TAG, "Removing activity " + r + " from stack");
        }
        if (r.task != null) {
            r.task.removeActivity(r);
        }
        mHistory.remove(r);
        r.takeFromHistory();
        removeTimeoutsForActivityLocked(r);
@@ -5169,4 +5306,185 @@ final class ActivityStack {

        return starting;
    }

    void verifyActivityRecords() {
        /* Until we have activity movement implemented for tasks just do the simple test
        ActivityIterator iterator = new ActivityIterator();
        int i;
        int N = mHistory.size();
        for (i = 0; i < N && iterator.hasNext(); ++i) {
            ActivityRecord r1 = mHistory.get(i);
            ActivityRecord r2 = iterator.next();
            if (r1 != r2) {
                break;
            }
        }
        if (i != N || iterator.hasNext()) {
            Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
                + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
        } */
        // Simple test
        ActivityIterator iterator = new ActivityIterator();
        while (iterator.hasNext()) {
            ActivityRecord r = iterator.next();
            if (!mHistory.contains(r)) {
                break;
            }
        }
        if (iterator.size() != mHistory.size() || iterator.hasNext()) {
            Slog.w(TAG, "verifyActivityRecords mHistory=" + mHistory
                + " mTaskHistory=" + iterator + " Callers=" + Debug.getCallers(2));
        }
    }

    private TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
            boolean toTop) {
        TaskRecord oldTask = mTaskIdToTaskRecord.get(taskId);
        if (oldTask != null) {
            Slog.w(TAG, "createTaskRecord: Reusing taskId=" + taskId + " without removing");
            mTaskHistory.remove(oldTask);
        }
        TaskRecord task = new TaskRecord(taskId, info, intent);
        mTaskIdToTaskRecord.put(taskId, task);
        if (toTop) {
            mTaskHistory.add(task);
        } else {
            mTaskHistory.add(0, task);
        }
        return task;
    }

    class TaskIterator implements Iterator<TaskRecord> {
        private int mCur;
        private boolean mReverse;

        TaskIterator() {
            this(FORWARD_ITERATOR);
        }

        TaskIterator(boolean reverse) {
            reset(reverse);
        }

        public void reset(boolean reverse) {
            mReverse = reverse;
            mCur = reverse ? mTaskHistory.size() - 1 : 0;
        }

        @Override
        public boolean hasNext() {
            if (mReverse) {
                return mCur >= 0;
            }
            return mCur < mTaskHistory.size();
        }

        @Override
        public TaskRecord next() {
            if (hasNext()) {
                TaskRecord task = mTaskHistory.get(mCur);
                mCur += (mReverse ? -1 : 1);
                return task;
            }
            throw new NoSuchElementException();
        }

        @Override
        public void remove() {
            throw new IllegalArgumentException();
        }
    }

    class ActivityIterator implements Iterator<ActivityRecord> {
        final TaskIterator mIterator;
        boolean mReverse;
        int mCur;
        TaskRecord mTaskRecord;
        final boolean mSkipFinishing;

        public ActivityIterator() {
            this(FORWARD_ITERATOR);
        }

        public ActivityIterator(boolean reverse) {
            this(reverse, false);
        }

        public ActivityIterator(boolean reverse, boolean skipFinishing) {
            mSkipFinishing = skipFinishing;
            mIterator = new TaskIterator();
            reset(reverse);
        }

        public void reset(boolean reverse) {
            mReverse = reverse;
            mIterator.reset(reverse);
            getNextTaskRecord();
        }

        private void getNextTaskRecord() {
            if (mIterator.hasNext()) {
                mTaskRecord = mIterator.next();
                mCur = mReverse ? mTaskRecord.mActivities.size() - 1 : 0;
            }
        }

        @Override
        public boolean hasNext() {
            if (mTaskRecord == null) {
                return false;
            }
            if (mReverse) {
                return mCur >= 0;
            }
            return mCur < mTaskRecord.mActivities.size();
        }

        @Override
        public ActivityRecord next() {
            while (hasNext()) {
                ActivityRecord r = mTaskRecord.mActivities.get(mCur);
                mCur += mReverse ? -1 : 1;
                if (!hasNext()) {
                    getNextTaskRecord();
                }
                if (mSkipFinishing && r.finishing) {
                    continue;
                }
                return r;
            }
            throw new NoSuchElementException();
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }

        int size() {
            int size = 0;
            final TaskIterator iterator = new TaskIterator();
            while (iterator.hasNext()) {
                size += iterator.next().mActivities.size();
            }
            return size;
        }

        ActivityRecord peek() {
            if (mTaskRecord != null && mCur >= 0 && mCur < mTaskRecord.mActivities.size()) {
                return mTaskRecord.mActivities.get(mCur);
            }
            return null;
        }

        @Override
        public String toString() {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < mTaskHistory.size(); ++i) {
                final TaskRecord task = mTaskHistory.get(i);
                sb.append("task_").append(i).append("-").append(task.mActivities).append(" ");
            }
            return sb.toString();
        }
    }
}
+53 −7
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.os.UserHandle;
import android.util.Slog;

import java.io.PrintWriter;
import java.util.ArrayList;

class TaskRecord extends ThumbnailHolder {
    final int taskId;       // Unique identifier for this task.
@@ -40,6 +41,10 @@ class TaskRecord extends ThumbnailHolder {
    String stringName;      // caching of toString() result.
    int userId;             // user for which this task was created

    int numFullscreen;      // Number of fullscreen activities.

    final ArrayList<ActivityRecord> mActivities = new ArrayList<ActivityRecord>();

    TaskRecord(int _taskId, ActivityInfo info, Intent _intent) {
        taskId = _taskId;
        affinity = info.taskAffinity;
@@ -105,11 +110,48 @@ class TaskRecord extends ThumbnailHolder {
        }
    }

    ActivityRecord getTopActivity() {
        for (int i = mActivities.size() - 1; i >= 0; --i) {
            final ActivityRecord r = mActivities.get(i);
            if (r.finishing) {
                continue;
            }
            return r;
        }
        return null;
    }

    void addActivityAtBottom(ActivityRecord r) {
        if (!mActivities.remove(r) && r.fullscreen) {
            // Was not previously in list.
            numFullscreen++;
        }
        mActivities.add(0, r);
    }

    void addActivityToTop(ActivityRecord r) {
        if (!mActivities.remove(r) && r.fullscreen) {
            // Was not previously in list.
            numFullscreen++;
        }
        mActivities.add(r);
    }

    /** @return true if this was the last activity in the task */
    boolean removeActivity(ActivityRecord r) {
        if (mActivities.remove(r) && r.fullscreen) {
            // Was previously in list.
            numFullscreen--;
        }
        return mActivities.size() == 0;
    }

    void dump(PrintWriter pw, String prefix) {
        if (numActivities != 0 || rootWasReset || userId != 0) {
            pw.print(prefix); pw.print("numActivities="); pw.print(numActivities);
                    pw.print(" rootWasReset="); pw.print(rootWasReset);
                    pw.print(" userId="); pw.println(userId);
                    pw.print(" userId="); pw.print(userId);
                    pw.print(" numFullscreen="); pw.println(numFullscreen);
        }
        if (affinity != null) {
            pw.print(prefix); pw.print("affinity="); pw.println(affinity);
@@ -136,6 +178,7 @@ class TaskRecord extends ThumbnailHolder {
            pw.print(prefix); pw.print("realActivity=");
            pw.println(realActivity.flattenToShortString());
        }
        pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
        if (!askedCompatMode) {
            pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode);
        }
@@ -146,6 +189,7 @@ class TaskRecord extends ThumbnailHolder {
                pw.print((getInactiveDuration()/1000)); pw.println("s)");
    }

    @Override
    public String toString() {
        if (stringName != null) {
            return stringName;
@@ -156,19 +200,21 @@ class TaskRecord extends ThumbnailHolder {
        sb.append(" #");
        sb.append(taskId);
        if (affinity != null) {
            sb.append(" A ");
            sb.append(" A=");
            sb.append(affinity);
        } else if (intent != null) {
            sb.append(" I ");
            sb.append(" I=");
            sb.append(intent.getComponent().flattenToShortString());
        } else if (affinityIntent != null) {
            sb.append(" aI ");
            sb.append(" aI=");
            sb.append(affinityIntent.getComponent().flattenToShortString());
        } else {
            sb.append(" ??");
        }
        sb.append(" U ");
        sb.append(" U=");
        sb.append(userId);
        sb.append(" sz=");
        sb.append(mActivities.size());
        sb.append('}');
        return stringName = sb.toString();
    }
+8 −0
Original line number Diff line number Diff line
@@ -228,6 +228,10 @@ class DisplayContent {
        public void remove() {
            throw new IllegalArgumentException();
        }

        @Override public String toString() {
            return mTaskLists.toString();
        }
    }

    class AppTokenIterator implements Iterator<AppWindowToken> {
@@ -294,6 +298,10 @@ class DisplayContent {
            }
            return size;
        }

        @Override public String toString() {
            return mIterator.toString();
        }
    }

    public void dump(String prefix, PrintWriter pw) {
+5 −0
Original line number Diff line number Diff line
@@ -23,4 +23,9 @@ import java.util.ArrayList;
public class TaskGroup {
    public int taskId = -1;
    public ArrayList<IApplicationToken> tokens = new ArrayList<IApplicationToken>();

    @Override
    public String toString() {
        return "id=" + taskId + " tokens=" + tokens;
    }
}
Loading