[AWARE] Measure message transmission latency

Add tests to measure the latency of message transmission for different
DW (Discovery Window) configurations. The message transmission is
measured without queueing - i.e. Tx waits for confirmation before
sending the next message.

Bug: 31940045
Test: new latency tests showing expected results
Change-Id: I3b8bf343c20905463754b2b5d371d3b557e0b7cd
diff --git a/acts/tests/google/wifi/aware/performance/LatencyTest.py b/acts/tests/google/wifi/aware/performance/LatencyTest.py
index 8aa9c58..3deca59 100644
--- a/acts/tests/google/wifi/aware/performance/LatencyTest.py
+++ b/acts/tests/google/wifi/aware/performance/LatencyTest.py
@@ -25,6 +25,7 @@
 
 class LatencyTest(AwareBaseTest):
   """Set of tests for Wi-Fi Aware to measure latency of Aware operations."""
+  SERVICE_NAME = "GoogleTestServiceXY"
 
   # number of second to 'reasonably' wait to make sure that devices synchronize
   # with each other - useful for OOB test cases, where the OOB discovery would
@@ -155,6 +156,100 @@
     p_dut.droid.wifiAwareDestroyAll()
     s_dut.droid.wifiAwareDestroyAll()
 
+  def run_message_latency(self, results, dw_24ghz, dw_5ghz, num_iterations):
+    """Run the message tx latency test with the specified DW intervals.
+
+    Args:
+      results: Result array to be populated - will add results (not erase it)
+      dw_24ghz: DW interval in the 2.4GHz band.
+      dw_5ghz: DW interval in the 5GHz band.
+    """
+    key = "dw24_%d_dw5_%d" % (dw_24ghz, dw_5ghz)
+    results[key] = {}
+    results[key]["num_iterations"] = num_iterations
+
+    p_dut = self.android_devices[0]
+    s_dut = self.android_devices[1]
+
+    # override the default DW configuration
+    autils.configure_dw(p_dut, is_default=True, is_24_band=True, value=dw_24ghz)
+    autils.configure_dw(
+        p_dut, is_default=False, is_24_band=True, value=dw_24ghz)
+    autils.configure_dw(p_dut, is_default=True, is_24_band=False, value=dw_5ghz)
+    autils.configure_dw(
+        p_dut, is_default=False, is_24_band=False, value=dw_5ghz)
+    autils.configure_dw(s_dut, is_default=True, is_24_band=True, value=dw_24ghz)
+    autils.configure_dw(
+        s_dut, is_default=False, is_24_band=True, value=dw_24ghz)
+    autils.configure_dw(s_dut, is_default=True, is_24_band=False, value=dw_5ghz)
+    autils.configure_dw(
+        s_dut, is_default=False, is_24_band=False, value=dw_5ghz)
+
+    # Start up a discovery session
+    (p_id, s_id, p_disc_id, s_disc_id,
+     peer_id_on_sub) = autils.create_discovery_pair(
+         p_dut,
+         s_dut,
+         p_config=autils.create_discovery_config(
+             self.SERVICE_NAME, aconsts.PUBLISH_TYPE_UNSOLICITED),
+         s_config=autils.create_discovery_config(
+             self.SERVICE_NAME, aconsts.SUBSCRIBE_TYPE_PASSIVE))
+
+    latencies = []
+    failed_tx = 0
+    messages_rx = 0
+    missing_rx = 0
+    corrupted_rx = 0
+    for i in range(num_iterations):
+      # send message
+      msg_s2p = "Message Subscriber -> Publisher #%d" % i
+      next_msg_id = self.get_next_msg_id()
+      s_dut.droid.wifiAwareSendMessage(s_disc_id, peer_id_on_sub, next_msg_id,
+                                       msg_s2p, 0)
+
+      # wait for Tx confirmation
+      try:
+        sub_tx_msg_event = s_dut.ed.pop_event(
+            aconsts.SESSION_CB_ON_MESSAGE_SENT, 2 * autils.EVENT_TIMEOUT)
+        latencies.append(
+            sub_tx_msg_event["data"][aconsts.SESSION_CB_KEY_LATENCY_MS])
+      except queue.Empty:
+        s_dut.log.info("[Subscriber] Timed out while waiting for "
+                       "SESSION_CB_ON_MESSAGE_SENT")
+        failed_tx = failed_tx + 1
+        continue
+
+      # wait for Rx confirmation (and validate contents)
+      try:
+        pub_rx_msg_event = p_dut.ed.pop_event(
+            aconsts.SESSION_CB_ON_MESSAGE_RECEIVED, 2 * autils.EVENT_TIMEOUT)
+        messages_rx = messages_rx + 1
+        if (pub_rx_msg_event["data"][aconsts.SESSION_CB_KEY_MESSAGE_AS_STRING]
+            != msg_s2p):
+          corrupted_rx = corrupted_rx + 1
+      except queue.Empty:
+        s_dut.log.info("[Publisher] Timed out while waiting for "
+                       "SESSION_CB_ON_MESSAGE_RECEIVED")
+        missing_rx = missing_rx + 1
+        continue
+
+    autils.extract_stats(
+        s_dut,
+        data=latencies,
+        results=results[key],
+        key_prefix="",
+        log_prefix="Subscribe Session Discovery (dw24=%d, dw5=%d)" %
+                   (dw_24ghz, dw_5ghz))
+    results[key]["failed_tx"] = failed_tx
+    results[key]["messages_rx"] = messages_rx
+    results[key]["missing_rx"] = missing_rx
+    results[key]["corrupted_rx"] = corrupted_rx
+
+    # clean up
+    p_dut.droid.wifiAwareDestroyAll()
+    s_dut.droid.wifiAwareDestroyAll()
+
+
   ########################################################################
 
   def test_discovery_latency_default_dws(self):
@@ -191,3 +286,24 @@
             num_iterations=10)
     asserts.explicit_pass(
         "test_discovery_latency_all_dws finished", extras=results)
+
+  def test_message_latency_default_dws(self):
+    """Measure the send message latency with the default DW configuration. Test
+    performed on non-queued message transmission - i.e. waiting for confirmation
+    of reception (ACK) before sending the next message."""
+    results = {}
+    self.run_message_latency(
+        results=results, dw_24ghz=1, dw_5ghz=1, num_iterations=100)
+    asserts.explicit_pass(
+        "test_message_latency_default_dws finished", extras=results)
+
+  def test_message_latency_non_interactive_dws(self):
+    """Measure the send message latency with the DW configuration for
+    non-interactive mode. Test performed on non-queued message transmission -
+    i.e. waiting for confirmation of reception (ACK) before sending the next
+    message."""
+    results = {}
+    self.run_message_latency(
+        results=results, dw_24ghz=4, dw_5ghz=0, num_iterations=100)
+    asserts.explicit_pass(
+        "test_message_latency_non_interactive_dws finished", extras=results)