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 Fixes: 190786551 Test: Kill SysUI and ensure it doesn't throw Test: atest DisplayAreaTest Change-Id: I1204818eefd96d2eb1fb6d195e186f36fd47efac Merged-In: I1204818eefd96d2eb1fb6d195e186f36fd47efac
This commit is contained in:
@@ -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) {
|
||||
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...
|
||||
if (mOrganizersByFeatureIds.get(feature).mOrganizer.asBinder()
|
||||
.isBinderAlive()) {
|
||||
throw new IllegalStateException(
|
||||
"Replacing existing organizer currently unsupported");
|
||||
}
|
||||
|
||||
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 */);
|
||||
|
||||
@@ -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;
|
||||
@@ -555,6 +557,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);
|
||||
@@ -566,6 +569,30 @@ public class DisplayAreaTest extends WindowTestsBase {
|
||||
.onDisplayAreaVanished(mockDisplayAreaOrganizer, displayArea);
|
||||
}
|
||||
|
||||
@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");
|
||||
|
||||
Reference in New Issue
Block a user