Refactor command line IME tracing

This change refactors the command handling for enabling or disabling IME
tracing. The change also adds synchronization checks for accessing
clients.

Bug: 154348613
Test: start IME tracing by calling "adb shell ime tracing start"
      end IME tracing by calling "adb shell ime tracing stop"
      pull traces in "/data/misc/wmtrace/ime_trace_*"
Change-Id: I66d7ba09508f4a19eaf6c1f3d0ce03daf84d7421
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 2d7f62d..c516232 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -474,6 +474,7 @@
         }
     }
 
+    @GuardedBy("mMethodMap")
     final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
 
     private static final class ActivityViewInfo {
@@ -5322,20 +5323,7 @@
                     case "reset":
                         return mService.handleShellCommandResetInputMethod(this);
                     case "tracing":
-                        int result = ImeTracing.getInstance().onShellCommand(this);
-                        boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
-                        for (ClientState state : mService.mClients.values()) {
-                            if (state != null) {
-                                try {
-                                    state.client.setImeTraceEnabled(isImeTraceEnabled);
-                                } catch (RemoteException e) {
-                                    Log.e(TAG,
-                                            "Error while trying to enable/disable ime "
-                                                    + "trace on client window", e);
-                                }
-                            }
-                        }
-                        return result;
+                        return mService.handleShellCommandTraceInputMethod(this);
                     default:
                         getOutPrintWriter().println("Unknown command: " + imeCommand);
                         return ShellCommandResult.FAILURE;
@@ -5716,6 +5704,34 @@
     }
 
     /**
+     * Handles {@code adb shell ime tracing start/stop}.
+     * @param shellCommand {@link ShellCommand} object that is handling this command.
+     * @return Exit code of the command.
+     */
+    @BinderThread
+    @ShellCommandResult
+    private int handleShellCommandTraceInputMethod(@NonNull ShellCommand shellCommand) {
+        int result = ImeTracing.getInstance().onShellCommand(shellCommand);
+        boolean isImeTraceEnabled = ImeTracing.getInstance().isEnabled();
+        ArrayMap<IBinder, ClientState> clients;
+        synchronized (mMethodMap) {
+            clients = new ArrayMap<>(mClients);
+        }
+        for (ClientState state : clients.values()) {
+            if (state != null) {
+                try {
+                    state.client.setImeTraceEnabled(isImeTraceEnabled);
+                } catch (RemoteException e) {
+                    Log.e(TAG,
+                            "Error while trying to enable/disable ime "
+                            + "trace on client window", e);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
      * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
      * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
      * @return {@code true} if userId has debugging privileges.