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:
Winson Chung
2021-06-25 17:04:31 -07:00
parent 50ffbb96c7
commit cfabf151e5
2 changed files with 90 additions and 40 deletions

View File

@@ -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 */);

View File

@@ -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");