From 5b70661c458759e123a08a097cc8b3b58af74795 Mon Sep 17 00:00:00 2001
From: Solti Ho <solti@google.com>
Date: Sun, 11 Feb 2024 19:49:01 +0000
Subject: [PATCH] Revert "uinput: use nanoseconds for delay durations"

Revert submission 26154399

Reason for revert: b/324707605

Reverted changes: /q/submissionid:26154399

Change-Id: Ie1e20baefa998f0b69fd56ffa780ea3d3cd038db
---
 .../com/android/commands/uinput/Device.java   | 36 +++++--------------
 .../android/commands/uinput/EvemuParser.java  |  6 ++--
 .../com/android/commands/uinput/Event.java    | 14 ++++----
 .../commands/uinput/JsonStyleParser.java      |  3 +-
 .../com/android/commands/uinput/Uinput.java   |  2 +-
 .../uinput/tests/EvemuParserTest.java         | 10 +++---
 6 files changed, 26 insertions(+), 45 deletions(-)

diff --git a/cmds/uinput/src/com/android/commands/uinput/Device.java b/cmds/uinput/src/com/android/commands/uinput/Device.java
index 3cbc4986e330..787055c8cd89 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Device.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Device.java
@@ -55,7 +55,7 @@ public class Device {
     private final SparseArray<InputAbsInfo> mAbsInfo;
     private final OutputStream mOutputStream;
     private final Object mCond = new Object();
-    private long mTimeToSendNanos;
+    private long mTimeToSend;
 
     static {
         System.loadLibrary("uinputcommand_jni");
@@ -101,13 +101,7 @@ public class Device {
         }
 
         mHandler.obtainMessage(MSG_OPEN_UINPUT_DEVICE, args).sendToTarget();
-        mTimeToSendNanos = SystemClock.uptimeNanos();
-    }
-
-    private long getTimeToSendMillis() {
-        // This should be the same as (long) Math.ceil(mTimeToSendNanos / 1_000_000.0), except
-        // without the precision loss that comes from converting from long to double and back.
-        return mTimeToSendNanos / 1_000_000 + ((mTimeToSendNanos % 1_000_000 > 0) ? 1 : 0);
+        mTimeToSend = SystemClock.uptimeMillis();
     }
 
     /**
@@ -118,26 +112,16 @@ public class Device {
     public void injectEvent(int[] events) {
         // if two messages are sent at identical time, they will be processed in order received
         Message msg = mHandler.obtainMessage(MSG_INJECT_EVENT, events);
-        mHandler.sendMessageAtTime(msg, getTimeToSendMillis());
+        mHandler.sendMessageAtTime(msg, mTimeToSend);
     }
 
     /**
-     * Delay subsequent device activity by the specified amount of time.
-     *
-     * <p>Note that although the delay is specified in nanoseconds, due to limitations of {@link
-     * Handler}'s API, scheduling only occurs with millisecond precision. When scheduling an
-     * injection or sync, the time at which it is scheduled will be rounded up to the nearest
-     * millisecond. While this means that a particular injection cannot be scheduled precisely,
-     * rounding errors will not accumulate over time. For example, if five injections are scheduled
-     * with a delay of 1,200,000ns before each one, the total delay will be 6ms, as opposed to the
-     * 10ms it would have been if each individual delay had been rounded up (as {@link EvemuParser}
-     * would otherwise have to do to avoid sending timestamps that are in the future).
+     * Impose a delay to the device for execution.
      *
-     * @param delayNanos  Time to delay in unit of nanoseconds.
+     * @param delay  Time to delay in unit of milliseconds.
      */
-    public void addDelayNanos(long delayNanos) {
-        mTimeToSendNanos =
-                Math.max(SystemClock.uptimeNanos(), mTimeToSendNanos) + delayNanos;
+    public void addDelay(int delay) {
+        mTimeToSend = Math.max(SystemClock.uptimeMillis(), mTimeToSend) + delay;
     }
 
     /**
@@ -147,8 +131,7 @@ public class Device {
      * @param syncToken  The token for this sync command.
      */
     public void syncEvent(String syncToken) {
-        mHandler.sendMessageAtTime(
-                mHandler.obtainMessage(MSG_SYNC_EVENT, syncToken), getTimeToSendMillis());
+        mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_SYNC_EVENT, syncToken), mTimeToSend);
     }
 
     /**
@@ -157,8 +140,7 @@ public class Device {
      */
     public void close() {
         Message msg = mHandler.obtainMessage(MSG_CLOSE_UINPUT_DEVICE);
-        mHandler.sendMessageAtTime(
-                msg, Math.max(SystemClock.uptimeMillis(), getTimeToSendMillis()) + 1);
+        mHandler.sendMessageAtTime(msg, Math.max(SystemClock.uptimeMillis(), mTimeToSend) + 1);
         try {
             synchronized (mCond) {
                 mCond.wait();
diff --git a/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java b/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java
index cf9744d2172f..7652f2403f6e 100644
--- a/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java
+++ b/cmds/uinput/src/com/android/commands/uinput/EvemuParser.java
@@ -44,7 +44,7 @@ public class EvemuParser implements EventParser {
      * recordings, this will always be the same.
      */
     private static final int DEVICE_ID = 1;
-    private static final int REGISTRATION_DELAY_NANOS = 500_000_000;
+    private static final int REGISTRATION_DELAY_MILLIS = 500;
 
     private static class CommentAwareReader {
         private final LineNumberReader mReader;
@@ -152,7 +152,7 @@ public class EvemuParser implements EventParser {
         final Event.Builder delayEb = new Event.Builder();
         delayEb.setId(DEVICE_ID);
         delayEb.setCommand(Event.Command.DELAY);
-        delayEb.setDurationNanos(REGISTRATION_DELAY_NANOS);
+        delayEb.setDurationMillis(REGISTRATION_DELAY_MILLIS);
         mQueuedEvents.add(delayEb.build());
     }
 
@@ -204,7 +204,7 @@ public class EvemuParser implements EventParser {
                 final Event.Builder delayEb = new Event.Builder();
                 delayEb.setId(DEVICE_ID);
                 delayEb.setCommand(Event.Command.DELAY);
-                delayEb.setDurationNanos(delayMicros * 1000);
+                delayEb.setDurationMillis((int) (delayMicros / 1000));
                 return delayEb.build();
             }
         }
diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java
index c4b4f21f501f..0f16a27aac1d 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Event.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Event.java
@@ -100,7 +100,7 @@ public class Event {
     private int mBusId;
     private int[] mInjections;
     private SparseArray<int[]> mConfiguration;
-    private long mDurationNanos;
+    private int mDurationMillis;
     private int mFfEffectsMax = 0;
     private String mInputPort;
     private SparseArray<InputAbsInfo> mAbsInfo;
@@ -150,8 +150,8 @@ public class Event {
         return mConfiguration;
     }
 
-    public long getDurationNanos() {
-        return mDurationNanos;
+    public int getDurationMillis() {
+        return mDurationMillis;
     }
 
     public int getFfEffectsMax() {
@@ -182,7 +182,7 @@ public class Event {
             + ", busId=" + mBusId
             + ", events=" + Arrays.toString(mInjections)
             + ", configuration=" + mConfiguration
-            + ", duration=" + mDurationNanos + "ns"
+            + ", duration=" + mDurationMillis + "ms"
             + ", ff_effects_max=" + mFfEffectsMax
             + ", port=" + mInputPort
             + "}";
@@ -237,8 +237,8 @@ public class Event {
             mEvent.mBusId = busId;
         }
 
-        public void setDurationNanos(long durationNanos) {
-            mEvent.mDurationNanos = durationNanos;
+        public void setDurationMillis(int durationMillis) {
+            mEvent.mDurationMillis = durationMillis;
         }
 
         public void setFfEffectsMax(int ffEffectsMax) {
@@ -271,7 +271,7 @@ public class Event {
                     }
                 }
                 case DELAY -> {
-                    if (mEvent.mDurationNanos <= 0) {
+                    if (mEvent.mDurationMillis <= 0) {
                         throw new IllegalStateException("Delay has missing or invalid duration");
                     }
                 }
diff --git a/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java b/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java
index 6994f0cb0e4b..ed3ff33f7e52 100644
--- a/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java
+++ b/cmds/uinput/src/com/android/commands/uinput/JsonStyleParser.java
@@ -71,8 +71,7 @@ public class JsonStyleParser implements EventParser {
                         case "configuration" -> eb.setConfiguration(readConfiguration());
                         case "ff_effects_max" -> eb.setFfEffectsMax(readInt());
                         case "abs_info" -> eb.setAbsInfo(readAbsInfoArray());
-                        // Duration is specified in milliseconds in the JSON-style format.
-                        case "duration" -> eb.setDurationNanos(readInt() * 1_000_000L);
+                        case "duration" -> eb.setDurationMillis(readInt());
                         case "port" -> eb.setInputPort(mReader.nextString());
                         case "syncToken" -> eb.setSyncToken(mReader.nextString());
                         default -> mReader.skipValue();
diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
index 0ef26382850e..04df27987d58 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Uinput.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
@@ -135,7 +135,7 @@ public class Uinput {
             case REGISTER ->
                     error("Device id=" + e.getId() + " is already registered. Ignoring event.");
             case INJECT -> d.injectEvent(e.getInjections());
-            case DELAY -> d.addDelayNanos(e.getDurationNanos());
+            case DELAY -> d.addDelay(e.getDurationMillis());
             case SYNC -> d.syncEvent(e.getSyncToken());
         }
     }
diff --git a/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java b/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java
index 140045226cbb..06b0aac271ad 100644
--- a/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java
+++ b/cmds/uinput/tests/src/com/android/commands/uinput/tests/EvemuParserTest.java
@@ -189,10 +189,10 @@ public class EvemuParserTest {
                 .containsExactly(eventType, eventCode, value).inOrder();
     }
 
-    private void assertDelayEvent(Event event, int durationMicros) {
+    private void assertDelayEvent(Event event, int durationMillis) {
         assertThat(event).isNotNull();
         assertThat(event.getCommand()).isEqualTo(Event.Command.DELAY);
-        assertThat(event.getDurationMicros()).isEqualTo(durationMicros);
+        assertThat(event.getDurationMillis()).isEqualTo(durationMillis);
     }
 
     @Test
@@ -231,12 +231,12 @@ public class EvemuParserTest {
         assertInjectEvent(parser.getNextEvent(), 0x1, 0x15, 1);
         assertInjectEvent(parser.getNextEvent(), 0x0, 0x0, 0);
 
-        assertDelayEvent(parser.getNextEvent(), 10000);
+        assertDelayEvent(parser.getNextEvent(), 10);
 
         assertInjectEvent(parser.getNextEvent(), 0x1, 0x15, 0);
         assertInjectEvent(parser.getNextEvent(), 0x0, 0x0, 0);
 
-        assertDelayEvent(parser.getNextEvent(), 1000000);
+        assertDelayEvent(parser.getNextEvent(), 1000);
 
         assertInjectEvent(parser.getNextEvent(), 0x1, 0x15, 1);
         assertInjectEvent(parser.getNextEvent(), 0x0, 0x0, 0);
@@ -490,7 +490,7 @@ public class EvemuParserTest {
         assertInjectEvent(parser.getNextEvent(), 0x3, 0x18, 56);
         assertInjectEvent(parser.getNextEvent(), 0x0, 0x0, 0);
 
-        assertDelayEvent(parser.getNextEvent(), 6080);
+        assertDelayEvent(parser.getNextEvent(), 6);
 
         assertInjectEvent(parser.getNextEvent(), 0x3, 0x0035, 888);
     }
-- 
GitLab