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

Commit 70c7a414 authored by Winson Chung's avatar Winson Chung
Browse files

Clean up previous DA organizer when registering

- There is no guarantee that binderDied() will come in for the old
  process before it tries to re-register. Instead, force clean up
  the existing organizer if another organizer is registered for the
  same feature
- Also unlink the death recipient when unregistering/cleaning up the
  organizer

Bug: 190786551
Test: Kill SysUI and ensure it doesn't throw
Change-Id: I1204818eefd96d2eb1fb6d195e186f36fd47efac
parent c45b4a0a
Loading
Loading
Loading
Loading
+62 −39
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.content.pm.ParceledListSlice;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
import android.window.IDisplayAreaOrganizer;
@@ -49,7 +50,8 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl

    final ActivityTaskManagerService mService;
    private final WindowManagerGlobalLock mGlobalLock;
    private final HashMap<Integer, IDisplayAreaOrganizer> mOrganizersByFeatureIds = new HashMap();
    private final HashMap<Integer, DisplayAreaOrganizerState> mOrganizersByFeatureIds =
            new HashMap();

    private class DeathRecipient implements IBinder.DeathRecipient {
        int mFeature;
@@ -63,12 +65,41 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
        @Override
        public void binderDied() {
            synchronized (mGlobalLock) {
                mOrganizersByFeatureIds.remove(mFeature);
                removeOrganizer(mOrganizer);
                mOrganizersByFeatureIds.remove(mFeature).destroy();
            }
        }
    }

    private class DisplayAreaOrganizerState {
        private final IDisplayAreaOrganizer mOrganizer;
        private final DeathRecipient mDeathRecipient;

        DisplayAreaOrganizerState(IDisplayAreaOrganizer organizer, int feature) {
            mOrganizer = organizer;
            mDeathRecipient = new DeathRecipient(organizer, feature);
            try {
                organizer.asBinder().linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                // Oh well...
            }
        }

        void destroy() {
            IBinder organizerBinder = mOrganizer.asBinder();
            mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
                if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
                    if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) {
                        // Delete the organizer created TDA when unregister.
                        deleteTaskDisplayArea(da.asTaskDisplayArea());
                    } else {
                        da.setOrganizer(null);
                    }
                }
            });
            organizerBinder.unlinkToDeath(mDeathRecipient, 0);
        }
    }

    DisplayAreaOrganizerController(ActivityTaskManagerService atm) {
        mService = atm;
        mGlobalLock = atm.mGlobalLock;
@@ -80,7 +111,8 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl

    @Nullable
    IDisplayAreaOrganizer getOrganizerByFeature(int featureId) {
        return mOrganizersByFeatureIds.get(featureId);
        final DisplayAreaOrganizerState state = mOrganizersByFeatureIds.get(featureId);
        return state != null ? state.mOrganizer : null;
    }

    @Override
@@ -94,17 +126,18 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Register display organizer=%s uid=%d",
                        organizer.asBinder(), uid);
                if (mOrganizersByFeatureIds.get(feature) != null) {
                    if (mOrganizersByFeatureIds.get(feature).mOrganizer.asBinder()
                            .isBinderAlive()) {
                        throw new IllegalStateException(
                                "Replacing existing organizer currently unsupported");
                    }

                final DeathRecipient dr = new DeathRecipient(organizer, feature);
                try {
                    organizer.asBinder().linkToDeath(dr, 0);
                } catch (RemoteException e) {
                    // Oh well...
                    mOrganizersByFeatureIds.remove(feature).destroy();
                    Slog.d(TAG, "Replacing dead organizer for feature=" + feature);
                }

                final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer,
                        feature);
                final List<DisplayAreaAppearedInfo> displayAreaInfos = new ArrayList<>();
                mService.mRootWindowContainer.forAllDisplays(dc -> {
                    if (!dc.isTrusted()) {
@@ -120,7 +153,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
                    });
                });

                mOrganizersByFeatureIds.put(feature, organizer);
                mOrganizersByFeatureIds.put(feature, state);
                return new ParceledListSlice<>(displayAreaInfos);
            }
        } finally {
@@ -137,9 +170,14 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
            synchronized (mGlobalLock) {
                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Unregister display organizer=%s uid=%d",
                        organizer.asBinder(), uid);
                mOrganizersByFeatureIds.entrySet().removeIf(
                        entry -> entry.getValue().asBinder() == organizer.asBinder());
                removeOrganizer(organizer);
                mOrganizersByFeatureIds.entrySet().removeIf((entry) -> {
                    final boolean matches = entry.getValue().mOrganizer.asBinder()
                            == organizer.asBinder();
                    if (matches) {
                        entry.getValue().destroy();
                    }
                    return matches;
                });
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
@@ -190,19 +228,15 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
                }

                final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++;
                final DeathRecipient dr = new DeathRecipient(organizer, taskDisplayAreaFeatureId);
                try {
                    organizer.asBinder().linkToDeath(dr, 0);
                } catch (RemoteException e) {
                    // Oh well...
                }
                final DisplayAreaOrganizerState state = new DisplayAreaOrganizerState(organizer,
                        taskDisplayAreaFeatureId);

                final TaskDisplayArea tda = parentRoot != null
                        ? createTaskDisplayArea(parentRoot, name, taskDisplayAreaFeatureId)
                        : createTaskDisplayArea(parentTda, name, taskDisplayAreaFeatureId);
                final DisplayAreaAppearedInfo tdaInfo = organizeDisplayArea(organizer, tda,
                        "DisplayAreaOrganizerController.createTaskDisplayArea");
                mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, organizer);
                mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, state);
                return tdaInfo;
            }
        } finally {
@@ -230,8 +264,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
                                    + "TaskDisplayArea=" + taskDisplayArea);
                }

                mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId);
                deleteTaskDisplayArea(taskDisplayArea);
                mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId).destroy();
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
@@ -251,6 +284,10 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl

    void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) {
        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea vanished name=%s", da.getName());
        if (!organizer.asBinder().isBinderAlive()) {
            Slog.d(TAG, "Organizer died before sending onDisplayAreaVanished");
            return;
        }
        try {
            organizer.onDisplayAreaVanished(da.getDisplayAreaInfo());
        } catch (RemoteException e) {
@@ -267,20 +304,6 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
        }
    }

    private void removeOrganizer(IDisplayAreaOrganizer organizer) {
        IBinder organizerBinder = organizer.asBinder();
        mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
            if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
                if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) {
                    // Delete the organizer created TDA when unregister.
                    deleteTaskDisplayArea(da.asTaskDisplayArea());
                } else {
                    da.setOrganizer(null);
                }
            }
        });
    }

    private DisplayAreaAppearedInfo organizeDisplayArea(IDisplayAreaOrganizer organizer,
            DisplayArea displayArea, String callsite) {
        displayArea.setOrganizer(organizer, true /* skipDisplayAreaAppeared */);
+27 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_LAST;

import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -57,6 +58,7 @@ import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.view.View;
@@ -556,6 +558,7 @@ public class DisplayAreaTest extends WindowTestsBase {
        final DisplayArea<WindowContainer> displayArea = new DisplayArea<>(
                mWm, BELOW_TASKS, "NewArea", FEATURE_VENDOR_FIRST);
        final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
        doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder();
        displayArea.mOrganizer = mockDisplayAreaOrganizer;
        spyOn(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController);
        mDisplayContent.addChild(displayArea, 0);
@@ -592,6 +595,30 @@ public class DisplayAreaTest extends WindowTestsBase {
        assertThat(info2.rootDisplayAreaId).isEqualTo(root.mFeatureId);
    }

    @Test
    public void testRegisterSameFeatureOrganizer_expectThrowsException() {
        final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
        final IBinder binder = mock(IBinder.class);
        doReturn(true).when(binder).isBinderAlive();
        doReturn(binder).when(mockDisplayAreaOrganizer).asBinder();
        final DisplayAreaOrganizerController controller =
                mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
        controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
        assertThrows(IllegalStateException.class,
                () -> controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST));
    }

    @Test
    public void testRegisterUnregisterOrganizer() {
        final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class);
        doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder();
        final DisplayAreaOrganizerController controller =
                mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
        controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
        controller.unregisterOrganizer(mockDisplayAreaOrganizer);
        controller.registerOrganizer(mockDisplayAreaOrganizer, FEATURE_VENDOR_FIRST);
    }

    private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
        private TestDisplayArea(WindowManagerService wms, Rect bounds) {
            super(wms, ANY, "half display area");