Loading services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java +62 −39 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading @@ -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()) { Loading @@ -120,7 +153,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl }); }); mOrganizersByFeatureIds.put(feature, organizer); mOrganizersByFeatureIds.put(feature, state); return new ParceledListSlice<>(displayAreaInfos); } } finally { Loading @@ -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); Loading Loading @@ -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 { Loading Loading @@ -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); Loading @@ -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) { Loading @@ -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 */); Loading services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +27 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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"); Loading Loading
services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java +62 −39 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading @@ -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()) { Loading @@ -120,7 +153,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl }); }); mOrganizersByFeatureIds.put(feature, organizer); mOrganizersByFeatureIds.put(feature, state); return new ParceledListSlice<>(displayAreaInfos); } } finally { Loading @@ -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); Loading Loading @@ -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 { Loading Loading @@ -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); Loading @@ -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) { Loading @@ -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 */); Loading
services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +27 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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"); Loading