Merge "Fix local Binder call scenario of IMMS#addClient()"
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index e9acdc3..d24b822 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageManager;
 import android.graphics.Rect;
 import android.inputmethodservice.InputMethodService;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -753,10 +754,20 @@
             throw new IllegalStateException(e);
         }
         final InputMethodManager imm = new InputMethodManager(service, displayId, looper);
+        // InputMethodManagerService#addClient() relies on Binder.getCalling{Pid, Uid}() to
+        // associate PID/UID with each IME client. This means:
+        //  A. if this method call will be handled as an IPC, there is no problem.
+        //  B. if this method call will be handled as an in-proc method call, we need to
+        //     ensure that Binder.getCalling{Pid, Uid}() return Process.my{Pid, Uid}()
+        // Either ways we can always call Binder.{clear, restore}CallingIdentity() because
+        // 1) doing so has no effect for A and 2) doing so is sufficient for B.
+        final long identity = Binder.clearCallingIdentity();
         try {
             service.addClient(imm.mClient, imm.mIInputContext, displayId);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
         return imm;
     }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index e37153e..e3a1a91 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1770,6 +1770,12 @@
     @Override
     public void addClient(IInputMethodClient client, IInputContext inputContext,
             int selfReportedDisplayId) {
+        // Here there are two scenarios where this method is called:
+        // A. IMM is being instantiated in a different process and this is an IPC from that process
+        // B. IMM is being instantiated in the same process but Binder.clearCallingIdentity() is
+        //    called in the caller side if necessary.
+        // In either case the following UID/PID should be the ones where InputMethodManager is
+        // actually running.
         final int callerUid = Binder.getCallingUid();
         final int callerPid = Binder.getCallingPid();
         synchronized (mMethodMap) {
@@ -1778,7 +1784,7 @@
                 if (state.uid == callerUid && state.pid == callerPid
                         && state.selfReportedDisplayId == selfReportedDisplayId) {
                     throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
-                            + " is already registered");
+                            + "/displayId=" + selfReportedDisplayId + " is already registered.");
                 }
             }
             final ClientDeathRecipient deathRecipient = new ClientDeathRecipient(this, client);