Merge "Implement waitFor (interface) to avoid polling interface state"
diff --git a/automotive/evs/1.0/default/EvsCamera.cpp b/automotive/evs/1.0/default/EvsCamera.cpp
index e0782ec..0daea5a 100644
--- a/automotive/evs/1.0/default/EvsCamera.cpp
+++ b/automotive/evs/1.0/default/EvsCamera.cpp
@@ -49,7 +49,7 @@
 
     mDescription.cameraId = id;
 
-    // Set up dummy data for testing
+    // Set up mock data for testing
     if (mDescription.cameraId == kCameraName_Backup) {
         mWidth  = 640;          // full NTSC/VGA
         mHeight = 480;          // full NTSC/VGA
diff --git a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
index 7fe7a33..ad607d8 100644
--- a/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
+++ b/automotive/evs/1.0/vts/functional/VtsHalEvsV1_0TargetTest.cpp
@@ -369,7 +369,7 @@
 TEST_P(EvsHidlTest, CameraStreamBuffering) {
     ALOGI("Starting CameraStreamBuffering test");
 
-    // Arbitrary constant (should be > 1 and less than crazy)
+    // Arbitrary constant (should be > 1 and not too big)
     static const unsigned int kBuffersToHold = 6;
 
     // Get the camera list
@@ -381,7 +381,7 @@
         sp<IEvsCamera> pCam = pEnumerator->openCamera(cam.cameraId);
         ASSERT_NE(pCam, nullptr);
 
-        // Ask for a crazy number of buffers in flight to ensure it errors correctly
+        // Ask for a very large number of buffers in flight to ensure it errors correctly
         Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
         EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
 
diff --git a/automotive/evs/1.1/default/ConfigManager.h b/automotive/evs/1.1/default/ConfigManager.h
index 870af1c..b0b2670 100644
--- a/automotive/evs/1.1/default/ConfigManager.h
+++ b/automotive/evs/1.1/default/ConfigManager.h
@@ -76,7 +76,7 @@
         }
 
         /*
-         * List of supported controls that the master client can program.
+         * List of supported controls that the primary client can program.
          * Paraemters are stored with its valid range
          */
         unordered_map<CameraParam,
diff --git a/automotive/evs/1.1/default/EvsEnumerator.cpp b/automotive/evs/1.1/default/EvsEnumerator.cpp
index 117ee7a..d066471 100644
--- a/automotive/evs/1.1/default/EvsEnumerator.cpp
+++ b/automotive/evs/1.1/default/EvsEnumerator.cpp
@@ -70,7 +70,7 @@
 
     // Add ultrasonics array desc.
     sUltrasonicsArrayRecordList.emplace_back(
-            EvsUltrasonicsArray::GetDummyArrayDesc("front_array"));
+            EvsUltrasonicsArray::GetMockArrayDesc("front_array"));
 }
 
 
diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
index bc69aa4..ebd47c6 100644
--- a/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.cpp
@@ -45,7 +45,7 @@
 
 namespace {
 
-void fillDummyArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
+void fillMockArrayDesc(UltrasonicsArrayDesc& arrayDesc) {
     arrayDesc.maxReadingsPerSensorCount = kMaxReadingsPerSensor;
     arrayDesc.maxReceiversCount = kMaxReceiversCount;
 
@@ -99,8 +99,8 @@
     }
 }
 
-// Fills dataFrameDesc with dummy data.
-bool fillDummyDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
+// Fills dataFrameDesc with mock data.
+bool fillMockDataFrame(UltrasonicsDataFrameDesc& dataFrameDesc, sp<IMemory> pIMemory) {
     dataFrameDesc.timestampNs = elapsedRealtimeNano();
 
     const std::vector<uint8_t> transmittersIdList = {0};
@@ -137,9 +137,9 @@
     : mFramesAllowed(0), mFramesInUse(0), mStreamState(STOPPED) {
     LOG(DEBUG) << "EvsUltrasonicsArray instantiated";
 
-    // Set up dummy data for description.
+    // Set up mock data for description.
     mArrayDesc.ultrasonicsArrayId = deviceName;
-    fillDummyArrayDesc(mArrayDesc);
+    fillMockArrayDesc(mArrayDesc);
 
     // Assign allocator.
     mShmemAllocator = IAllocator::getService("ashmem");
@@ -182,10 +182,10 @@
     mStreamState = DEAD;
 }
 
-UltrasonicsArrayDesc EvsUltrasonicsArray::GetDummyArrayDesc(const char* deviceName) {
+UltrasonicsArrayDesc EvsUltrasonicsArray::GetMockArrayDesc(const char* deviceName) {
     UltrasonicsArrayDesc ultrasonicsArrayDesc;
     ultrasonicsArrayDesc.ultrasonicsArrayId = deviceName;
-    fillDummyArrayDesc(ultrasonicsArrayDesc);
+    fillMockArrayDesc(ultrasonicsArrayDesc);
     return ultrasonicsArrayDesc;
 }
 
@@ -497,17 +497,17 @@
 
         if (timeForFrame) {
             // Assemble the buffer description we'll transmit below
-            UltrasonicsDataFrameDesc dummyDataFrameDesc;
-            dummyDataFrameDesc.dataFrameId = idx;
-            dummyDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
+            UltrasonicsDataFrameDesc mockDataFrameDesc;
+            mockDataFrameDesc.dataFrameId = idx;
+            mockDataFrameDesc.waveformsData = mDataFrames[idx].sharedMemory.hidlMemory;
 
-            // Fill dummy waveform data.
-            fillDummyDataFrame(dummyDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
+            // Fill mock waveform data.
+            fillMockDataFrame(mockDataFrameDesc, mDataFrames[idx].sharedMemory.pIMemory);
 
             // Issue the (asynchronous) callback to the client -- can't be holding the lock
-            auto result = mStream->deliverDataFrame(dummyDataFrameDesc);
+            auto result = mStream->deliverDataFrame(mockDataFrameDesc);
             if (result.isOk()) {
-                LOG(DEBUG) << "Delivered data frame id: " << dummyDataFrameDesc.dataFrameId;
+                LOG(DEBUG) << "Delivered data frame id: " << mockDataFrameDesc.dataFrameId;
             } else {
                 // This can happen if the client dies and is likely unrecoverable.
                 // To avoid consuming resources generating failing calls, we stop sending
diff --git a/automotive/evs/1.1/default/EvsUltrasonicsArray.h b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
index 7a41012..88aa600 100644
--- a/automotive/evs/1.1/default/EvsUltrasonicsArray.h
+++ b/automotive/evs/1.1/default/EvsUltrasonicsArray.h
@@ -58,7 +58,7 @@
     static sp<EvsUltrasonicsArray> Create(const char* deviceName);
 
     // Returns a ultrasonics array descriptor filled with sample data.
-    static UltrasonicsArrayDesc GetDummyArrayDesc(const char* id);
+    static UltrasonicsArrayDesc GetMockArrayDesc(const char* id);
 
     DISALLOW_COPY_AND_ASSIGN(EvsUltrasonicsArray);
     virtual ~EvsUltrasonicsArray() override;
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 4398fb1..638ecd5 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -500,7 +500,7 @@
 TEST_P(EvsHidlTest, CameraStreamBuffering) {
     LOG(INFO) << "Starting CameraStreamBuffering test";
 
-    // Arbitrary constant (should be > 1 and less than crazy)
+    // Arbitrary constant (should be > 1 and not too big)
     static const unsigned int kBuffersToHold = 6;
 
     // Get the camera list
@@ -527,7 +527,7 @@
         // Store a camera handle for a clean-up
         activeCameras.push_back(pCam);
 
-        // Ask for a crazy number of buffers in flight to ensure it errors correctly
+        // Ask for a very large number of buffers in flight to ensure it errors correctly
         Return<EvsResult> badResult = pCam->setMaxFramesInFlight(0xFFFFFFFF);
         EXPECT_EQ(EvsResult::BUFFER_NOT_AVAILABLE, badResult);
 
@@ -930,12 +930,12 @@
 
 
 /*
- * CameraMasterRelease
- * Verify that non-master client gets notified when the master client either
+ * CameraPrimaryClientRelease
+ * Verify that non-primary client gets notified when the primary client either
  * terminates or releases a role.
  */
-TEST_P(EvsHidlTest, CameraMasterRelease) {
-    LOG(INFO) << "Starting CameraMasterRelease test";
+TEST_P(EvsHidlTest, CameraPrimaryClientRelease) {
+    LOG(INFO) << "Starting CameraPrimaryClientRelease test";
 
     if (mIsHwModule) {
         // This test is not for HW module implementation.
@@ -961,57 +961,57 @@
         }
 
         // Create two camera clients.
-        sp<IEvsCamera_1_1> pCamMaster =
+        sp<IEvsCamera_1_1> pCamPrimary =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
-        ASSERT_NE(pCamMaster, nullptr);
+        ASSERT_NE(pCamPrimary, nullptr);
 
         // Store a camera handle for a clean-up
-        activeCameras.push_back(pCamMaster);
+        activeCameras.push_back(pCamPrimary);
 
-        sp<IEvsCamera_1_1> pCamNonMaster =
+        sp<IEvsCamera_1_1> pCamSecondary =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
-        ASSERT_NE(pCamNonMaster, nullptr);
+        ASSERT_NE(pCamSecondary, nullptr);
 
         // Store a camera handle for a clean-up
-        activeCameras.push_back(pCamNonMaster);
+        activeCameras.push_back(pCamSecondary);
 
         // Set up per-client frame receiver objects which will fire up its own thread
-        sp<FrameHandler> frameHandlerMaster =
-            new FrameHandler(pCamMaster, cam,
+        sp<FrameHandler> frameHandlerPrimary =
+            new FrameHandler(pCamPrimary, cam,
                              nullptr,
                              FrameHandler::eAutoReturn);
-        ASSERT_NE(frameHandlerMaster, nullptr);
-        sp<FrameHandler> frameHandlerNonMaster =
-            new FrameHandler(pCamNonMaster, cam,
+        ASSERT_NE(frameHandlerPrimary, nullptr);
+        sp<FrameHandler> frameHandlerSecondary =
+            new FrameHandler(pCamSecondary, cam,
                              nullptr,
                              FrameHandler::eAutoReturn);
-        ASSERT_NE(frameHandlerNonMaster, nullptr);
+        ASSERT_NE(frameHandlerSecondary, nullptr);
 
-        // Set one client as the master
-        EvsResult result = pCamMaster->setMaster();
+        // Set one client as the primary client
+        EvsResult result = pCamPrimary->setMaster();
         ASSERT_TRUE(result == EvsResult::OK);
 
-        // Try to set another client as the master.
-        result = pCamNonMaster->setMaster();
+        // Try to set another client as the primary client.
+        result = pCamSecondary->setMaster();
         ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
 
-        // Start the camera's video stream via a master client.
-        bool startResult = frameHandlerMaster->startStream();
+        // Start the camera's video stream via a primary client client.
+        bool startResult = frameHandlerPrimary->startStream();
         ASSERT_TRUE(startResult);
 
         // Ensure the stream starts
-        frameHandlerMaster->waitForFrameCount(1);
+        frameHandlerPrimary->waitForFrameCount(1);
 
         // Start the camera's video stream via another client
-        startResult = frameHandlerNonMaster->startStream();
+        startResult = frameHandlerSecondary->startStream();
         ASSERT_TRUE(startResult);
 
         // Ensure the stream starts
-        frameHandlerNonMaster->waitForFrameCount(1);
+        frameHandlerSecondary->waitForFrameCount(1);
 
-        // Non-master client expects to receive a master role relesed
+        // Non-primary client expects to receive a primary client role relesed
         // notification.
         EvsEventDesc aTargetEvent  = {};
         EvsEventDesc aNotification = {};
@@ -1020,14 +1020,14 @@
         std::mutex eventLock;
         std::condition_variable eventCond;
         std::thread listener = std::thread(
-            [&aNotification, &frameHandlerNonMaster, &listening, &eventCond]() {
+            [&aNotification, &frameHandlerSecondary, &listening, &eventCond]() {
                 // Notify that a listening thread is running.
                 listening = true;
                 eventCond.notify_all();
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
-                if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+                if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification, true)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
 
@@ -1043,8 +1043,8 @@
         }
         lock.unlock();
 
-        // Release a master role.
-        pCamMaster->unsetMaster();
+        // Release a primary client role.
+        pCamPrimary->unsetMaster();
 
         // Join a listening thread.
         if (listener.joinable()) {
@@ -1055,24 +1055,24 @@
         ASSERT_EQ(EvsEventType::MASTER_RELEASED,
                   static_cast<EvsEventType>(aNotification.aType));
 
-        // Non-master becomes a master.
-        result = pCamNonMaster->setMaster();
+        // Non-primary becomes a primary client.
+        result = pCamSecondary->setMaster();
         ASSERT_TRUE(result == EvsResult::OK);
 
-        // Previous master client fails to become a master.
-        result = pCamMaster->setMaster();
+        // Previous primary client fails to become a primary client.
+        result = pCamPrimary->setMaster();
         ASSERT_TRUE(result == EvsResult::OWNERSHIP_LOST);
 
         listening = false;
         listener = std::thread(
-            [&aNotification, &frameHandlerMaster, &listening, &eventCond]() {
+            [&aNotification, &frameHandlerPrimary, &listening, &eventCond]() {
                 // Notify that a listening thread is running.
                 listening = true;
                 eventCond.notify_all();
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
-                if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
+                if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification, true)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
 
@@ -1087,8 +1087,8 @@
         }
         lock.unlock();
 
-        // Closing current master client.
-        frameHandlerNonMaster->shutdown();
+        // Closing current primary client.
+        frameHandlerSecondary->shutdown();
 
         // Join a listening thread.
         if (listener.joinable()) {
@@ -1100,11 +1100,11 @@
                   static_cast<EvsEventType>(aNotification.aType));
 
         // Closing streams.
-        frameHandlerMaster->shutdown();
+        frameHandlerPrimary->shutdown();
 
         // Explicitly release the camera
-        pEnumerator->closeCamera(pCamMaster);
-        pEnumerator->closeCamera(pCamNonMaster);
+        pEnumerator->closeCamera(pCamPrimary);
+        pEnumerator->closeCamera(pCamSecondary);
         activeCameras.clear();
     }
 }
@@ -1112,7 +1112,7 @@
 
 /*
  * MultiCameraParameter:
- * Verify that master and non-master clients behave as expected when they try to adjust
+ * Verify that primary and non-primary clients behave as expected when they try to adjust
  * camera parameters.
  */
 TEST_P(EvsHidlTest, MultiCameraParameter) {
@@ -1142,88 +1142,88 @@
         }
 
         // Create two camera clients.
-        sp<IEvsCamera_1_1> pCamMaster =
+        sp<IEvsCamera_1_1> pCamPrimary =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
-        ASSERT_NE(pCamMaster, nullptr);
+        ASSERT_NE(pCamPrimary, nullptr);
 
         // Store a camera handle for a clean-up
-        activeCameras.push_back(pCamMaster);
+        activeCameras.push_back(pCamPrimary);
 
-        sp<IEvsCamera_1_1> pCamNonMaster =
+        sp<IEvsCamera_1_1> pCamSecondary =
             IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
             .withDefault(nullptr);
-        ASSERT_NE(pCamNonMaster, nullptr);
+        ASSERT_NE(pCamSecondary, nullptr);
 
         // Store a camera handle for a clean-up
-        activeCameras.push_back(pCamNonMaster);
+        activeCameras.push_back(pCamSecondary);
 
         // Get the parameter list
-        std::vector<CameraParam> camMasterCmds, camNonMasterCmds;
-        pCamMaster->getParameterList([&camMasterCmds](hidl_vec<CameraParam> cmdList) {
-                camMasterCmds.reserve(cmdList.size());
+        std::vector<CameraParam> camPrimaryCmds, camSecondaryCmds;
+        pCamPrimary->getParameterList([&camPrimaryCmds](hidl_vec<CameraParam> cmdList) {
+                camPrimaryCmds.reserve(cmdList.size());
                 for (auto &&cmd : cmdList) {
-                    camMasterCmds.push_back(cmd);
+                    camPrimaryCmds.push_back(cmd);
                 }
             }
         );
 
-        pCamNonMaster->getParameterList([&camNonMasterCmds](hidl_vec<CameraParam> cmdList) {
-                camNonMasterCmds.reserve(cmdList.size());
+        pCamSecondary->getParameterList([&camSecondaryCmds](hidl_vec<CameraParam> cmdList) {
+                camSecondaryCmds.reserve(cmdList.size());
                 for (auto &&cmd : cmdList) {
-                    camNonMasterCmds.push_back(cmd);
+                    camSecondaryCmds.push_back(cmd);
                 }
             }
         );
 
-        if (camMasterCmds.size() < 1 ||
-            camNonMasterCmds.size() < 1) {
+        if (camPrimaryCmds.size() < 1 ||
+            camSecondaryCmds.size() < 1) {
             // Skip a camera device if it does not support any parameter.
             continue;
         }
 
         // Set up per-client frame receiver objects which will fire up its own thread
-        sp<FrameHandler> frameHandlerMaster =
-            new FrameHandler(pCamMaster, cam,
+        sp<FrameHandler> frameHandlerPrimary =
+            new FrameHandler(pCamPrimary, cam,
                              nullptr,
                              FrameHandler::eAutoReturn);
-        ASSERT_NE(frameHandlerMaster, nullptr);
-        sp<FrameHandler> frameHandlerNonMaster =
-            new FrameHandler(pCamNonMaster, cam,
+        ASSERT_NE(frameHandlerPrimary, nullptr);
+        sp<FrameHandler> frameHandlerSecondary =
+            new FrameHandler(pCamSecondary, cam,
                              nullptr,
                              FrameHandler::eAutoReturn);
-        ASSERT_NE(frameHandlerNonMaster, nullptr);
+        ASSERT_NE(frameHandlerSecondary, nullptr);
 
-        // Set one client as the master
-        EvsResult result = pCamMaster->setMaster();
+        // Set one client as the primary client.
+        EvsResult result = pCamPrimary->setMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
-        // Try to set another client as the master.
-        result = pCamNonMaster->setMaster();
+        // Try to set another client as the primary client.
+        result = pCamSecondary->setMaster();
         ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
 
-        // Start the camera's video stream via a master client.
-        bool startResult = frameHandlerMaster->startStream();
+        // Start the camera's video stream via a primary client client.
+        bool startResult = frameHandlerPrimary->startStream();
         ASSERT_TRUE(startResult);
 
         // Ensure the stream starts
-        frameHandlerMaster->waitForFrameCount(1);
+        frameHandlerPrimary->waitForFrameCount(1);
 
         // Start the camera's video stream via another client
-        startResult = frameHandlerNonMaster->startStream();
+        startResult = frameHandlerSecondary->startStream();
         ASSERT_TRUE(startResult);
 
         // Ensure the stream starts
-        frameHandlerNonMaster->waitForFrameCount(1);
+        frameHandlerSecondary->waitForFrameCount(1);
 
         int32_t val0 = 0;
         std::vector<int32_t> values;
         EvsEventDesc aNotification0 = {};
         EvsEventDesc aNotification1 = {};
-        for (auto &cmd : camMasterCmds) {
+        for (auto &cmd : camPrimaryCmds) {
             // Get a valid parameter value range
             int32_t minVal, maxVal, step;
-            pCamMaster->getIntParameterRange(
+            pCamPrimary->getIntParameterRange(
                 cmd,
                 [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
                     minVal = val0;
@@ -1236,7 +1236,7 @@
             if (cmd == CameraParam::ABSOLUTE_FOCUS) {
                 // Try to turn off auto-focus
                 values.clear();
-                pCamMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                pCamPrimary->setIntParameter(CameraParam::AUTO_FOCUS, 0,
                                    [&result, &values](auto status, auto effectiveValues) {
                                        result = status;
                                        if (status == EvsResult::OK) {
@@ -1261,7 +1261,7 @@
             std::condition_variable eventCond;
             std::thread listener0 = std::thread(
                 [cmd, val0,
-                 &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+                 &aNotification0, &frameHandlerPrimary, &listening0, &listening1, &eventCond]() {
                     listening0 = true;
                     if (listening1) {
                         eventCond.notify_all();
@@ -1271,14 +1271,14 @@
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
-                    if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+                    if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
             std::thread listener1 = std::thread(
                 [cmd, val0,
-                 &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+                 &aNotification1, &frameHandlerSecondary, &listening0, &listening1, &eventCond]() {
                     listening1 = true;
                     if (listening0) {
                         eventCond.notify_all();
@@ -1288,7 +1288,7 @@
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
-                    if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+                    if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
@@ -1305,7 +1305,7 @@
 
             // Try to program a parameter
             values.clear();
-            pCamMaster->setIntParameter(cmd, val0,
+            pCamPrimary->setIntParameter(cmd, val0,
                                      [&result, &values](auto status, auto effectiveValues) {
                                          result = status;
                                          if (status == EvsResult::OK) {
@@ -1345,9 +1345,9 @@
             }
 
             // Clients expects to receive a parameter change notification
-            // whenever a master client adjusts it.
+            // whenever a primary client client adjusts it.
             values.clear();
-            pCamMaster->getIntParameter(cmd,
+            pCamPrimary->getIntParameter(cmd,
                                      [&result, &values](auto status, auto readValues) {
                                          result = status;
                                          if (status == EvsResult::OK) {
@@ -1362,9 +1362,9 @@
             }
         }
 
-        // Try to adjust a parameter via non-master client
+        // Try to adjust a parameter via non-primary client
         values.clear();
-        pCamNonMaster->setIntParameter(camNonMasterCmds[0], val0,
+        pCamSecondary->setIntParameter(camSecondaryCmds[0], val0,
                                     [&result, &values](auto status, auto effectiveValues) {
                                         result = status;
                                         if (status == EvsResult::OK) {
@@ -1375,21 +1375,21 @@
                                     });
         ASSERT_EQ(EvsResult::INVALID_ARG, result);
 
-        // Non-master client attemps to be a master
-        result = pCamNonMaster->setMaster();
+        // Non-primary client attempts to be a primary client
+        result = pCamSecondary->setMaster();
         ASSERT_EQ(EvsResult::OWNERSHIP_LOST, result);
 
-        // Master client retires from a master role
+        // Primary client retires from a primary client role
         bool listening = false;
         std::condition_variable eventCond;
         std::thread listener = std::thread(
-            [&aNotification0, &frameHandlerNonMaster, &listening, &eventCond]() {
+            [&aNotification0, &frameHandlerSecondary, &listening, &eventCond]() {
                 listening = true;
                 eventCond.notify_all();
 
                 EvsEventDesc aTargetEvent;
                 aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
-                if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
+                if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification0, true)) {
                     LOG(WARNING) << "A timer is expired before a target event is fired.";
                 }
             }
@@ -1403,7 +1403,7 @@
         }
         lock.unlock();
 
-        result = pCamMaster->unsetMaster();
+        result = pCamPrimary->unsetMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
         if (listener.joinable()) {
@@ -1414,7 +1414,7 @@
 
         // Try to adjust a parameter after being retired
         values.clear();
-        pCamMaster->setIntParameter(camMasterCmds[0], val0,
+        pCamPrimary->setIntParameter(camPrimaryCmds[0], val0,
                                  [&result, &values](auto status, auto effectiveValues) {
                                      result = status;
                                      if (status == EvsResult::OK) {
@@ -1425,15 +1425,15 @@
                                  });
         ASSERT_EQ(EvsResult::INVALID_ARG, result);
 
-        // Non-master client becomes a master
-        result = pCamNonMaster->setMaster();
+        // Non-primary client becomes a primary client
+        result = pCamSecondary->setMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
-        // Try to adjust a parameter via new master client
-        for (auto &cmd : camNonMasterCmds) {
+        // Try to adjust a parameter via new primary client
+        for (auto &cmd : camSecondaryCmds) {
             // Get a valid parameter value range
             int32_t minVal, maxVal, step;
-            pCamNonMaster->getIntParameterRange(
+            pCamSecondary->getIntParameterRange(
                 cmd,
                 [&minVal, &maxVal, &step](int32_t val0, int32_t val1, int32_t val2) {
                     minVal = val0;
@@ -1447,7 +1447,7 @@
             if (cmd == CameraParam::ABSOLUTE_FOCUS) {
                 // Try to turn off auto-focus
                 values.clear();
-                pCamNonMaster->setIntParameter(CameraParam::AUTO_FOCUS, 0,
+                pCamSecondary->setIntParameter(CameraParam::AUTO_FOCUS, 0,
                                    [&result, &values](auto status, auto effectiveValues) {
                                        result = status;
                                        if (status == EvsResult::OK) {
@@ -1471,7 +1471,7 @@
             bool listening1 = false;
             std::condition_variable eventCond;
             std::thread listener0 = std::thread(
-                [&cmd, &val0, &aNotification0, &frameHandlerMaster, &listening0, &listening1, &eventCond]() {
+                [&]() {
                     listening0 = true;
                     if (listening1) {
                         eventCond.notify_all();
@@ -1481,13 +1481,13 @@
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
-                    if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
+                    if (!frameHandlerPrimary->waitForEvent(aTargetEvent, aNotification0)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
             );
             std::thread listener1 = std::thread(
-                [&cmd, &val0, &aNotification1, &frameHandlerNonMaster, &listening0, &listening1, &eventCond]() {
+                [&]() {
                     listening1 = true;
                     if (listening0) {
                         eventCond.notify_all();
@@ -1497,7 +1497,7 @@
                     aTargetEvent.aType = EvsEventType::PARAMETER_CHANGED;
                     aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
                     aTargetEvent.payload[1] = val0;
-                    if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
+                    if (!frameHandlerSecondary->waitForEvent(aTargetEvent, aNotification1)) {
                         LOG(WARNING) << "A timer is expired before a target event is fired.";
                     }
                 }
@@ -1514,7 +1514,7 @@
 
             // Try to program a parameter
             values.clear();
-            pCamNonMaster->setIntParameter(cmd, val0,
+            pCamSecondary->setIntParameter(cmd, val0,
                                         [&result, &values](auto status, auto effectiveValues) {
                                             result = status;
                                             if (status == EvsResult::OK) {
@@ -1526,9 +1526,9 @@
             ASSERT_EQ(EvsResult::OK, result);
 
             // Clients expects to receive a parameter change notification
-            // whenever a master client adjusts it.
+            // whenever a primary client client adjusts it.
             values.clear();
-            pCamNonMaster->getIntParameter(cmd,
+            pCamSecondary->getIntParameter(cmd,
                                         [&result, &values](auto status, auto readValues) {
                                             result = status;
                                             if (status == EvsResult::OK) {
@@ -1567,17 +1567,17 @@
             }
         }
 
-        // New master retires from a master role
-        result = pCamNonMaster->unsetMaster();
+        // New primary client retires from the role
+        result = pCamSecondary->unsetMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
         // Shutdown
-        frameHandlerMaster->shutdown();
-        frameHandlerNonMaster->shutdown();
+        frameHandlerPrimary->shutdown();
+        frameHandlerSecondary->shutdown();
 
         // Explicitly release the camera
-        pEnumerator->closeCamera(pCamMaster);
-        pEnumerator->closeCamera(pCamNonMaster);
+        pEnumerator->closeCamera(pCamPrimary);
+        pEnumerator->closeCamera(pCamSecondary);
         activeCameras.clear();
     }
 }
@@ -1586,7 +1586,7 @@
 /*
  * HighPriorityCameraClient:
  * EVS client, which owns the display, is priortized and therefore can take over
- * a master role from other EVS clients without the display.
+ * a primary client role from other EVS clients without the display.
  */
 TEST_P(EvsHidlTest, HighPriorityCameraClient) {
     LOG(INFO) << "Starting HighPriorityCameraClient test";
@@ -1668,7 +1668,7 @@
         frameHandler0->waitForFrameCount(1);
         frameHandler1->waitForFrameCount(1);
 
-        // Client 1 becomes a master and programs a parameter.
+        // Client 1 becomes a primary client and programs a parameter.
         EvsResult result = EvsResult::OK;
         // Get a valid parameter value range
         int32_t minVal, maxVal, step;
@@ -1681,7 +1681,7 @@
             }
         );
 
-        // Client1 becomes a master
+        // Client1 becomes a primary client
         result = pCam1->setMaster();
         ASSERT_EQ(EvsResult::OK, result);
 
@@ -1820,7 +1820,7 @@
         }
         lock.unlock();
 
-        // Client 0 steals a master role
+        // Client 0 steals a primary client role
         ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
 
         // Join a listener
@@ -2241,7 +2241,7 @@
 TEST_P(EvsHidlTest, CameraStreamExternalBuffering) {
     LOG(INFO) << "Starting CameraStreamExternalBuffering test";
 
-    // Arbitrary constant (should be > 1 and less than crazy)
+    // Arbitrary constant (should be > 1 and not too big)
     static const unsigned int kBuffersToHold = 6;
 
     // Get the camera list
diff --git a/automotive/vehicle/2.0/utils/Android.bp b/automotive/vehicle/2.0/utils/Android.bp
new file mode 100644
index 0000000..e354634
--- /dev/null
+++ b/automotive/vehicle/2.0/utils/Android.bp
@@ -0,0 +1,41 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// User HAL helper library.
+cc_library_static {
+    name: "android.hardware.automotive.vehicle@2.0-user-hal-helper-lib",
+    defaults: ["vhal_v2_0_defaults"],
+    vendor: true,
+    host_supported: true,
+    srcs: [
+        "UserHalHelper.cpp",
+    ],
+    export_include_dirs: [
+        ".",
+    ],
+}
+
+cc_test {
+    name: "android.hardware.automotive.vehicle@2.0-utils-unit-tests",
+    defaults: ["vhal_v2_0_defaults"],
+    vendor: true,
+    srcs: [
+        "tests/UserHalHelper_test.cpp",
+    ],
+    static_libs: [
+        "android.hardware.automotive.vehicle@2.0-user-hal-helper-lib",
+        "libgmock",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/automotive/vehicle/2.0/utils/UserHalHelper.cpp b/automotive/vehicle/2.0/utils/UserHalHelper.cpp
new file mode 100644
index 0000000..33b3948
--- /dev/null
+++ b/automotive/vehicle/2.0/utils/UserHalHelper.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "UserHalHelper"
+
+#include "UserHalHelper.h"
+
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace user_hal_helper {
+namespace {
+
+using android::base::Error;
+using android::base::Result;
+
+static constexpr const char* kSeparator = "||";
+static const size_t kNumFieldsPerUserInfo = 2;
+static const size_t kNumFieldsPerSetAssociation = 2;
+
+template <typename T>
+Result<T> verifyAndCast(int32_t value) {
+    T castValue = static_cast<T>(value);
+    const auto iter = hidl_enum_range<T>();
+    if (castValue < *iter.begin() || castValue > *std::prev(iter.end())) {
+        return Error() << "Value " << value << " not in range [" << toString(*iter.begin()) << ", "
+                       << toString(*std::prev(iter.end())) << "]";
+    }
+    for (const auto& v : hidl_enum_range<T>()) {
+        if (castValue == v) {
+            return castValue;
+        }
+    }
+    return Error() << "Value " << value << " not in enum values";
+}
+
+Result<void> verifyPropValue(const VehiclePropValue& propValue, VehicleProperty vehicleProperty,
+                             size_t minInt32Values) {
+    auto prop = verifyAndCast<VehicleProperty>(propValue.prop);
+    if (!prop.ok()) {
+        return Error() << "Invalid vehicle property: " << prop.error();
+    }
+    if (*prop != vehicleProperty) {
+        return Error() << "Mismatching " << toString(vehicleProperty) << " request, received "
+                       << toString(*prop) << " property";
+    }
+    if (propValue.value.int32Values.size() < minInt32Values) {
+        return Error() << "Int32Values must have at least " << minInt32Values
+                       << " values, received " << propValue.value.int32Values.size();
+    }
+    return {};
+}
+
+Result<void> parseUserInfo(const hidl_vec<int32_t>& int32Values, size_t startPos,
+                           UserInfo* userInfo) {
+    if (int32Values.size() < startPos + kNumFieldsPerUserInfo) {
+        return Error() << "Int32Values must have at least " << startPos + 2 << " values, received "
+                       << int32Values.size();
+    }
+    userInfo->userId = int32Values[startPos];
+    auto userFlags = verifyAndCast<UserFlags>(int32Values[startPos + 1]);
+    if (!userFlags.ok()) {
+        return Error() << "Invalid user flags: " << userFlags.error();
+    }
+    userInfo->flags = *userFlags;
+    return {};
+}
+
+Result<void> parseUsersInfo(const hidl_vec<int32_t>& int32Values, size_t startPos,
+                            UsersInfo* usersInfo) {
+    if (int32Values.size() < startPos + 3) {
+        return Error() << "Int32Values must have at least " << startPos + 3 << " values, received "
+                       << int32Values.size();
+    }
+    auto ret = parseUserInfo(int32Values, startPos, &usersInfo->currentUser);
+    if (!ret.ok()) {
+        return ret;
+    }
+    usersInfo->numberUsers = int32Values[startPos + 2];
+    usersInfo->existingUsers.resize(usersInfo->numberUsers);
+    for (size_t i = 0; i < static_cast<size_t>(usersInfo->numberUsers); ++i) {
+        ret = parseUserInfo(int32Values, startPos + 3 + (kNumFieldsPerUserInfo * i),
+                            &usersInfo->existingUsers[i]);
+        if (!ret.ok()) {
+            return Error() << "Failed to parse existing user '" << i << "' info: " << ret.error();
+        }
+    }
+    return {};
+}
+
+Result<void> parseUserAssociationTypes(
+        const hidl_vec<int32_t>& int32Values, size_t startPos, size_t numberAssociationTypes,
+        hidl_vec<UserIdentificationAssociationType>* associationTypes) {
+    size_t minInt32Values = startPos + numberAssociationTypes;
+    if (int32Values.size() < minInt32Values) {
+        return Error() << "Int32Values must have at least " << minInt32Values
+                       << " values, received " << int32Values.size();
+    }
+    associationTypes->resize(numberAssociationTypes);
+    for (size_t i = 0; i < static_cast<size_t>(numberAssociationTypes); ++i) {
+        size_t pos = startPos + i;
+        auto type = verifyAndCast<UserIdentificationAssociationType>(int32Values[pos]);
+        if (!type.ok()) {
+            return Error() << "Invalid association type in query '" << i << "': " << type.error();
+        }
+        (*associationTypes)[i] = *type;
+    }
+    return {};
+}
+
+Result<void> parseUserAssociations(const hidl_vec<int32_t>& int32Values, size_t startPos,
+                                   size_t numberAssociations,
+                                   hidl_vec<UserIdentificationSetAssociation>* associations) {
+    size_t minInt32Values = startPos + (numberAssociations * kNumFieldsPerSetAssociation);
+    if (int32Values.size() < minInt32Values) {
+        return Error() << "Int32Values must have at least " << minInt32Values
+                       << " values, received " << int32Values.size();
+    }
+    associations->resize(numberAssociations);
+    for (size_t i = 0; i < static_cast<size_t>(numberAssociations); ++i) {
+        size_t pos = startPos + (kNumFieldsPerSetAssociation * i);
+        auto type = verifyAndCast<UserIdentificationAssociationType>(int32Values[pos]);
+        if (!type.ok()) {
+            return Error() << "Invalid association type in request '" << i << "': " << type.error();
+        }
+        (*associations)[i].type = *type;
+        auto value = verifyAndCast<UserIdentificationAssociationSetValue>(int32Values[pos + 1]);
+        if (!value.ok()) {
+            return Error() << "Invalid association set value in request '" << i
+                           << "': " << value.error();
+        }
+        (*associations)[i].value = *value;
+    }
+    return {};
+}
+
+}  // namespace
+
+Result<InitialUserInfoRequest> toInitialUserInfoRequest(const VehiclePropValue& propValue) {
+    auto ret = verifyPropValue(propValue, VehicleProperty::INITIAL_USER_INFO, 2);
+    if (!ret.ok()) {
+        return ret.error();
+    }
+    InitialUserInfoRequest request;
+    request.requestId = propValue.value.int32Values[0];
+    auto requestType = verifyAndCast<InitialUserInfoRequestType>(propValue.value.int32Values[1]);
+    if (!requestType.ok()) {
+        return Error() << "Invalid InitialUserInfoRequestType: " << requestType.error();
+    }
+    request.requestType = *requestType;
+    ret = parseUsersInfo(propValue.value.int32Values, 2, &request.usersInfo);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse users info: " << ret.error();
+    }
+    return request;
+}
+
+Result<SwitchUserRequest> toSwitchUserRequest(const VehiclePropValue& propValue) {
+    auto ret = verifyPropValue(propValue, VehicleProperty::SWITCH_USER, 2);
+    if (!ret.ok()) {
+        return ret.error();
+    }
+    SwitchUserRequest request;
+    auto messageType = verifyAndCast<SwitchUserMessageType>(propValue.value.int32Values[1]);
+    if (!messageType.ok()) {
+        return Error() << "Invalid SwitchUserMessageType: " << messageType.error();
+    }
+    if (*messageType != SwitchUserMessageType::LEGACY_ANDROID_SWITCH &&
+        *messageType != SwitchUserMessageType::ANDROID_SWITCH &&
+        *messageType != SwitchUserMessageType::ANDROID_POST_SWITCH) {
+        return Error() << "Invalid " << toString(*messageType) << " from Android System";
+    }
+    request.requestId = propValue.value.int32Values[0];
+    request.messageType = *messageType;
+    ret = parseUserInfo(propValue.value.int32Values, 2, &request.targetUser);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse target user info: " << ret.error();
+    }
+    ret = parseUsersInfo(propValue.value.int32Values, 4, &request.usersInfo);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse users info: " << ret.error();
+    }
+    return request;
+}
+
+Result<CreateUserRequest> toCreateUserRequest(const VehiclePropValue& propValue) {
+    auto ret = verifyPropValue(propValue, VehicleProperty::CREATE_USER, 1);
+    if (!ret.ok()) {
+        return ret.error();
+    }
+    CreateUserRequest request;
+    request.requestId = propValue.value.int32Values[0];
+    ret = parseUserInfo(propValue.value.int32Values, 1, &request.newUserInfo);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse new user info: " << ret.error();
+    }
+    request.newUserName = propValue.value.stringValue;
+    ret = parseUsersInfo(propValue.value.int32Values, 3, &request.usersInfo);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse users info: " << ret.error();
+    }
+    return request;
+}
+
+Result<RemoveUserRequest> toRemoveUserRequest(const VehiclePropValue& propValue) {
+    auto ret = verifyPropValue(propValue, VehicleProperty::REMOVE_USER, 1);
+    if (!ret.ok()) {
+        return ret.error();
+    }
+    RemoveUserRequest request;
+    request.requestId = propValue.value.int32Values[0];
+    ret = parseUserInfo(propValue.value.int32Values, 1, &request.removedUserInfo);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse removed user info: " << ret.error();
+    }
+    ret = parseUsersInfo(propValue.value.int32Values, 3, &request.usersInfo);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse users info: " << ret.error();
+    }
+    return request;
+}
+
+Result<UserIdentificationGetRequest> toUserIdentificationGetRequest(
+        const VehiclePropValue& propValue) {
+    auto ret = verifyPropValue(propValue, VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 4);
+    if (!ret.ok()) {
+        return ret.error();
+    }
+    UserIdentificationGetRequest request;
+    request.requestId = propValue.value.int32Values[0];
+    ret = parseUserInfo(propValue.value.int32Values, 1, &request.userInfo);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse user info: " << ret.error();
+    }
+    request.numberAssociationTypes = propValue.value.int32Values[3];
+    ret = parseUserAssociationTypes(propValue.value.int32Values, 4, request.numberAssociationTypes,
+                                    &request.associationTypes);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse UserIdentificationAssociationType: " << ret.error();
+    }
+    return request;
+}
+
+Result<UserIdentificationSetRequest> toUserIdentificationSetRequest(
+        const VehiclePropValue& propValue) {
+    auto ret = verifyPropValue(propValue, VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 4);
+    if (!ret.ok()) {
+        return ret.error();
+    }
+    UserIdentificationSetRequest request;
+    request.requestId = propValue.value.int32Values[0];
+    ret = parseUserInfo(propValue.value.int32Values, 1, &request.userInfo);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse user info: " << ret.error();
+    }
+    request.numberAssociations = propValue.value.int32Values[3];
+    ret = parseUserAssociations(propValue.value.int32Values, 4, request.numberAssociations,
+                                &request.associations);
+    if (!ret.ok()) {
+        return Error() << "Failed to parse UserIdentificationSetAssociation: " << ret.error();
+    }
+    return request;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserRequest& request) {
+    if (request.messageType != SwitchUserMessageType::VEHICLE_REQUEST) {
+        ALOGE("Invalid %s message type %s from HAL", toString(VehicleProperty::SWITCH_USER).c_str(),
+              toString(request.messageType).c_str());
+        return nullptr;
+    }
+    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+    propValue->prop = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
+    propValue->timestamp = elapsedRealtimeNano();
+    propValue->value.int32Values.resize(3);
+    propValue->value.int32Values[0] = static_cast<int32_t>(request.requestId);
+    propValue->value.int32Values[1] = static_cast<int32_t>(request.messageType);
+    propValue->value.int32Values[2] = static_cast<int32_t>(request.targetUser.userId);
+    return propValue;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const InitialUserInfoResponse& response) {
+    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+    propValue->prop = static_cast<int32_t>(VehicleProperty::INITIAL_USER_INFO);
+    propValue->timestamp = elapsedRealtimeNano();
+    propValue->value.int32Values.resize(4);
+    propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
+    propValue->value.int32Values[1] = static_cast<int32_t>(response.action);
+    propValue->value.int32Values[2] = static_cast<int32_t>(response.userToSwitchOrCreate.userId);
+    propValue->value.int32Values[3] = static_cast<int32_t>(response.userToSwitchOrCreate.flags);
+    propValue->value.stringValue = std::string(response.userLocales) + std::string(kSeparator) +
+                                   std::string(response.userNameToCreate);
+    return propValue;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserResponse& response) {
+    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+    propValue->prop = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
+    propValue->timestamp = elapsedRealtimeNano();
+    propValue->value.int32Values.resize(3);
+    propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
+    propValue->value.int32Values[1] = static_cast<int32_t>(response.messageType);
+    propValue->value.int32Values[2] = static_cast<int32_t>(response.status);
+    if (response.status == SwitchUserStatus::FAILURE) {
+        propValue->value.stringValue = response.errorMessage;
+    }
+    return propValue;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const CreateUserResponse& response) {
+    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+    propValue->prop = static_cast<int32_t>(VehicleProperty::CREATE_USER);
+    propValue->timestamp = elapsedRealtimeNano();
+    propValue->value.int32Values.resize(2);
+    propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
+    propValue->value.int32Values[1] = static_cast<int32_t>(response.status);
+    if (response.status == CreateUserStatus::FAILURE) {
+        propValue->value.stringValue = response.errorMessage;
+    }
+    return propValue;
+}
+
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const UserIdentificationResponse& response) {
+    auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
+    propValue->prop = static_cast<int32_t>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
+    propValue->timestamp = elapsedRealtimeNano();
+    propValue->value.int32Values.resize(2 + (response.numberAssociation * 2));
+    propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
+    propValue->value.int32Values[1] = static_cast<int32_t>(response.numberAssociation);
+    for (size_t i = 0; i < static_cast<size_t>(response.numberAssociation); ++i) {
+        size_t int32ValuesPos = 2 + (2 * i);
+        propValue->value.int32Values[int32ValuesPos] =
+                static_cast<int32_t>(response.associations[i].type);
+        propValue->value.int32Values[int32ValuesPos + 1] =
+                static_cast<int32_t>(response.associations[i].value);
+    }
+    if (!response.errorMessage.empty()) {
+        propValue->value.stringValue = response.errorMessage;
+    }
+    return propValue;
+}
+
+}  // namespace user_hal_helper
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/utils/UserHalHelper.h b/automotive/vehicle/2.0/utils/UserHalHelper.h
new file mode 100644
index 0000000..bee34cf
--- /dev/null
+++ b/automotive/vehicle/2.0/utils/UserHalHelper.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_UserHalHelper_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_UserHalHelper_H_
+
+#include <android-base/result.h>
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+#include <functional>
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace user_hal_helper {
+
+// Below functions parse VehiclePropValues to the respective User HAL request structs. On success,
+// these functions return the User HAL struct. Otherwise, they return the error.
+android::base::Result<InitialUserInfoRequest> toInitialUserInfoRequest(
+        const VehiclePropValue& propValue);
+android::base::Result<SwitchUserRequest> toSwitchUserRequest(const VehiclePropValue& propValue);
+android::base::Result<CreateUserRequest> toCreateUserRequest(const VehiclePropValue& propValue);
+android::base::Result<RemoveUserRequest> toRemoveUserRequest(const VehiclePropValue& propValue);
+android::base::Result<UserIdentificationGetRequest> toUserIdentificationGetRequest(
+        const VehiclePropValue& propValue);
+android::base::Result<UserIdentificationSetRequest> toUserIdentificationSetRequest(
+        const VehiclePropValue& propValue);
+
+// Below functions convert the User HAL structs to VehiclePropValues. On success, these functions
+// return the pointer to VehiclePropValue. Otherwise, they return nullptr.
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserRequest& request);
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const InitialUserInfoResponse& response);
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserResponse& response);
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const CreateUserResponse& response);
+std::unique_ptr<VehiclePropValue> toVehiclePropValue(const UserIdentificationResponse& response);
+
+}  // namespace user_hal_helper
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_UserHalHelper_H_
diff --git a/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp b/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp
new file mode 100644
index 0000000..7da87a2
--- /dev/null
+++ b/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp
@@ -0,0 +1,666 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "UserHalHelper.h"
+
+#include <gtest/gtest.h>
+
+#include <cstdint>
+
+#include "gmock/gmock.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace user_hal_helper {
+
+namespace {
+
+using testing::Eq;
+using testing::Gt;
+using testing::IsNull;
+using testing::NotNull;
+using testing::Pointee;
+
+constexpr int32_t INITIAL_USER_INFO = static_cast<int32_t>(VehicleProperty::INITIAL_USER_INFO);
+constexpr int32_t SWITCH_USER = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
+constexpr int32_t CREATE_USER = static_cast<int32_t>(VehicleProperty::CREATE_USER);
+constexpr int32_t REMOVE_USER = static_cast<int32_t>(VehicleProperty::REMOVE_USER);
+constexpr int32_t USER_IDENTIFICATION_ASSOCIATION =
+        static_cast<int32_t>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
+
+constexpr int32_t FIRST_BOOT_AFTER_OTA =
+        static_cast<int32_t>(InitialUserInfoRequestType::FIRST_BOOT_AFTER_OTA);
+constexpr int32_t LEGACY_ANDROID_SWITCH =
+        static_cast<int32_t>(SwitchUserMessageType::LEGACY_ANDROID_SWITCH);
+constexpr int32_t VEHICLE_REQUEST = static_cast<int32_t>(SwitchUserMessageType::VEHICLE_REQUEST);
+
+constexpr int32_t GUEST_USER = static_cast<int32_t>(UserFlags::GUEST);
+constexpr int32_t NONE_USER = static_cast<int32_t>(UserFlags::NONE);
+constexpr int32_t SYSTEM_USER = static_cast<int32_t>(UserFlags::SYSTEM);
+
+constexpr int32_t USER_ID_ASSOC_KEY_FOB =
+        static_cast<int32_t>(UserIdentificationAssociationType::KEY_FOB);
+constexpr int32_t USER_ID_ASSOC_CUSTOM_1 =
+        static_cast<int32_t>(UserIdentificationAssociationType::CUSTOM_1);
+
+constexpr int32_t USER_ID_ASSOC_SET_CURRENT_USER =
+        static_cast<int32_t>(UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER);
+constexpr int32_t USER_ID_ASSOC_UNSET_CURRENT_USER =
+        static_cast<int32_t>(UserIdentificationAssociationSetValue::DISASSOCIATE_CURRENT_USER);
+
+constexpr int32_t USER_ID_ASSOC_CURRENT_USER =
+        static_cast<int32_t>(UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER);
+constexpr int32_t USER_ID_ASSOC_NO_USER =
+        static_cast<int32_t>(UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER);
+
+}  // namespace
+
+TEST(UserHalHelperTest, TestToInitialUserInfoRequest) {
+    VehiclePropValue propValue{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, SYSTEM_USER,
+                                      10, NONE_USER}},
+    };
+    InitialUserInfoRequest expected{
+            .requestId = 23,
+            .requestType = InitialUserInfoRequestType::FIRST_BOOT_AFTER_OTA,
+            .usersInfo = {{10, UserFlags::NONE},
+                          2,
+                          {{0, UserFlags::SYSTEM}, {10, UserFlags::NONE}}},
+    };
+
+    auto actual = toInitialUserInfoRequest(propValue);
+
+    ASSERT_TRUE(actual.ok()) << actual.error().message();
+    EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithMismatchingPropType) {
+    VehiclePropValue propValue{
+            .prop = INT32_MAX,
+            .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, SYSTEM_USER,
+                                      10, NONE_USER}},
+    };
+
+    auto actual = toInitialUserInfoRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithInvalidRequestType) {
+    VehiclePropValue propValue{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, INT32_MAX, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+                                      NONE_USER}},
+    };
+
+    auto actual = toInitialUserInfoRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on invalid request type";
+}
+
+TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithInvalidUserFlag) {
+    VehiclePropValue propValue{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, SYSTEM_USER,
+                                      10, INT32_MAX}},
+    };
+
+    auto actual = toInitialUserInfoRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on invalid user flags";
+}
+
+TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithIncompleteUsersInfo) {
+    VehiclePropValue propValueMissingSecondUserInfo{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0,
+                                      SYSTEM_USER /*Missing 2nd UserInfo*/}},
+    };
+
+    auto actual = toInitialUserInfoRequest(propValueMissingSecondUserInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing second user info";
+
+    VehiclePropValue propValueMissingUsersInfo{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, /*Missing UsersInfo*/}},
+    };
+
+    actual = toInitialUserInfoRequest(propValueMissingUsersInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing users info";
+}
+
+TEST(UserHalHelperTest, TestToSwitchUserRequest) {
+    VehiclePropValue propValue{
+            .prop = SWITCH_USER,
+            .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, 0, SYSTEM_USER, 10, NONE_USER, 2,
+                                      0, SYSTEM_USER, 10, NONE_USER}},
+    };
+    SwitchUserRequest expected{
+            .requestId = 23,
+            .messageType = SwitchUserMessageType::LEGACY_ANDROID_SWITCH,
+            .targetUser = {0, UserFlags::SYSTEM},
+            .usersInfo = {{10, UserFlags::NONE},
+                          2,
+                          {{0, UserFlags::SYSTEM}, {10, UserFlags::NONE}}},
+    };
+
+    auto actual = toSwitchUserRequest(propValue);
+
+    ASSERT_TRUE(actual.ok()) << actual.error().message();
+    EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToSwitchUserRequestWithMismatchingPropType) {
+    VehiclePropValue propValue{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, 0, SYSTEM_USER, 10, NONE_USER, 2,
+                                      0, SYSTEM_USER, 10, NONE_USER}},
+    };
+
+    auto actual = toSwitchUserRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToSwitchUserRequestWithInvalidMessageType) {
+    VehiclePropValue propValueIncompatibleMessageType{
+            .prop = SWITCH_USER,
+            .value = {.int32Values = {23, VEHICLE_REQUEST, 0, SYSTEM_USER, 10, NONE_USER, 2, 0,
+                                      SYSTEM_USER, 10, NONE_USER}},
+    };
+
+    auto actual = toSwitchUserRequest(propValueIncompatibleMessageType);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on incompatible message type";
+
+    VehiclePropValue propValueInvalidMessageType{
+            .prop = SWITCH_USER,
+            .value = {.int32Values = {23, INT32_MAX, 0, SYSTEM_USER, 10, NONE_USER, 2, 0,
+                                      SYSTEM_USER, 10, NONE_USER}},
+    };
+
+    actual = toSwitchUserRequest(propValueInvalidMessageType);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on invalid message type";
+}
+
+TEST(UserHalHelperTest, TestFailsToSwitchUserRequestWithIncompleteUsersInfo) {
+    VehiclePropValue propValueMissingSecondUserInfo{
+            .prop = SWITCH_USER,
+            .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, 0, SYSTEM_USER, 10, NONE_USER, 2,
+                                      0, SYSTEM_USER,
+                                      /*Missing 2nd UserInfo*/}},
+    };
+
+    auto actual = toSwitchUserRequest(propValueMissingSecondUserInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing second user info";
+
+    VehiclePropValue propValueMissingUsersInfo{
+            .prop = SWITCH_USER,
+            .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, 0, SYSTEM_USER,
+                                      /*Missing UsersInfo*/}},
+    };
+
+    actual = toSwitchUserRequest(propValueMissingUsersInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing users info";
+
+    VehiclePropValue propValueMissingTargetUser{
+            .prop = SWITCH_USER,
+            .value = {.int32Values = {23, LEGACY_ANDROID_SWITCH, /*Missing target UserInfo*/}},
+    };
+
+    actual = toSwitchUserRequest(propValueMissingTargetUser);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing target user info";
+}
+
+TEST(UserHalHelperTest, TestToCreateUserRequest) {
+    VehiclePropValue propValue{
+            .prop = CREATE_USER,
+            .value = {.int32Values = {23, 11, GUEST_USER, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+                                      NONE_USER},
+                      .stringValue = "Guest11"},
+    };
+    CreateUserRequest expected{
+            .requestId = 23,
+            .newUserInfo = {11, UserFlags::GUEST},
+            .newUserName = "Guest11",
+            .usersInfo = {{10, UserFlags::NONE},
+                          2,
+                          {{0, UserFlags::SYSTEM}, {10, UserFlags::NONE}}},
+    };
+
+    auto actual = toCreateUserRequest(propValue);
+
+    ASSERT_TRUE(actual.ok()) << actual.error().message();
+    EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToCreateUserRequestWithMismatchingPropType) {
+    VehiclePropValue propValue{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, 11, GUEST_USER, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+                                      NONE_USER},
+                      .stringValue = "Guest11"},
+    };
+
+    auto actual = toCreateUserRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToCreateUserRequestWithIncompleteUsersInfo) {
+    VehiclePropValue propValueMissingSecondUserInfo{
+            .prop = CREATE_USER,
+            .value = {.int32Values = {23, 11, GUEST_USER, 10, NONE_USER, 2, 0,
+                                      SYSTEM_USER /*Missing 2nd UserInfo*/},
+                      .stringValue = "Guest11"},
+    };
+
+    auto actual = toCreateUserRequest(propValueMissingSecondUserInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing second user info";
+
+    VehiclePropValue propValueMissingUsersInfo{
+            .prop = CREATE_USER,
+            .value = {.int32Values = {23, 11, GUEST_USER, /*Missing UsersInfo*/},
+                      .stringValue = "Guest11"},
+    };
+
+    actual = toCreateUserRequest(propValueMissingUsersInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing users info";
+
+    VehiclePropValue propValueMissingCreateUserInfo{
+            .prop = CREATE_USER,
+            .value = {.int32Values = {23, /*Missing create UserInfo*/}, .stringValue = "Guest11"},
+    };
+
+    actual = toCreateUserRequest(propValueMissingCreateUserInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing create user info";
+}
+
+TEST(UserHalHelperTest, TestToRemoveUserRequest) {
+    VehiclePropValue propValue{
+            .prop = REMOVE_USER,
+            .value = {.int32Values = {23, 10, NONE_USER, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+                                      NONE_USER}},
+    };
+    RemoveUserRequest expected{
+            .requestId = 23,
+            .removedUserInfo = {10, UserFlags::NONE},
+            .usersInfo = {{10, UserFlags::NONE},
+                          2,
+                          {{0, UserFlags::SYSTEM}, {10, UserFlags::NONE}}},
+    };
+
+    auto actual = toRemoveUserRequest(propValue);
+
+    ASSERT_TRUE(actual.ok()) << actual.error().message();
+    EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToRemoveUserRequestWithMismatchingPropType) {
+    VehiclePropValue propValue{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, 10, NONE_USER, 10, NONE_USER, 2, 0, SYSTEM_USER, 10,
+                                      NONE_USER}},
+    };
+
+    auto actual = toRemoveUserRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToRemoveUserRequestWithIncompleteUsersInfo) {
+    VehiclePropValue propValueMissingSecondUserInfo{
+            .prop = REMOVE_USER,
+            .value = {.int32Values = {23, 10, NONE_USER, 10, NONE_USER, 2, 0,
+                                      SYSTEM_USER /*Missing 2nd UserInfo*/}},
+    };
+
+    auto actual = toRemoveUserRequest(propValueMissingSecondUserInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing second user info";
+
+    VehiclePropValue propValueMissingUsersInfo{
+            .prop = REMOVE_USER,
+            .value = {.int32Values = {23, 10, NONE_USER, /*Missing UsersInfo*/}},
+    };
+
+    actual = toRemoveUserRequest(propValueMissingUsersInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing users info";
+
+    VehiclePropValue propValueMissingRemoveUserInfo{
+            .prop = REMOVE_USER,
+            .value = {.int32Values = {23, /*Missing remove UserInfo*/}},
+    };
+
+    actual = toRemoveUserRequest(propValueMissingRemoveUserInfo);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing remove user info";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequest) {
+    VehiclePropValue propValue{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+                                      USER_ID_ASSOC_CUSTOM_1}},
+    };
+    UserIdentificationGetRequest expected{
+            .requestId = 23,
+            .userInfo = {10, UserFlags::NONE},
+            .numberAssociationTypes = 2,
+            .associationTypes = {UserIdentificationAssociationType::KEY_FOB,
+                                 UserIdentificationAssociationType::CUSTOM_1},
+    };
+
+    auto actual = toUserIdentificationGetRequest(propValue);
+
+    ASSERT_TRUE(actual.ok()) << actual.error().message();
+    EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequestWithMismatchingPropType) {
+    VehiclePropValue propValue{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+                                      USER_ID_ASSOC_CUSTOM_1}},
+    };
+
+    auto actual = toUserIdentificationGetRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequestWithInvalidAssociationTypes) {
+    VehiclePropValue propValue{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 10, NONE_USER, 1, INT32_MAX}},
+    };
+
+    auto actual = toUserIdentificationGetRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on invalid association type";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequestWithIncompleteAssociationTypes) {
+    VehiclePropValue propValueMissingSecondAssociationType{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 10, NONE_USER, 2,
+                                      USER_ID_ASSOC_KEY_FOB /*Missing 2nd association type*/}},
+    };
+
+    auto actual = toUserIdentificationGetRequest(propValueMissingSecondAssociationType);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing second association type";
+
+    VehiclePropValue propValueMissingNumberAssociationTypes{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 10, NONE_USER, /*Missing number association types*/}},
+    };
+
+    actual = toUserIdentificationGetRequest(propValueMissingNumberAssociationTypes);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing number association types";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationGetRequestWithMissingUserInfo) {
+    VehiclePropValue propValue{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, /*Missing user info*/}},
+    };
+
+    auto actual = toUserIdentificationGetRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing UserInfo";
+}
+
+TEST(UserHalHelperTest, TestToUserIdentificationSetRequest) {
+    VehiclePropValue propValue{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+                                      USER_ID_ASSOC_SET_CURRENT_USER, USER_ID_ASSOC_CUSTOM_1,
+                                      USER_ID_ASSOC_UNSET_CURRENT_USER}},
+    };
+    UserIdentificationSetRequest expected{
+            .requestId = 23,
+            .userInfo = {10, UserFlags::NONE},
+            .numberAssociations = 2,
+            .associations = {{UserIdentificationAssociationType::KEY_FOB,
+                              UserIdentificationAssociationSetValue::ASSOCIATE_CURRENT_USER},
+                             {UserIdentificationAssociationType::CUSTOM_1,
+                              UserIdentificationAssociationSetValue::DISASSOCIATE_CURRENT_USER}},
+    };
+
+    auto actual = toUserIdentificationSetRequest(propValue);
+
+    ASSERT_TRUE(actual.ok()) << actual.error().message();
+    EXPECT_THAT(actual.value(), Eq(expected));
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationSetRequestWithMismatchingPropType) {
+    VehiclePropValue propValue{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+                                      USER_ID_ASSOC_SET_CURRENT_USER, USER_ID_ASSOC_CUSTOM_1,
+                                      USER_ID_ASSOC_UNSET_CURRENT_USER}},
+    };
+
+    auto actual = toUserIdentificationSetRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on mismatching property type";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationSetRequestWithInvalidAssociations) {
+    VehiclePropValue propValueInvalidAssociationType{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 10, NONE_USER, 1, INT32_MAX,
+                                      USER_ID_ASSOC_SET_CURRENT_USER}},
+    };
+
+    auto actual = toUserIdentificationSetRequest(propValueInvalidAssociationType);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on invalid association type";
+
+    VehiclePropValue propValueInvalidAssociationValue{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 10, NONE_USER, USER_ID_ASSOC_KEY_FOB, INT32_MAX}},
+    };
+
+    actual = toUserIdentificationSetRequest(propValueInvalidAssociationValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing number association types";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationSetRequestWithIncompleteAssociations) {
+    VehiclePropValue propValueMissingSecondAssociationType{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 10, NONE_USER, 2, USER_ID_ASSOC_KEY_FOB,
+                                      USER_ID_ASSOC_SET_CURRENT_USER,
+                                      /*Missing 2nd association*/}},
+    };
+
+    auto actual = toUserIdentificationSetRequest(propValueMissingSecondAssociationType);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing second association type";
+
+    VehiclePropValue propValueMissingNumberAssociationTypes{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 10, NONE_USER, /*Missing number associations*/}},
+    };
+
+    actual = toUserIdentificationSetRequest(propValueMissingNumberAssociationTypes);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing number association types";
+}
+
+TEST(UserHalHelperTest, TestFailsToUserIdentificationSetRequestWithMissingUserInfo) {
+    VehiclePropValue propValue{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, /*Missing user info*/}},
+    };
+
+    auto actual = toUserIdentificationSetRequest(propValue);
+
+    EXPECT_FALSE(actual.ok()) << "No error returned on missing UserInfo";
+}
+
+TEST(UserHalHelperTest, TestSwitchUserRequestToVehiclePropValue) {
+    SwitchUserRequest request{
+            .requestId = 23,
+            .messageType = SwitchUserMessageType::VEHICLE_REQUEST,
+            .targetUser = {11, UserFlags::GUEST},
+    };
+    VehiclePropValue expected{
+            .prop = SWITCH_USER,
+            .value = {.int32Values = {23,
+                                      static_cast<int32_t>(SwitchUserMessageType::VEHICLE_REQUEST),
+                                      11}},
+    };
+
+    auto actual = toVehiclePropValue(request);
+
+    ASSERT_THAT(actual, NotNull());
+    EXPECT_THAT(actual->timestamp, Gt(0));
+    // Don't rely on real timestamp in tests as the expected and actual objects won't have the same
+    // timestamps. Thus remove the timestamps before comparing them.
+    actual->timestamp = 0;
+    EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+TEST(UserHalHelperTest, TestFailsSwitchUserRequestToVehiclePropValueWithIncompatibleMessageType) {
+    SwitchUserRequest request{
+            .requestId = 23,
+            .messageType = SwitchUserMessageType::VEHICLE_RESPONSE,
+            .targetUser = {11, UserFlags::GUEST},
+    };
+
+    auto actual = toVehiclePropValue(request);
+
+    EXPECT_THAT(actual, IsNull());
+}
+
+TEST(UserHalHelperTest, TestInitialUserInfoResponseToVehiclePropValue) {
+    InitialUserInfoResponse response{
+            .requestId = 23,
+            .action = InitialUserInfoResponseAction::CREATE,
+            .userToSwitchOrCreate = {11, UserFlags::GUEST},
+            .userLocales = "en-US,pt-BR",
+            .userNameToCreate = "Owner",
+    };
+    VehiclePropValue expected{
+            .prop = INITIAL_USER_INFO,
+            .value = {.int32Values = {23,
+                                      static_cast<int32_t>(InitialUserInfoResponseAction::CREATE),
+                                      11, GUEST_USER},
+                      .stringValue = "en-US,pt-BR||Owner"},
+    };
+
+    auto actual = toVehiclePropValue(response);
+
+    ASSERT_THAT(actual, NotNull());
+    EXPECT_THAT(actual->timestamp, Gt(0));
+    actual->timestamp = 0;
+    EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+TEST(UserHalHelperTest, TestSwitchUserResponseToVehiclePropValue) {
+    SwitchUserResponse response{
+            .requestId = 23,
+            .messageType = SwitchUserMessageType::VEHICLE_RESPONSE,
+            .status = SwitchUserStatus::FAILURE,
+            .errorMessage = "random error",
+    };
+    VehiclePropValue expected{
+            .prop = SWITCH_USER,
+            .value = {.int32Values = {23,
+                                      static_cast<int32_t>(SwitchUserMessageType::VEHICLE_RESPONSE),
+                                      static_cast<int32_t>(SwitchUserStatus::FAILURE)},
+                      .stringValue = "random error"},
+    };
+
+    auto actual = toVehiclePropValue(response);
+
+    ASSERT_THAT(actual, NotNull());
+    EXPECT_THAT(actual->timestamp, Gt(0));
+    actual->timestamp = 0;
+    EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+TEST(UserHalHelperTest, TestCreateUserResponseToVehiclePropValue) {
+    CreateUserResponse response{
+            .requestId = 23,
+            .status = CreateUserStatus::FAILURE,
+            .errorMessage = "random error",
+    };
+    VehiclePropValue expected{
+            .prop = CREATE_USER,
+            .value = {.int32Values = {23, static_cast<int32_t>(CreateUserStatus::FAILURE)},
+                      .stringValue = "random error"},
+    };
+
+    auto actual = toVehiclePropValue(response);
+
+    ASSERT_THAT(actual, NotNull());
+    EXPECT_THAT(actual->timestamp, Gt(0));
+    actual->timestamp = 0;
+    EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+TEST(UserHalHelperTest, TestUserIdentificationResponseToVehiclePropValue) {
+    UserIdentificationResponse response{
+            .requestId = 23,
+            .numberAssociation = 2,
+            .associations = {{UserIdentificationAssociationType::KEY_FOB,
+                              UserIdentificationAssociationValue::ASSOCIATED_CURRENT_USER},
+                             {UserIdentificationAssociationType::CUSTOM_1,
+                              UserIdentificationAssociationValue::NOT_ASSOCIATED_ANY_USER}},
+            .errorMessage = "random error",
+    };
+    VehiclePropValue expected{
+            .prop = USER_IDENTIFICATION_ASSOCIATION,
+            .value = {.int32Values = {23, 2, USER_ID_ASSOC_KEY_FOB, USER_ID_ASSOC_CURRENT_USER,
+                                      USER_ID_ASSOC_CUSTOM_1, USER_ID_ASSOC_NO_USER},
+                      .stringValue = "random error"},
+    };
+
+    auto actual = toVehiclePropValue(response);
+
+    ASSERT_THAT(actual, NotNull());
+    EXPECT_THAT(actual->timestamp, Gt(0));
+    actual->timestamp = 0;
+    EXPECT_THAT(actual, Pointee(Eq(expected)));
+}
+
+}  // namespace user_hal_helper
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 384edf3..832c419 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -4453,9 +4453,12 @@
                             nullptr};
         } else {
             allocateGraphicBuffer(testStream.width, testStream.height,
-                    android_convertGralloc1To0Usage(halStreamConfig.streams[0].producerUsage,
-                        halStreamConfig.streams[0].consumerUsage),
-                    halStreamConfig.streams[0].overrideFormat, &buffer_handle);
+                                  /* We don't look at halStreamConfig.streams[0].consumerUsage
+                                   * since that is 0 for output streams
+                                   */
+                                  android_convertGralloc1To0Usage(
+                                          halStreamConfig.streams[0].producerUsage, bufferUsage),
+                                  halStreamConfig.streams[0].overrideFormat, &buffer_handle);
             outputBuffer = {halStreamConfig.streams[0].id,
                             bufferId,
                             buffer_handle,
diff --git a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
index 3ddb2b3..75d6252 100644
--- a/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
+++ b/wifi/hostapd/1.0/vts/functional/hostapd_hidl_test_utils.cpp
@@ -17,7 +17,6 @@
 #include <android-base/logging.h>
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
-#include <android/hidl/manager/1.0/IServiceNotification.h>
 #include <hidl/HidlTransportSupport.h>
 
 #include <wifi_system/hostapd_manager.h>
@@ -39,7 +38,6 @@
 using ::android::hardware::wifi::hostapd::V1_0::IHostapd;
 using ::android::hardware::wifi::V1_0::ChipModeId;
 using ::android::hardware::wifi::V1_0::IWifiChip;
-using ::android::hidl::manager::V1_0::IServiceNotification;
 using ::android::wifi_system::HostapdManager;
 using ::android::wifi_system::SupplicantManager;
 
@@ -68,55 +66,6 @@
 }
 }  // namespace
 
-// Utility class to wait for wpa_hostapd's HIDL service registration.
-class ServiceNotificationListener : public IServiceNotification {
-   public:
-    Return<void> onRegistration(const hidl_string& fully_qualified_name,
-                                const hidl_string& instance_name,
-                                bool pre_existing) override {
-        if (pre_existing) {
-            return Void();
-        }
-        std::unique_lock<std::mutex> lock(mutex_);
-        registered_.push_back(std::string(fully_qualified_name.c_str()) + "/" +
-                              instance_name.c_str());
-        lock.unlock();
-        condition_.notify_one();
-        return Void();
-    }
-
-    bool registerForHidlServiceNotifications(const std::string& instance_name) {
-        if (!IHostapd::registerForNotifications(instance_name, this)) {
-            return false;
-        }
-        configureRpcThreadpool(2, false);
-        return true;
-    }
-
-    bool waitForHidlService(uint32_t timeout_in_millis,
-                            const std::string& instance_name) {
-        std::unique_lock<std::mutex> lock(mutex_);
-        condition_.wait_for(lock, std::chrono::milliseconds(timeout_in_millis),
-                            [&]() { return registered_.size() >= 1; });
-        if (registered_.size() != 1) {
-            return false;
-        }
-        std::string expected_registered =
-            std::string(IHostapd::descriptor) + "/" + instance_name;
-        if (registered_[0] != expected_registered) {
-            LOG(ERROR) << "Expected: " << expected_registered
-                       << ", Got: " << registered_[0];
-            return false;
-        }
-        return true;
-    }
-
-   private:
-    std::vector<std::string> registered_{};
-    std::mutex mutex_;
-    std::condition_variable condition_;
-};
-
 void stopSupplicantIfNeeded(const std::string& instance_name) {
     SupplicantManager supplicant_manager;
     if (supplicant_manager.IsSupplicantRunning()) {
@@ -139,16 +88,11 @@
     const std::string& hostapd_instance_name) {
     initilializeDriverAndFirmware(wifi_instance_name);
 
-    android::sp<ServiceNotificationListener> notification_listener =
-        new ServiceNotificationListener();
-    ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
-        hostapd_instance_name));
-
     HostapdManager hostapd_manager;
     ASSERT_TRUE(hostapd_manager.StartHostapd());
 
-    ASSERT_TRUE(
-        notification_listener->waitForHidlService(500, hostapd_instance_name));
+    // Wait for hostapd service to come up.
+    IHostapd::getService(hostapd_instance_name);
 }
 
 bool is_1_1(const sp<IHostapd>& hostapd) {
diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
index addf066..5e7a371 100644
--- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
+++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp
@@ -18,7 +18,6 @@
 #include <cutils/properties.h>
 
 #include <android/hidl/manager/1.0/IServiceManager.h>
-#include <android/hidl/manager/1.0/IServiceNotification.h>
 #include <hidl/HidlTransportSupport.h>
 
 #include <wifi_system/interface_tool.h>
@@ -45,7 +44,6 @@
 using ::android::hardware::wifi::supplicant::V1_0::IfaceType;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
 using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
-using ::android::hidl::manager::V1_0::IServiceNotification;
 using ::android::wifi_system::InterfaceTool;
 using ::android::wifi_system::SupplicantManager;
 
@@ -120,55 +118,6 @@
 }
 }  // namespace
 
-// Utility class to wait for wpa_supplicant's HIDL service registration.
-class ServiceNotificationListener : public IServiceNotification {
-   public:
-    Return<void> onRegistration(const hidl_string& fully_qualified_name,
-                                const hidl_string& instance_name,
-                                bool pre_existing) override {
-        if (pre_existing) {
-            return Void();
-        }
-        std::unique_lock<std::mutex> lock(mutex_);
-        registered_.push_back(std::string(fully_qualified_name.c_str()) + "/" +
-                              instance_name.c_str());
-        lock.unlock();
-        condition_.notify_one();
-        return Void();
-    }
-
-    bool registerForHidlServiceNotifications(const std::string& instance_name) {
-        if (!ISupplicant::registerForNotifications(instance_name, this)) {
-            return false;
-        }
-        configureRpcThreadpool(2, false);
-        return true;
-    }
-
-    bool waitForHidlService(uint32_t timeout_in_millis,
-                            const std::string& instance_name) {
-        std::unique_lock<std::mutex> lock(mutex_);
-        condition_.wait_for(lock, std::chrono::milliseconds(timeout_in_millis),
-                            [&]() { return registered_.size() >= 1; });
-        if (registered_.size() != 1) {
-            return false;
-        }
-        std::string exptected_registered =
-            std::string(ISupplicant::descriptor) + "/" + instance_name;
-        if (registered_[0] != exptected_registered) {
-            LOG(ERROR) << "Expected: " << exptected_registered
-                       << ", Got: " << registered_[0];
-            return false;
-        }
-        return true;
-    }
-
-   private:
-    std::vector<std::string> registered_{};
-    std::mutex mutex_;
-    std::condition_variable condition_;
-};
-
 void stopSupplicant() { stopSupplicant(""); }
 
 void stopSupplicant(const std::string& wifi_instance_name) {
@@ -184,17 +133,12 @@
     const std::string& supplicant_instance_name) {
     initilializeDriverAndFirmware(wifi_instance_name);
 
-    android::sp<ServiceNotificationListener> notification_listener =
-        new ServiceNotificationListener();
-    ASSERT_TRUE(notification_listener->registerForHidlServiceNotifications(
-        supplicant_instance_name));
-
     SupplicantManager supplicant_manager;
     ASSERT_TRUE(supplicant_manager.StartSupplicant());
     ASSERT_TRUE(supplicant_manager.IsSupplicantRunning());
 
-    ASSERT_TRUE(notification_listener->waitForHidlService(
-        500, supplicant_instance_name));
+    // Wait for supplicant service to come up.
+    ISupplicant::getService(supplicant_instance_name);
 }
 
 bool is_1_1(const sp<ISupplicant>& supplicant) {