Snap for 10338099 from dd44e1b38af3a21ec7e245033deece4e0d2cfd2b to udc-release

Change-Id: I50af16df5516d7c779a8159b04c6f0b94946b6ac
diff --git a/host/tinysys/hal/tinysys_chre_connection.cc b/host/tinysys/hal/tinysys_chre_connection.cc
index 0a02164..22ef714 100644
--- a/host/tinysys/hal/tinysys_chre_connection.cc
+++ b/host/tinysys/hal/tinysys_chre_connection.cc
@@ -80,8 +80,9 @@
     return false;
   }
   mLogger.init();
-  // launch the listener tasks
+  // launch the tasks
   mMessageListener = std::thread(messageListenerTask, this);
+  mMessageSender = std::thread(messageSenderTask, this);
   mStateListener = std::thread(chreStateMonitorTask, this);
   mLpmaHandler.init();
   return true;
@@ -138,25 +139,35 @@
   }
 }
 
+[[noreturn]] void TinysysChreConnection::messageSenderTask(
+    TinysysChreConnection *chreConnection) {
+  LOGI("Message sender task is launched.");
+  int chreFd = chreConnection->getChreFileDescriptor();
+  while (true) {
+    chreConnection->mQueue.waitForMessage();
+    ChreConnectionMessage &message = chreConnection->mQueue.front();
+    auto size =
+        TEMP_FAILURE_RETRY(write(chreFd, &message, message.getMessageSize()));
+    if (size < 0) {
+      LOGE("Failed to write to chre file descriptor. errno=%d\n", errno);
+    }
+    chreConnection->mQueue.pop();
+  }
+}
+
 bool TinysysChreConnection::sendMessage(void *data, size_t length) {
   if (length <= 0 || length > kMaxPayloadBytes) {
     LOGE("length %zu is not within the accepted range.", length);
     return false;
   }
-  mChreMessage->setData(data, length);
-  auto size = TEMP_FAILURE_RETRY(write(mChreFileDescriptor, mChreMessage.get(),
-                                       mChreMessage->getMessageSize()));
-  if (size < 0) {
-    LOGE("Failed to write to chre file descriptor. errno=%d\n", errno);
-    return false;
-  }
-  return true;
+  return mQueue.emplace(data, length);
 }
 
 void TinysysChreConnection::handleMessageFromChre(
     TinysysChreConnection *chreConnection, const unsigned char *messageBuffer,
     size_t messageLen) {
-  // TODO(b/267188769): Move the wake lock acquisition/release to RAII pattern.
+  // TODO(b/267188769): Move the wake lock acquisition/release to RAII
+  // pattern.
   bool isWakelockAcquired =
       acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock) == 0;
   if (!isWakelockAcquired) {
diff --git a/host/tinysys/hal/tinysys_chre_connection.h b/host/tinysys/hal/tinysys_chre_connection.h
index 7b3dbae..e42b0c4 100644
--- a/host/tinysys/hal/tinysys_chre_connection.h
+++ b/host/tinysys/hal/tinysys_chre_connection.h
@@ -26,6 +26,8 @@
 
 #include <unistd.h>
 #include <cassert>
+#include <future>
+#include <queue>
 #include <thread>
 
 using ::android::chre::StHalLpmaHandler;
@@ -41,7 +43,6 @@
   TinysysChreConnection(ChreConnectionCallback *callback)
       : mCallback(callback), mLpmaHandler(/* allowed= */ true) {
     mPayload = std::make_unique<uint8_t[]>(kMaxPayloadBytes);
-    mChreMessage = std::make_unique<ChreConnectionMessage>();
   };
 
   ~TinysysChreConnection() override {
@@ -50,6 +51,9 @@
     if (mMessageListener.joinable()) {
       mMessageListener.join();
     }
+    if (mMessageSender.joinable()) {
+      mMessageSender.join();
+    }
     if (mStateListener.joinable()) {
       mStateListener.join();
     }
@@ -89,6 +93,9 @@
   // The path to CHRE file descriptor
   static constexpr char kChreFileDescriptorPath[] = "/dev/scp_chre_manager";
 
+  // Max queue size for sending messages to CHRE
+  static constexpr size_t kMaxSynchronousMessageQueueSize = 64;
+
   // Wrapper for a message sent to CHRE
   struct ChreConnectionMessage {
     // This magic number is the SCP_CHRE_MAGIC constant defined by kernel
@@ -98,7 +105,7 @@
     uint32_t payloadSize = 0;
     uint8_t payload[kMaxPayloadBytes];
 
-    void setData(void *data, size_t length) {
+    ChreConnectionMessage(void *data, size_t length) {
       assert(length <= kMaxPayloadBytes);
       memcpy(payload, data, length);
       payloadSize = static_cast<uint32_t>(length);
@@ -109,10 +116,49 @@
     }
   };
 
+  // A queue suitable for multiple producers and a single consumer.
+  class SynchronousMessageQueue {
+   public:
+    bool emplace(void *data, size_t length) {
+      std::unique_lock<std::mutex> lock(mMutex);
+      if (mQueue.size() >= kMaxSynchronousMessageQueueSize) {
+        LOGE("Message queue from HAL to CHRE is full!");
+        return false;
+      }
+      mQueue.emplace(data, length);
+      mCv.notify_all();
+      return true;
+    }
+
+    void pop() {
+      std::unique_lock<std::mutex> lock(mMutex);
+      mQueue.pop();
+    }
+
+    ChreConnectionMessage &front() {
+      std::unique_lock<std::mutex> lock(mMutex);
+      return mQueue.front();
+    }
+
+    void waitForMessage() {
+      std::unique_lock<std::mutex> lock(mMutex);
+      mCv.wait(lock, [&]() { return !mQueue.empty(); });
+    }
+
+   private:
+    std::mutex mMutex;
+    std::condition_variable mCv;
+    std::queue<ChreConnectionMessage> mQueue;
+  };
+
   // The task receiving message from CHRE
   [[noreturn]] static void messageListenerTask(
       TinysysChreConnection *chreConnection);
 
+  // The task sending message to CHRE
+  [[noreturn]] static void messageSenderTask(
+      TinysysChreConnection *chreConnection);
+
   // The task receiving CHRE state update
   [[noreturn]] static void chreStateMonitorTask(
       TinysysChreConnection *chreConnection);
@@ -130,19 +176,21 @@
   // The calback function that should be implemented by HAL
   ChreConnectionCallback *mCallback;
 
-  // the message listener thread that hosts messageListenerTask
+  // the message listener thread that receives messages from CHRE
   std::thread mMessageListener;
+  // the message sender thread that sends messages to CHRE
+  std::thread mMessageSender;
   // the status listener thread that hosts chreStateMonitorTask
   std::thread mStateListener;
 
   // Payload received from CHRE
   std::unique_ptr<uint8_t[]> mPayload;
 
-  // message to be sent to CHRE
-  std::unique_ptr<ChreConnectionMessage> mChreMessage;
-
-  //! The LPMA handler to talk to the ST HAL
+  // The LPMA handler to talk to the ST HAL
   StHalLpmaHandler mLpmaHandler;
+
+  // For messages sent to CHRE
+  SynchronousMessageQueue mQueue;
 };
 }  // namespace aidl::android::hardware::contexthub