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

Commit bed90751 authored by Jorge Gil's avatar Jorge Gil
Browse files

Desks: Do not reuse to-be-removed desk

Default desk creation may happen as a result of removing the last desk.
If that desk was no longer associated to any user, it will have been
scheduled for deletion. This means that there can be a race where the
creation request may be received by RootTaskDesksOrganizer before the
last desk is completely deleted, which results in the organizer
providing the DesktopTasksController/Repository a deskId that will soon
have no associated root to it, ultimately causing a crash the next a
task is attempted to be moved into desktop.

This change adds manual tracking of pending root removals, so that those
roots can be ignored on create requests.

Flag: com.android.window.flags.enable_multiple_desktops_backend
Bug: 406333979
Test: enter desktop, swipe it up to remove it from overview or through
adb command, then try to re-enter desktop - verify there's no crash

Change-Id: I0699b92217fe54e03e92509124752f0120b3f37a
parent 3877df4d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ class RootTaskDesksOrganizer(
        mutableListOf<CreateDeskMinimizationRootRequest>()
    @VisibleForTesting
    val deskMinimizationRootsByDeskId: MutableMap<Int, DeskMinimizationRoot> = mutableMapOf()
    private val removeDeskRootRequests = mutableSetOf<Int>()
    private var onTaskInfoChangedListener: ((RunningTaskInfo) -> Unit)? = null

    init {
@@ -80,6 +81,7 @@ class RootTaskDesksOrganizer(
                .valueIterator()
                .asSequence()
                .filterNot { desk -> userId in desk.users }
                .filterNot { desk -> desk.deskId in removeDeskRootRequests }
                .firstOrNull()
        if (unassignedDesk != null) {
            unassignedDesk.users.add(userId)
@@ -112,6 +114,7 @@ class RootTaskDesksOrganizer(
        if (deskRoot.users.isEmpty()) {
            // No longer in use by any users, remove it completely.
            logD("removeDesk %d is no longer used by any users, removing it completely", deskId)
            removeDeskRootRequests.add(deskId)
            wct.removeRootTask(deskRoot.token)
            deskMinimizationRootsByDeskId[deskId]?.let { root -> wct.removeRootTask(root.token) }
        }
@@ -390,6 +393,7 @@ class RootTaskDesksOrganizer(
            val displayId = deskRoot.taskInfo.displayId
            logV("Desk #$deskId vanished from display #$displayId")
            deskRootsByDeskId.remove(deskId)
            removeDeskRootRequests.remove(deskId)
            return
        }
        val deskMinimizationRoot =
@@ -530,6 +534,8 @@ class RootTaskDesksOrganizer(
        pw.println(
            "${innerPrefix}launchAdjacentEnabled=" + launchAdjacentController.launchAdjacentEnabled
        )
        pw.println("${innerPrefix}createDeskRootRequests=$createDeskRootRequests")
        pw.println("${innerPrefix}removeDeskRootRequests=$removeDeskRootRequests")
        pw.println("${innerPrefix}Desk Roots:")
        deskRootsByDeskId.forEach { deskId, root ->
            val minimizationRoot = deskMinimizationRootsByDeskId[deskId]
+12 −3
Original line number Diff line number Diff line
@@ -92,10 +92,19 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
    fun testCreateDesk_rootExistsForOtherUser_reusesRoot() = runTest {
        val desk = createDeskSuspending(userId = PRIMARY_USER_ID)

        val deskId =
            organizer.createDeskSuspending(displayId = DEFAULT_DISPLAY, userId = SECONDARY_USER_ID)
        val desk2 = createDeskSuspending(userId = SECONDARY_USER_ID)

        assertThat(deskId).isEqualTo(desk.deskRoot.deskId)
        assertThat(desk2.deskRoot.deskId).isEqualTo(desk.deskRoot.deskId)
    }

    @Test
    fun testCreateDesk_rootExistsForOtherUser_pendingDeletion_doesNotReuseRoot() = runTest {
        val desk = createDeskSuspending(userId = PRIMARY_USER_ID)
        organizer.removeDesk(WindowContainerTransaction(), desk.deskRoot.deskId, PRIMARY_USER_ID)

        val desk2 = createDeskSuspending(userId = SECONDARY_USER_ID)

        assertThat(desk2.deskRoot.deskId).isNotEqualTo(desk.deskRoot.deskId)
    }

    @Test