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

Commit 03d65a72 authored by arthurhung's avatar arthurhung
Browse files

Fix consumer closed input channel cause an error occurred (1/2)

An input channel specifies the file descriptors used to send input
events to a window in another process. And All of the file descriptors
open in the calling process shall be closed when process terminated.

The server side could receive the socket broken event when the process
terminated, we should do the unregister channel before close the file
descriptor or do it automatically without error if there is no valid
window.

- Change the order that remove window before dispose the receiver.
- Unregister input channel when windowless window removed.

Bug: 133782251
Test: open app and exit by back key or recent apps, check if any
      error log occurs.
Change-Id: I59d0084c2c771544e7ee226ce53c574f60c6b988
parent 73407d65
Loading
Loading
Loading
Loading
+7 −4
Original line number Original line Diff line number Diff line
@@ -4636,14 +4636,17 @@ public final class ViewRootImpl implements ViewParent,
            mInputQueueCallback = null;
            mInputQueueCallback = null;
            mInputQueue = null;
            mInputQueue = null;
        }
        }
        if (mInputEventReceiver != null) {
            mInputEventReceiver.dispose();
            mInputEventReceiver = null;
        }
        try {
        try {
            mWindowSession.remove(mWindow);
            mWindowSession.remove(mWindow);
        } catch (RemoteException e) {
        } 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);
        mDisplayManager.unregisterDisplayListener(mDisplayListener);


+1 −0
Original line number Original line Diff line number Diff line
@@ -191,6 +191,7 @@ public class WindowlessWindowManager implements IWindowSession {
            throw new IllegalArgumentException(
            throw new IllegalArgumentException(
                    "Invalid window token (never added or removed already)");
                    "Invalid window token (never added or removed already)");
        }
        }

        try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
        try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
            t.remove(state.mSurfaceControl).apply();
            t.remove(state.mSurfaceControl).apply();
        }
        }
+32 −4
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@ import android.util.ArrayMap;
import android.util.Slog;
import android.util.Slog;
import android.view.IWindow;
import android.view.IWindow;
import android.view.InputApplicationHandle;
import android.view.InputApplicationHandle;
import android.view.InputChannel;


/**
/**
 * Keeps track of embedded windows.
 * Keeps track of embedded windows.
@@ -95,7 +96,7 @@ class EmbeddedWindowController {
    void remove(IWindow client) {
    void remove(IWindow client) {
        for (int i = mWindows.size() - 1; i >= 0; i--) {
        for (int i = mWindows.size() - 1; i >= 0; i--) {
            if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) {
            if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) {
                mWindows.removeAt(i);
                mWindows.removeAt(i).onRemoved();
                return;
                return;
            }
            }
        }
        }
@@ -104,7 +105,7 @@ class EmbeddedWindowController {
    void onWindowRemoved(WindowState host) {
    void onWindowRemoved(WindowState host) {
        for (int i = mWindows.size() - 1; i >= 0; i--) {
        for (int i = mWindows.size() - 1; i >= 0; i--) {
            if (mWindows.valueAt(i).mHostWindowState == host) {
            if (mWindows.valueAt(i).mHostWindowState == host) {
                mWindows.removeAt(i);
                mWindows.removeAt(i).onRemoved();
            }
            }
        }
        }
    }
    }
@@ -132,6 +133,8 @@ class EmbeddedWindowController {
        @Nullable final ActivityRecord mHostActivityRecord;
        @Nullable final ActivityRecord mHostActivityRecord;
        final int mOwnerUid;
        final int mOwnerUid;
        final int mOwnerPid;
        final int mOwnerPid;
        final WindowManagerService mWmService;
        InputChannel mInputChannel;


        /**
        /**
         * @param clientToken client token used to clean up the map if the embedding process dies
         * @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 ownerUid  calling uid
         * @param ownerPid  calling pid used for anr blaming
         * @param ownerPid  calling pid used for anr blaming
         */
         */
        EmbeddedWindow(IWindow clientToken, WindowState hostWindowState, int ownerUid,
        EmbeddedWindow(WindowManagerService service, IWindow clientToken,
                int ownerPid) {
                WindowState hostWindowState, int ownerUid, int ownerPid) {
            mWmService = service;
            mClient = clientToken;
            mClient = clientToken;
            mHostWindowState = hostWindowState;
            mHostWindowState = hostWindowState;
            mHostActivityRecord = (mHostWindowState != null) ? mHostWindowState.mActivityRecord
            mHostActivityRecord = (mHostWindowState != null) ? mHostWindowState.mActivityRecord
@@ -167,5 +171,29 @@ class EmbeddedWindowController {
            return new InputApplicationHandle(
            return new InputApplicationHandle(
                    mHostWindowState.mInputWindowHandle.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;
            }
        }
    }
    }
}
}
+3 −18
Original line number Original line Diff line number Diff line
@@ -8015,26 +8015,15 @@ public class WindowManagerService extends IWindowManager.Stub
            IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) {
            IWindow window, IBinder hostInputToken, int flags, InputChannel outInputChannel) {
        final InputApplicationHandle applicationHandle;
        final InputApplicationHandle applicationHandle;
        final String name;
        final String name;
        final InputChannel[] inputChannels;
        final InputChannel clientChannel;
        final InputChannel clientChannel;
        final InputChannel serverChannel;
        synchronized (mGlobalLock) {
        synchronized (mGlobalLock) {
            EmbeddedWindowController.EmbeddedWindow win =
            EmbeddedWindowController.EmbeddedWindow win =
                    new EmbeddedWindowController.EmbeddedWindow(window,
                    new EmbeddedWindowController.EmbeddedWindow(this, window,
                            mInputToWindowMap.get(hostInputToken), callingUid, callingPid);
                            mInputToWindowMap.get(hostInputToken), callingUid, callingPid);
            name = win.getName();
            clientChannel = win.openInputChannel();

            inputChannels = InputChannel.openInputChannelPair(name);
            serverChannel = inputChannels[0];
            clientChannel = inputChannels[1];
            mInputManager.registerInputChannel(serverChannel);
            mEmbeddedWindowController.add(clientChannel.getToken(), win);
            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();
            applicationHandle = win.getApplicationHandle();
            name = win.getName();
        }
        }


        updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
        updateInputChannel(clientChannel.getToken(), callingUid, callingPid, displayId, surface,
@@ -8042,10 +8031,6 @@ public class WindowManagerService extends IWindowManager.Stub


        clientChannel.transferTo(outInputChannel);
        clientChannel.transferTo(outInputChannel);
        clientChannel.dispose();
        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,
    private void updateInputChannel(IBinder channelToken, int callingUid, int callingPid,