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

Commit 009f699c authored by Bryce Lee's avatar Bryce Lee Committed by gitbuildkicker
Browse files

Remove window container from empty task when destroying.

Previously, the window container was being removed whenever we were
removing the task in a destroy mode. However, this caused issues
where an activity may still be present in the task record, leading to
a subequent change to limit this to tasks with overlays. This led to
the situation where the window container would not be destroyed when
it was supposed to, such as moving an activity to recents, but
otherwise destroying.

This changelist addresses the issue by always removing the window
container from tasks when removed from their parent stack in a
destroy mode and empty. In the recents flow, this will fire and
cleanup when the activity is destroyed.

Change-Id: I87548d6ff8e4d77b6294504d7cc78370cd5d31fa
Fixes: 37301159
Test: bit FrameworksServicesTests:com.android.server.am.ActivityStackTests
(cherry picked from commit 840c566d)
parent bb7326d4
Loading
Loading
Loading
Loading
+5 −2
Original line number Original line Diff line number Diff line
@@ -116,6 +116,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.Display;
import android.view.Display;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.BatteryStatsImpl;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
import com.android.server.Watchdog;
@@ -230,9 +231,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
    // activities and there is a specific combination of stacks.
    // activities and there is a specific combination of stacks.
    private static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
    private static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;


    @VisibleForTesting
    /* The various modes for the method {@link #removeTask}. */
    /* The various modes for the method {@link #removeTask}. */
    // Task is being completely removed from all stacks in the system.
    // Task is being completely removed from all stacks in the system.
    private static final int REMOVE_TASK_MODE_DESTROYING = 0;
    protected static final int REMOVE_TASK_MODE_DESTROYING = 0;
    // Task is being removed from this stack so we can add it to another stack. In the case we are
    // Task is being removed from this stack so we can add it to another stack. In the case we are
    // moving we don't want to perform some operations on the task like removing it from window
    // moving we don't want to perform some operations on the task like removing it from window
    // manager or recents.
    // manager or recents.
@@ -3984,7 +3986,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                //       where we are destroying the task, move this back into removeTask()
                //       where we are destroying the task, move this back into removeTask()
                mStackSupervisor.removeTaskByIdLocked(task.taskId, false /* killProcess */,
                mStackSupervisor.removeTaskByIdLocked(task.taskId, false /* killProcess */,
                        !REMOVE_FROM_RECENTS, PAUSE_IMMEDIATELY);
                        !REMOVE_FROM_RECENTS, PAUSE_IMMEDIATELY);
                task.removeWindowContainer();
            }
            }
            removeTask(task, reason, REMOVE_TASK_MODE_DESTROYING);
            removeTask(task, reason, REMOVE_TASK_MODE_DESTROYING);
        }
        }
@@ -5076,6 +5077,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
                mRecentTasks.remove(task);
                mRecentTasks.remove(task);
                task.removedFromRecents();
                task.removedFromRecents();
            }
            }

            task.removeWindowContainer();
        }
        }


        if (mTaskHistory.isEmpty()) {
        if (mTaskHistory.isEmpty()) {
+64 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

package com.android.server.am;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import android.content.ComponentName;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;

import org.junit.runner.RunWith;
import org.junit.Test;

/**
 * Tests for the {@link ActivityStack} class.
 *
 * Build/Install/Run:
 *  bit FrameworksServicesTests:com.android.server.am.ActivityStackTests
 */
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ActivityStackTests extends ActivityTestsBase {
    private final ComponentName testActivityComponent =
            ComponentName.unflattenFromString("com.foo/.BarActivity");

    @Test
    public void testEmptyTaskCleanupOnRemove() throws Exception {
        final ActivityManagerService service = createActivityManagerService();
        final TestActivityStack testStack = new ActivityStackBuilder(service).build();
        final TaskRecord task = createTask(service, testActivityComponent, testStack);
        assertNotNull(task.getWindowContainerController());
        testStack.removeTask(task, "testEmptyTaskCleanupOnRemove",
                ActivityStack.REMOVE_TASK_MODE_DESTROYING);
        assertNull(task.getWindowContainerController());
    }
    @Test
    public void testOccupiedTaskCleanupOnRemove() throws Exception {
        final ActivityManagerService service = createActivityManagerService();
        final TestActivityStack testStack = new ActivityStackBuilder(service).build();
        final TaskRecord task = createTask(service, testActivityComponent, testStack);
        final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
        assertNotNull(task.getWindowContainerController());
        testStack.removeTask(task, "testOccupiedTaskCleanupOnRemove",
                ActivityStack.REMOVE_TASK_MODE_DESTROYING);
        assertNotNull(task.getWindowContainerController());
    }
}
+24 −7
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.am;


import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mock;


import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
@@ -62,14 +63,16 @@ public class ActivityTestsBase {
    }
    }


    protected ActivityManagerService createActivityManagerService() {
    protected ActivityManagerService createActivityManagerService() {
        return new TestActivityManagerService(mContext);
        final ActivityManagerService service = new TestActivityManagerService(mContext);
        service.mWindowManager = WindowTestUtils.getWindowManagerService(mContext);
        return service;
    }
    }


    protected static TestActivityStack createActivityStack(ActivityManagerService service,
    protected static TestActivityStack createActivityStack(ActivityManagerService service,
            int stackId, int displayId, boolean onTop) {
            int stackId, int displayId, boolean onTop) {
        if (service.mStackSupervisor instanceof TestActivityStackSupervisor) {
        if (service.mStackSupervisor instanceof TestActivityStackSupervisor) {
            final TestActivityStack stack = ((TestActivityStackSupervisor) service.mStackSupervisor)
            final TestActivityStack stack = ((TestActivityStackSupervisor) service.mStackSupervisor)
                    .createTestStack(stackId, onTop);
                    .createTestStack(service, stackId, onTop);
            return stack;
            return stack;
        }
        }


@@ -109,7 +112,7 @@ public class ActivityTestsBase {
        intent.setComponent(component);
        intent.setComponent(component);


        final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/,
        final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/,
                null /*_taskDescription*/, null /*thumbnailInfo*/);
                null /*_taskDescription*/, new ActivityManager.TaskThumbnailInfo());
        stack.addTask(task, true, "creating test task");
        stack.addTask(task, true, "creating test task");
        task.setStack(stack);
        task.setStack(stack);
        task.createWindowContainer(true, true);
        task.createWindowContainer(true, true);
@@ -146,25 +149,39 @@ public class ActivityTestsBase {
        void updateUIDsPresentOnDisplay() {
        void updateUIDsPresentOnDisplay() {
        }
        }


        public TestActivityStack createTestStack(int stackId, boolean onTop) {
        public TestActivityStack createTestStack(ActivityManagerService service, int stackId,
                boolean onTop) {
            final ActivityDisplay display = new ActivityDisplay();
            final ActivityDisplay display = new ActivityDisplay();
            final TestActivityContainer container =
            final TestActivityContainer container =
                    new TestActivityContainer(stackId, display, onTop);
                    new TestActivityContainer(service, stackId, display, onTop);
            return container.getStack();
            return container.getStack();
        }
        }


        private class TestActivityContainer extends ActivityContainer {
        private class TestActivityContainer extends ActivityContainer {
            private ActivityManagerService mService;
            private TestActivityStack mStack;
            private TestActivityStack mStack;
            TestActivityContainer(int stackId, ActivityDisplay activityDisplay, boolean onTop) {
            private boolean mOnTop;

            TestActivityContainer(ActivityManagerService service, int stackId,
                    ActivityDisplay activityDisplay, boolean onTop) {
                super(stackId, activityDisplay, onTop);
                super(stackId, activityDisplay, onTop);
                mService = service;
            }
            }


            @Override
            @Override
            protected void createStack(int stackId, boolean onTop) {
            protected void createStack(int stackId, boolean onTop) {
                mStack = new TestActivityStack(this, null /*recentTasks*/, onTop);
                // normally stack creation is done here. However we need to do it on demand since
                // we cannot set {@link mService} by the time the super constructor calling this
                // method is invoked.
                mOnTop = onTop;
            }
            }


            public TestActivityStack getStack() {
            public TestActivityStack getStack() {
                if (mStack == null) {
                    mStack = new TestActivityStack(this,
                            new RecentTasks(mService, mService.mStackSupervisor), mOnTop);
                }

                return mStack;
                return mStack;
            }
            }
        }
        }