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

Commit 755c8bfb authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Fix issue #6319312: Consecutive call to Activity's onCreate()/onResume()...

...without onPause() in between

There was a bug in the handling of "always finish activities" where we
would go through destroying activities while in the middle of updating
the activity stack.  This would result in the activity behind the
non-full-screen activity being created and then immediately destroyed,
which things were not expecting.

Change-Id: Idaa89089f7b1af7eb747d7b8f9f394beeb2d23fa
parent ff0e8cd8
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -136,7 +136,7 @@ public final class ActivityThread {
    /** @hide */
    public static final boolean DEBUG_BROADCAST = false;
    private static final boolean DEBUG_RESULTS = false;
    private static final boolean DEBUG_BACKUP = true;
    private static final boolean DEBUG_BACKUP = false;
    private static final boolean DEBUG_CONFIGURATION = false;
    private static final boolean DEBUG_SERVICE = false;
    private static final boolean DEBUG_MEMORY_TRIM = false;
@@ -1172,10 +1172,10 @@ public final class ActivityThread {
                    case DUMP_PROVIDER: return "DUMP_PROVIDER";
                }
            }
            return "(unknown)";
            return Integer.toString(code);
        }
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + msg.what);
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
@@ -1378,7 +1378,7 @@ public final class ActivityThread {
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
            }
            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
        }

        private void maybeSnapshot() {
+6 −2
Original line number Diff line number Diff line
@@ -14508,9 +14508,11 @@ public final class ActivityManagerService extends ActivityManagerNative
                            // activities causes more harm than good.
                            if (curLevel >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
                                    && app != mHomeProcess && app != mPreviousProcess) {
                                // Need to do this on its own message because the stack may not
                                // be in a consistent state at this point.
                                // For these apps we will also finish their activities
                                // to help them free memory.
                                mMainStack.destroyActivitiesLocked(app, false, "trim");
                                mMainStack.scheduleDestroyActivities(app, false, "trim");
                            }
                        }
                    }
@@ -14582,7 +14584,9 @@ public final class ActivityManagerService extends ActivityManagerNative
        }
        if (mAlwaysFinishActivities) {
            mMainStack.destroyActivitiesLocked(null, false, "always-finish");
            // Need to do this on its own message because the stack may not
            // be in a consistent state at this point.
            mMainStack.scheduleDestroyActivities(null, false, "always-finish");
        }
    }
+43 −6
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -289,6 +288,18 @@ final class ActivityStack {
    static final int RESUME_TOP_ACTIVITY_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
    static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7;
    static final int STOP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 8;
    static final int DESTROY_ACTIVITIES_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 9;

    static class ScheduleDestroyArgs {
        final ProcessRecord mOwner;
        final boolean mOomAdj;
        final String mReason;
        ScheduleDestroyArgs(ProcessRecord owner, boolean oomAdj, String reason) {
            mOwner = owner;
            mOomAdj = oomAdj;
            mReason = reason;
        }
    }

    final Handler mHandler = new Handler() {
        //public Handler() {
@@ -384,6 +395,12 @@ final class ActivityStack {
                        }
                    }
                } break;
                case DESTROY_ACTIVITIES_MSG: {
                    ScheduleDestroyArgs args = (ScheduleDestroyArgs)msg.obj;
                    synchronized (mService) {
                        destroyActivitiesLocked(args.mOwner, args.mOomAdj, args.mReason);
                    }
                }
            }
        }
    };
@@ -3822,18 +3839,38 @@ final class ActivityStack {
        }
    }

    final void scheduleDestroyActivities(ProcessRecord owner, boolean oomAdj, String reason) {
        Message msg = mHandler.obtainMessage(DESTROY_ACTIVITIES_MSG);
        msg.obj = new ScheduleDestroyArgs(owner, oomAdj, reason);
        mHandler.sendMessage(msg);
    }

    final void destroyActivitiesLocked(ProcessRecord owner, boolean oomAdj, String reason) {
        boolean lastIsOpaque = false;
        for (int i=mHistory.size()-1; i>=0; i--) {
            ActivityRecord r = mHistory.get(i);
            if (r.finishing) {
                continue;
            }
            if (r.fullscreen) {
                lastIsOpaque = true;
            }
            if (owner != null && r.app != owner) {
                continue;
            }
            if (!lastIsOpaque) {
                continue;
            }
            // We can destroy this one if we have its icicle saved and
            // it is not in the process of pausing/stopping/finishing.
            if (r.app != null && r.haveState && !r.visible && r.stopped && !r.finishing
            if (r.app != null && r != mResumedActivity && r != mPausingActivity
                    && r.haveState && !r.visible && r.stopped
                    && r.state != ActivityState.DESTROYING
                    && r.state != ActivityState.DESTROYED) {
                destroyActivityLocked(r, true, oomAdj, "trim");
                if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
                        + " resumed=" + mResumedActivity
                        + " pausing=" + mPausingActivity);
                destroyActivityLocked(r, true, oomAdj, reason);
            }
        }
    }
@@ -3847,7 +3884,7 @@ final class ActivityStack {
    final boolean destroyActivityLocked(ActivityRecord r,
            boolean removeFromApp, boolean oomAdj, String reason) {
        if (DEBUG_SWITCH) Slog.v(
            TAG, "Removing activity: token=" + r
            TAG, "Removing activity from " + reason + ": token=" + r
              + ", app=" + (r.app != null ? r.app.processName : "(null)"));
        EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
                System.identityHashCode(r),