Merge "Align all offsets to word boundary."
diff --git a/include/fmq/MessageQueue.h b/include/fmq/MessageQueue.h
index eaaad02..730a638 100644
--- a/include/fmq/MessageQueue.h
+++ b/include/fmq/MessageQueue.h
@@ -31,7 +31,7 @@
 
 template <typename T, MQFlavor flavor>
 struct MessageQueue {
-    typedef MQDescriptor<T,flavor> Descriptor;
+    typedef MQDescriptor<T, flavor> Descriptor;
 
     /**
      * @param Desc MQDescriptor describing the FMQ.
@@ -332,11 +332,13 @@
     }
 
     /*
-     * Ashmem memory region size needs to
-     * be specified in page-aligned bytes.
+     * Ashmem memory region size needs to be specified in page-aligned bytes.
+     * kQueueSizeBytes needs to be aligned to word boundary so that all offsets
+     * in the grantorDescriptor will be word aligned.
      */
     size_t kAshmemSizePageAligned =
-            (kQueueSizeBytes + kMetaDataSize + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+            (Descriptor::alignToWordBoundary(kQueueSizeBytes) + kMetaDataSize + PAGE_SIZE - 1) &
+            ~(PAGE_SIZE - 1);
 
     /*
      * Create an ashmem region to map the memory for the ringbuffer,
@@ -463,7 +465,7 @@
          * notification.
          */
         status_t status = evFlag->wait(readNotification, &efState, timeOutNanos);
-        switch(status) {
+        switch (status) {
             case android::NO_ERROR:
                 /*
                  * If wait() returns NO_ERROR, break and check efState.
@@ -561,7 +563,7 @@
          * notification.
          */
         status_t status = evFlag->wait(writeNotification, &efState, timeOutNanos);
-        switch(status) {
+        switch (status) {
             case android::NO_ERROR:
                 /*
                  * If wait() returns NO_ERROR, break and check efState.
diff --git a/tests/mq_test.cpp b/tests/mq_test.cpp
index 1cafe97..3748cfe 100644
--- a/tests/mq_test.cpp
+++ b/tests/mq_test.cpp
@@ -94,6 +94,32 @@
     size_t mNumMessagesMax = 0;
 };
 
+class QueueSizeOdd : public ::testing::Test {
+ protected:
+  virtual void TearDown() {
+      delete mQueue;
+  }
+  virtual void SetUp() {
+      static constexpr size_t kNumElementsInQueue = 2049;
+      mQueue = new (std::nothrow) android::hardware::MessageQueue<
+              uint8_t, android::hardware::kSynchronizedReadWrite>(kNumElementsInQueue,
+                                                                  true /* configureEventFlagWord */);
+      ASSERT_NE(nullptr, mQueue);
+      ASSERT_TRUE(mQueue->isValid());
+      mNumMessagesMax = mQueue->getQuantumCount();
+      ASSERT_EQ(kNumElementsInQueue, mNumMessagesMax);
+      auto evFlagWordPtr = mQueue->getEventFlagWord();
+      ASSERT_NE(nullptr, evFlagWordPtr);
+      /*
+       * Initialize the EventFlag word to indicate Queue is not full.
+       */
+      std::atomic_init(evFlagWordPtr, static_cast<uint32_t>(kFmqNotFull));
+  }
+
+  android::hardware::MessageQueue<uint8_t, android::hardware::kSynchronizedReadWrite>* mQueue;
+  size_t mNumMessagesMax = 0;
+};
+
 /*
  * This thread will attempt to read and block. When wait returns
  * it checks if the kFmqNotEmpty bit is actually set.
@@ -248,6 +274,22 @@
 }
 
 /*
+ * Test that odd queue sizes do not cause unaligned error
+ * on access to EventFlag object.
+ */
+TEST_F(QueueSizeOdd, EventFlagTest) {
+    const size_t dataLen = 64;
+    uint8_t data[dataLen] = {0};
+
+    bool ret = mQueue->writeBlocking(data,
+                                     dataLen,
+                                     static_cast<uint32_t>(kFmqNotFull),
+                                     static_cast<uint32_t>(kFmqNotEmpty),
+                                     5000000000 /* timeOutNanos */);
+    ASSERT_TRUE(ret);
+}
+
+/*
  * Verify that a few bytes of data can be successfully written and read.
  */
 TEST_F(SynchronizedReadWrites, SmallInputTest1) {