Cleaning up InputConsumers

- Log the pid and user handle for the client input consumer
- Pass token to WMS to ensure that it is notified when the client input
  consumer process is killed

Bug: 37309537
Test: android.server.am.ActivityManagerPinnedStackTests
Change-Id: I432d96b1f524ab34dbbad3eeb67d996abdd5f4ca
Signed-off-by: Winson Chung <winsonc@google.com>
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 6e49bac..d62eab9 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -385,7 +385,7 @@
     /**
      * Create an input consumer by name.
      */
-    void createInputConsumer(String name, out InputChannel inputChannel);
+    void createInputConsumer(IBinder token, String name, out InputChannel inputChannel);
 
     /**
      * Destroy an input consumer by name.  This method will also dispose the input channels
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
index e6d6c55..db4f988 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/InputConsumerController.java
@@ -18,6 +18,8 @@
 
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
@@ -77,7 +79,8 @@
         }
     }
 
-    private IWindowManager mWindowManager;
+    private final IWindowManager mWindowManager;
+    private final IBinder mToken;
 
     private PipInputEventReceiver mInputEventReceiver;
     private TouchListener mListener;
@@ -85,6 +88,7 @@
 
     public InputConsumerController(IWindowManager windowManager) {
         mWindowManager = windowManager;
+        mToken = new Binder();
         registerInputConsumer();
     }
 
@@ -122,7 +126,7 @@
             final InputChannel inputChannel = new InputChannel();
             try {
                 mWindowManager.destroyInputConsumer(INPUT_CONSUMER_PIP);
-                mWindowManager.createInputConsumer(INPUT_CONSUMER_PIP, inputChannel);
+                mWindowManager.createInputConsumer(mToken, INPUT_CONSUMER_PIP, inputChannel);
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to create PIP input consumer", e);
             }
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 36753b7..d40db8c 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,21 +16,36 @@
 
 package com.android.server.wm;
 
+import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
 import android.view.Display;
 import android.view.InputChannel;
 import android.view.WindowManager;
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
 
-class InputConsumerImpl {
+import java.io.PrintWriter;
+
+class InputConsumerImpl implements IBinder.DeathRecipient {
     final WindowManagerService mService;
     final InputChannel mServerChannel, mClientChannel;
     final InputApplicationHandle mApplicationHandle;
     final InputWindowHandle mWindowHandle;
 
-    InputConsumerImpl(WindowManagerService service, String name, InputChannel inputChannel) {
+    final IBinder mToken;
+    final String mName;
+    final int mClientPid;
+    final UserHandle mClientUser;
+
+    InputConsumerImpl(WindowManagerService service, IBinder token, String name,
+            InputChannel inputChannel, int clientPid, UserHandle clientUser) {
         mService = service;
+        mToken = token;
+        mName = name;
+        mClientPid = clientPid;
+        mClientUser = clientUser;
 
         InputChannel[] channels = InputChannel.openInputChannelPair(name);
         mServerChannel = channels[0];
@@ -68,6 +83,26 @@
         mWindowHandle.scaleFactor = 1.0f;
     }
 
+    void linkToDeathRecipient() {
+        if (mToken == null) {
+            return;
+        }
+
+        try {
+            mToken.linkToDeath(this, 0);
+        } catch (RemoteException e) {
+            // Client died, do nothing
+        }
+    }
+
+    void unlinkFromDeathRecipient() {
+        if (mToken == null) {
+            return;
+        }
+
+        mToken.unlinkToDeath(this, 0);
+    }
+
     void layout(int dw, int dh) {
         mWindowHandle.touchableRegion.set(0, 0, dw, dh);
         mWindowHandle.frameLeft = 0;
@@ -86,5 +121,19 @@
         mService.mInputManager.unregisterInputChannel(mServerChannel);
         mClientChannel.dispose();
         mServerChannel.dispose();
+        unlinkFromDeathRecipient();
+    }
+
+    @Override
+    public void binderDied() {
+        synchronized (mService.getWindowManagerLock()) {
+            // Clean up the input consumer
+            mService.mInputMonitor.destroyInputConsumer(mName);
+            unlinkFromDeathRecipient();
+        }
+    }
+
+    void dump(PrintWriter pw, String name, String prefix) {
+        pw.println(prefix + "  name=" + name + " pid=" + mClientPid + " user=" + mClientUser);
     }
 }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 238cb9f..35f1cb4 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -25,6 +25,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
@@ -34,8 +35,11 @@
 import android.app.ActivityManager;
 import android.graphics.Rect;
 import android.os.Debug;
+import android.os.IBinder;
 import android.os.Looper;
+import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
@@ -43,7 +47,6 @@
 import android.view.InputEventReceiver;
 import android.view.KeyEvent;
 import android.view.WindowManager;
-
 import android.view.WindowManagerPolicy;
 
 import com.android.server.input.InputApplicationHandle;
@@ -106,8 +109,9 @@
 
         EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor,
                                    Looper looper, String name,
-                                   InputEventReceiver.Factory inputEventReceiverFactory) {
-            super(service, name, null);
+                                   InputEventReceiver.Factory inputEventReceiverFactory,
+                                   int clientPid, UserHandle clientUser) {
+            super(service, null /* token */, name, null /* inputChannel */, clientPid, clientUser);
             mInputMonitor = monitor;
             mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
                     mClientChannel, looper);
@@ -129,6 +133,7 @@
 
     private void addInputConsumer(String name, InputConsumerImpl consumer) {
         mInputConsumers.put(name, consumer);
+        consumer.linkToDeathRecipient();
         updateInputWindowsLw(true /* force */);
     }
 
@@ -166,17 +171,20 @@
         }
 
         final EventReceiverInputConsumer consumer = new EventReceiverInputConsumer(mService,
-                this, looper, name, inputEventReceiverFactory);
+                this, looper, name, inputEventReceiverFactory, Process.myPid(),
+                UserHandle.SYSTEM);
         addInputConsumer(name, consumer);
         return consumer;
     }
 
-    void createInputConsumer(String name, InputChannel inputChannel) {
+    void createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid,
+            UserHandle clientUser) {
         if (mInputConsumers.containsKey(name)) {
             throw new IllegalStateException("Existing input consumer found with name: " + name);
         }
 
-        final InputConsumerImpl consumer = new InputConsumerImpl(mService, name, inputChannel);
+        final InputConsumerImpl consumer = new InputConsumerImpl(mService, token, name,
+                inputChannel, clientPid, clientUser);
         switch (name) {
             case INPUT_CONSUMER_WALLPAPER:
                 consumer.mWindowHandle.hasWallpaper = true;
@@ -592,7 +600,7 @@
         if (!inputConsumerKeys.isEmpty()) {
             pw.println(prefix + "InputConsumers:");
             for (String key : inputConsumerKeys) {
-                pw.println(prefix + "  name=" + key);
+                mInputConsumers.get(key).dump(pw, key, prefix);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ad6fc39..c7dac62 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6253,9 +6253,10 @@
     }
 
     @Override
-    public void createInputConsumer(String name, InputChannel inputChannel) {
+    public void createInputConsumer(IBinder token, String name, InputChannel inputChannel) {
         synchronized (mWindowMap) {
-            mInputMonitor.createInputConsumer(name, inputChannel);
+            mInputMonitor.createInputConsumer(token, name, inputChannel, Binder.getCallingPid(),
+                    Binder.getCallingUserHandle());
         }
     }