Handle some input events in the background thread

For better performance, made some latency sentive input events be
handled in the background thread instead of UI thread

Bug: 331179939
Bug: 347253952
Test: check the latency
Change-Id: Ib8e849abfedc9a606ccb0fbdffb9c7a696a82570
diff --git a/java/framework/src/android/system/virtualmachine/VirtualMachine.java b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
index 23269d9..b6de9bb 100644
--- a/java/framework/src/android/system/virtualmachine/VirtualMachine.java
+++ b/java/framework/src/android/system/virtualmachine/VirtualMachine.java
@@ -77,6 +77,7 @@
 import android.system.virtualizationservice.VirtualMachineState;
 import android.util.JsonReader;
 import android.util.Log;
+import android.util.Pair;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
@@ -112,8 +113,11 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 import java.util.zip.ZipFile;
@@ -174,6 +178,15 @@
     private ParcelFileDescriptor mSwitchesSock;
     private ParcelFileDescriptor mTrackpadSock;
 
+    private enum InputEventType {
+        TOUCH,
+        MOUSE,
+        TRACKPAD
+    }
+
+    private BlockingQueue<Pair<InputEventType, MotionEvent>> mInputEventQueue =
+            new LinkedBlockingQueue<>();
+
     /**
      * Status of a virtual machine
      *
@@ -333,6 +346,8 @@
 
     private final Executor mConsoleExecutor = Executors.newSingleThreadExecutor();
 
+    private ExecutorService mInputEventExecutor;
+
     /** The configuration that is currently associated with this VM. */
     @GuardedBy("mLock")
     @NonNull
@@ -907,8 +922,7 @@
 
         // Handle input devices here
         List<InputDevice> inputDevices = new ArrayList<>();
-        if (vmConfig.getCustomImageConfig() != null
-                && rawConfig.displayConfig != null) {
+        if (vmConfig.getCustomImageConfig() != null && rawConfig.displayConfig != null) {
             if (vmConfig.getCustomImageConfig().useTouch()) {
                 ParcelFileDescriptor[] pfds = ParcelFileDescriptor.createSocketPair();
                 mTouchSock = pfds[0];
@@ -983,6 +997,17 @@
 
     /** @hide */
     public boolean sendMouseEvent(MotionEvent event) {
+        try {
+            mInputEventQueue.add(Pair.create(InputEventType.MOUSE, event));
+            return true;
+        } catch (Exception e) {
+            Log.e(TAG, e.toString());
+            return false;
+        }
+    }
+
+    /** @hide */
+    private boolean sendMouseEventInternal(MotionEvent event) {
         if (mMouseSock == null) {
             Log.d(TAG, "mMouseSock == null");
             return false;
@@ -1071,6 +1096,17 @@
 
     /** @hide */
     public boolean sendMultiTouchEvent(MotionEvent event) {
+        try {
+            mInputEventQueue.add(Pair.create(InputEventType.TOUCH, event));
+            return true;
+        } catch (Exception e) {
+            Log.e(TAG, e.toString());
+            return false;
+        }
+    }
+
+    /** @hide */
+    private boolean sendMultiTouchEventInternal(MotionEvent event) {
         if (mTouchSock == null) {
             Log.d(TAG, "mTouchSock == null");
             return false;
@@ -1157,6 +1193,17 @@
 
     /** @hide */
     public boolean sendTrackpadEvent(MotionEvent event) {
+        try {
+            mInputEventQueue.add(Pair.create(InputEventType.TRACKPAD, event));
+            return true;
+        } catch (Exception e) {
+            Log.e(TAG, e.toString());
+            return false;
+        }
+    }
+
+    /** @hide */
+    private boolean sendTrackpadEventInternal(MotionEvent event) {
         if (mTrackpadSock == null) {
             Log.d(TAG, "mTrackpadSock == null");
             return false;
@@ -1476,7 +1523,29 @@
                 } else if (mVmOutputCaptured) {
                     consoleOutFd = mConsoleOutWriter;
                 }
-
+                mInputEventExecutor = Executors.newSingleThreadExecutor();
+                mInputEventExecutor.execute(
+                        () -> {
+                            while (true) {
+                                try {
+                                    Pair<InputEventType, MotionEvent> event =
+                                            mInputEventQueue.take();
+                                    switch (event.first) {
+                                        case TOUCH:
+                                            sendMultiTouchEventInternal(event.second);
+                                            break;
+                                        case TRACKPAD:
+                                            sendTrackpadEventInternal(event.second);
+                                            break;
+                                        case MOUSE:
+                                            sendMouseEventInternal(event.second);
+                                            break;
+                                    }
+                                } catch (Exception e) {
+                                    Log.e(TAG, e.toString());
+                                }
+                            }
+                        });
                 ParcelFileDescriptor consoleInFd = null;
                 if (mConnectVmConsole) {
                     consoleInFd = mPtyFd;
@@ -1738,6 +1807,9 @@
             try {
                 mVirtualMachine.stop();
                 dropVm();
+                if (mInputEventExecutor != null) {
+                    mInputEventExecutor.shutdownNow();
+                }
             } catch (RemoteException e) {
                 throw e.rethrowAsRuntimeException();
             } catch (ServiceSpecificException e) {