diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index a17af6c906176..172197c8f3966 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -4638,14 +4638,17 @@ public final class ViewRootImpl implements ViewParent, mInputQueueCallback = null; mInputQueue = null; } - if (mInputEventReceiver != null) { - mInputEventReceiver.dispose(); - mInputEventReceiver = null; - } try { mWindowSession.remove(mWindow); } catch (RemoteException e) { } + // Dispose receiver would dispose client InputChannel, too. That could send out a socket + // broken event, so we need to unregister the server InputChannel when removing window to + // prevent server side receive the event and prompt error. + if (mInputEventReceiver != null) { + mInputEventReceiver.dispose(); + mInputEventReceiver = null; + } mDisplayManager.unregisterDisplayListener(mDisplayListener); diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 15604a2ae2c1a..cd954c41f4693 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -191,6 +191,7 @@ public class WindowlessWindowManager implements IWindowSession { throw new IllegalArgumentException( "Invalid window token (never added or removed already)"); } + try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) { t.remove(state.mSurfaceControl).apply(); } diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java index 484a5a8b53b8f..9bbd4cd0778ac 100644 --- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java +++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java @@ -28,6 +28,7 @@ import android.util.ArrayMap; import android.util.Slog; import android.view.IWindow; import android.view.InputApplicationHandle; +import android.view.InputChannel; /** * Keeps track of embedded windows. @@ -95,7 +96,7 @@ class EmbeddedWindowController { void remove(IWindow client) { for (int i = mWindows.size() - 1; i >= 0; i--) { if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) { - mWindows.removeAt(i); + mWindows.removeAt(i).onRemoved(); return; } } @@ -104,7 +105,7 @@ class EmbeddedWindowController { void onWindowRemoved(WindowState host) { for (int i = mWindows.size() - 1; i >= 0; i--) { if (mWindows.valueAt(i).mHostWindowState == host) { - mWindows.removeAt(i); + mWindows.removeAt(i).onRemoved(); } } } @@ -132,6 +133,8 @@ class EmbeddedWindowController { @Nullable final ActivityRecord mHostActivityRecord; final int mOwnerUid; final int mOwnerPid; + final WindowManagerService mWmService; + InputChannel mInputChannel; /** * @param clientToken client token used to clean up the map if the embedding process dies @@ -142,8 +145,9 @@ class EmbeddedWindowController { * @param ownerUid calling uid * @param ownerPid calling pid used for anr blaming */ - EmbeddedWindow(IWindow clientToken, WindowState hostWindowState, int ownerUid, - int ownerPid) { + EmbeddedWindow(WindowManagerService service, IWindow clientToken, + WindowState hostWindowState, int ownerUid, int ownerPid) { + mWmService = service; mClient = clientToken; mHostWindowState = hostWindowState; mHostActivityRecord = (mHostWindowState != null) ? mHostWindowState.mActivityRecord @@ -167,5 +171,29 @@ class EmbeddedWindowController { return new InputApplicationHandle( mHostWindowState.mInputWindowHandle.inputApplicationHandle); } + + InputChannel openInputChannel() { + final String name = getName(); + + final InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); + mInputChannel = inputChannels[0]; + final InputChannel clientChannel = inputChannels[1]; + mWmService.mInputManager.registerInputChannel(mInputChannel); + + if (mInputChannel.getToken() != clientChannel.getToken()) { + throw new IllegalStateException("Client and Server tokens are expected to" + + "be the same"); + } + + return clientChannel; + } + + void onRemoved() { + if (mInputChannel != null) { + mWmService.mInputManager.unregisterInputChannel(mInputChannel); + mInputChannel.dispose(); + mInputChannel = null; + } + } } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 814fa7287646d..13a0b2c536e72 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8030,26 +8030,15 @@ public class WindowManagerService extends IWindowManager.Stub IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) { final InputApplicationHandle applicationHandle; final String name; - final InputChannel[] inputChannels; final InputChannel clientChannel; - final InputChannel serverChannel; synchronized (mGlobalLock) { EmbeddedWindowController.EmbeddedWindow win = - new EmbeddedWindowController.EmbeddedWindow(window, + new EmbeddedWindowController.EmbeddedWindow(this, window, mInputToWindowMap.get(hostInputToken), callingUid, callingPid); - name = win.getName(); - - inputChannels = InputChannel.openInputChannelPair(name); - serverChannel = inputChannels[0]; - clientChannel = inputChannels[1]; - mInputManager.registerInputChannel(serverChannel); + clientChannel = win.openInputChannel(); mEmbeddedWindowController.add(clientChannel.getToken(), win); - if (serverChannel.getToken() != clientChannel.getToken()) { - throw new IllegalStateException("Client and Server channel are expected to" - + "be the same"); - } - applicationHandle = win.getApplicationHandle(); + name = win.getName(); } updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface, @@ -8057,10 +8046,6 @@ public class WindowManagerService extends IWindowManager.Stub clientChannel.transferTo(outInputChannel); clientChannel.dispose(); - // Prevent the java finalizer from breaking the input channel. But we won't - // do any further management so we just release the java ref and let the - // InputDispatcher hold the last ref. - serverChannel.release(); } private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,