Merge "Update Documentation and name for EPOCH_TIME to ANDROID_EPOCH_TIME."
diff --git a/automotive/audiocontrol/1.0/vts/functional/OWNERS b/automotive/audiocontrol/1.0/vts/functional/OWNERS
new file mode 100644
index 0000000..fb422db
--- /dev/null
+++ b/automotive/audiocontrol/1.0/vts/functional/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 162915
+zhaomingyin@google.com
diff --git a/automotive/audiocontrol/2.0/vts/functional/OWNERS b/automotive/audiocontrol/2.0/vts/functional/OWNERS
new file mode 100644
index 0000000..fb422db
--- /dev/null
+++ b/automotive/audiocontrol/2.0/vts/functional/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 162915
+zhaomingyin@google.com
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index e1b9729..c33a2e7 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -79,19 +79,24 @@
 using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
 using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay;
 
+namespace {
+
 /*
  * Plese note that this is different from what is defined in
  * libhardware/modules/camera/3_4/metadata/types.h; this has one additional
  * field to store a framerate.
  */
-const size_t kStreamCfgSz = 5;
 typedef struct {
+    int32_t id;
     int32_t width;
     int32_t height;
     int32_t format;
     int32_t direction;
     int32_t framerate;
 } RawStreamConfig;
+constexpr const size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t);
+
+} // anonymous namespace
 
 
 // The main test class for EVS
@@ -236,6 +241,28 @@
         return physicalCameras;
     }
 
+    Stream getFirstStreamConfiguration(camera_metadata_t* metadata) {
+        Stream targetCfg = {};
+        camera_metadata_entry_t streamCfgs;
+        if (!find_camera_metadata_entry(metadata,
+                 ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
+                 &streamCfgs)) {
+            // Stream configurations are found in metadata
+            RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
+            for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
+                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
+                    targetCfg.width = ptr->width;
+                    targetCfg.height = ptr->height;
+                    targetCfg.format = static_cast<PixelFormat>(ptr->format);
+                    break;
+                }
+                ++ptr;
+            }
+        }
+
+        return targetCfg;
+    }
 
     sp<IEvsEnumerator>              pEnumerator;   // Every test needs access to the service
     std::vector<CameraDesc>         cameraInfo;    // Empty unless/until loadCameraList() is called
@@ -265,10 +292,6 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Open and close each camera twice
     for (auto&& cam: cameraInfo) {
         bool isLogicalCam = false;
@@ -278,8 +301,14 @@
             continue;
         }
 
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
         for (int pass = 0; pass < 2; pass++) {
-            sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg);
+            sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
             ASSERT_NE(pCam, nullptr);
 
             for (auto&& devName : devices) {
@@ -343,10 +372,6 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Open and close each camera twice
     for (auto&& cam: cameraInfo) {
         bool isLogicalCam = false;
@@ -356,10 +381,14 @@
             continue;
         }
 
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
         activeCameras.clear();
-        sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam, nullptr);
 
         // Store a camera handle for a clean-up
@@ -372,9 +401,7 @@
                                 }
         );
 
-        sp<IEvsCamera_1_1> pCam2 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam2 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam2, nullptr);
 
         // Store a camera handle for a clean-up
@@ -422,10 +449,6 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
         bool isLogicalCam = false;
@@ -435,9 +458,13 @@
             continue;
         }
 
-        sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam, nullptr);
 
         // Store a camera handle for a clean-up
@@ -519,10 +546,6 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
         bool isLogicalCam = false;
@@ -532,9 +555,13 @@
             continue;
         }
 
-        sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam, nullptr);
 
         // Store a camera handle for a clean-up
@@ -601,10 +628,6 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Request available display IDs
     uint8_t targetDisplayId = 0;
     pEnumerator->getDisplayIdList([&targetDisplayId](auto ids) {
@@ -642,9 +665,13 @@
             continue;
         }
 
-        sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
+        sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam, nullptr);
 
         // Store a camera handle for a clean-up
@@ -708,24 +735,22 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
         // Create two camera clients.
-        sp<IEvsCamera_1_1> pCam0 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam0 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam0, nullptr);
 
         // Store a camera handle for a clean-up
         activeCameras.push_back(pCam0);
 
-        sp<IEvsCamera_1_1> pCam1 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam1, nullptr);
 
         // Store a camera handle for a clean-up
@@ -812,10 +837,6 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Test each reported camera
     Return<EvsResult> result = EvsResult::OK;
     for (auto&& cam: cameraInfo) {
@@ -828,10 +849,14 @@
             continue;
         }
 
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
         // Create a camera client
-        sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam, nullptr);
 
         // Store a camera
@@ -961,10 +986,6 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
         bool isLogicalCam = false;
@@ -976,18 +997,20 @@
             continue;
         }
 
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
         // Create two camera clients.
-        sp<IEvsCamera_1_1> pCamPrimary =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCamPrimary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCamPrimary, nullptr);
 
         // Store a camera handle for a clean-up
         activeCameras.push_back(pCamPrimary);
 
-        sp<IEvsCamera_1_1> pCamSecondary =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCamSecondary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCamSecondary, nullptr);
 
         // Store a camera handle for a clean-up
@@ -1142,10 +1165,6 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
         bool isLogicalCam = false;
@@ -1157,18 +1176,20 @@
             continue;
         }
 
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
         // Create two camera clients.
-        sp<IEvsCamera_1_1> pCamPrimary =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCamPrimary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCamPrimary, nullptr);
 
         // Store a camera handle for a clean-up
         activeCameras.push_back(pCamPrimary);
 
-        sp<IEvsCamera_1_1> pCamSecondary =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCamSecondary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCamSecondary, nullptr);
 
         // Store a camera handle for a clean-up
@@ -1615,28 +1636,26 @@
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Request exclusive access to the EVS display
     sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay();
     ASSERT_NE(pDisplay, nullptr);
 
     // Test each reported camera
     for (auto&& cam: cameraInfo) {
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
+
         // Create two clients
-        sp<IEvsCamera_1_1> pCam0 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam0 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam0, nullptr);
 
         // Store a camera handle for a clean-up
         activeCameras.push_back(pCam0);
 
-        sp<IEvsCamera_1_1> pCam1 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam1, nullptr);
 
         // Store a camera handle for a clean-up
@@ -2001,7 +2020,7 @@
                  &streamCfgs)) {
             // Stream configurations are found in metadata
             RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
-            for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+            for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
                 if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
                     ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
 
@@ -2026,9 +2045,7 @@
             continue;
         }
 
-        sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam, nullptr);
 
         // Store a camera handle for a clean-up
@@ -2106,7 +2123,7 @@
                  &streamCfgs)) {
             // Stream configurations are found in metadata
             RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32);
-            for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) {
+            for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) {
                 if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
                     ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
 
@@ -2132,9 +2149,7 @@
         }
 
         // Create the first camera client with a selected stream configuration.
-        sp<IEvsCamera_1_1> pCam0 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam0 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam0, nullptr);
 
         // Store a camera handle for a clean-up
@@ -2144,9 +2159,7 @@
         // configuration.
         int32_t id = targetCfg.id;
         targetCfg.id += 1;  // EVS manager sees only the stream id.
-        sp<IEvsCamera_1_1> pCam1 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_EQ(pCam1, nullptr);
 
         // Store a camera handle for a clean-up
@@ -2154,9 +2167,7 @@
 
         // Try again with same stream configuration.
         targetCfg.id = id;
-        pCam1 =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg))
-            .withDefault(nullptr);
+        pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam1, nullptr);
 
         // Set up per-client frame receiver objects which will fire up its own thread
@@ -2258,52 +2269,23 @@
     LOG(INFO) << "Starting CameraStreamExternalBuffering test";
 
     // Arbitrary constant (should be > 1 and not too big)
-    static const unsigned int kBuffersToHold = 6;
+    static const unsigned int kBuffersToHold = 3;
 
     // Get the camera list
     loadCameraList();
 
-    // Using null stream configuration makes EVS uses the default resolution and
-    // output format.
-    Stream nullCfg = {};
-
     // Acquire the graphics buffer allocator
     android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
     const auto usage =
             GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
-    const auto format = HAL_PIXEL_FORMAT_RGBA_8888;
-    uint32_t width = 640;
-    uint32_t height = 360;
-    camera_metadata_entry_t streamCfgs;
 
     // Test each reported camera
     for (auto&& cam : cameraInfo) {
-        bool foundCfg = false;
-        if (!find_camera_metadata_entry(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()),
-                                        ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
-                                        &streamCfgs)) {
-            // Stream configurations are found in metadata
-            RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
-
-            LOG(DEBUG) << __LINE__ << " start searching " << streamCfgs.count;
-            for (unsigned idx = 0; idx < streamCfgs.count; idx++) {
-                LOG(DEBUG) << "ptr->direction= " << ptr->direction
-                           << " ptr->format= " << ptr->format;
-                if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
-                    ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
-                    width = ptr->width;
-                    height = ptr->height;
-                    foundCfg = true;
-                    // Always use the 1st available configuration
-                    break;
-                }
-                ++ptr;
-            }
-        }
-
-        if (!foundCfg) {
-            LOG(INFO) << "No configuration found. Use default stream configurations.";
-        }
+        // Read a target resolution from the metadata
+        Stream targetCfg =
+            getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()));
+        ASSERT_GT(targetCfg.width, 0);
+        ASSERT_GT(targetCfg.height, 0);
 
         // Allocate buffers to use
         hidl_vec<BufferDesc> buffers;
@@ -2312,8 +2294,11 @@
             unsigned pixelsPerLine;
             buffer_handle_t memHandle = nullptr;
             android::status_t result =
-                    alloc.allocate(width, height, format, 1, usage, &memHandle, &pixelsPerLine, 0,
-                                   "CameraStreamExternalBufferingTest");
+                    alloc.allocate(targetCfg.width, targetCfg.height,
+                                   (android::PixelFormat)targetCfg.format,
+                                   /* layerCount = */ 1, usage, &memHandle, &pixelsPerLine,
+                                   /* graphicBufferId = */ 0,
+                                   /* requestorName = */ "CameraStreamExternalBufferingTest");
             if (result != android::NO_ERROR) {
                 LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
                 // Release previous allocated buffers
@@ -2325,10 +2310,10 @@
                 BufferDesc buf;
                 AHardwareBuffer_Desc* pDesc =
                         reinterpret_cast<AHardwareBuffer_Desc*>(&buf.buffer.description);
-                pDesc->width = width;
-                pDesc->height = height;
+                pDesc->width = targetCfg.width;
+                pDesc->height = targetCfg.height;
                 pDesc->layers = 1;
-                pDesc->format = format;
+                pDesc->format = static_cast<uint32_t>(targetCfg.format);
                 pDesc->usage = usage;
                 pDesc->stride = pixelsPerLine;
                 buf.buffer.nativeHandle = memHandle;
@@ -2340,9 +2325,7 @@
         bool isLogicalCam = false;
         getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
 
-        sp<IEvsCamera_1_1> pCam =
-            IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
-            .withDefault(nullptr);
+        sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg);
         ASSERT_NE(pCam, nullptr);
 
         // Store a camera handle for a clean-up
@@ -2362,7 +2345,7 @@
         }
 
         EXPECT_EQ(result, EvsResult::OK);
-        EXPECT_GE(delta, 0);
+        EXPECT_GE(delta, kBuffersToHold);
 
         // Set up a frame receiver object which will fire up its own thread.
         sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam,
@@ -2378,7 +2361,7 @@
         sleep(1);   // 1 second should be enough for at least 5 frames to be delivered worst case
         unsigned framesReceived = 0;
         frameHandler->getFramesCounters(&framesReceived, nullptr);
-        ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
+        ASSERT_LE(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit";
 
 
         // Give back one buffer
@@ -2387,9 +2370,10 @@
 
         // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one
         // filled since we require 10fps minimum -- but give a 10% allowance just in case.
+        unsigned framesReceivedAfter = 0;
         usleep(110 * kMillisecondsToMicroseconds);
-        frameHandler->getFramesCounters(&framesReceived, nullptr);
-        EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed";
+        frameHandler->getFramesCounters(&framesReceivedAfter, nullptr);
+        EXPECT_EQ(framesReceived + 1, framesReceivedAfter) << "Stream should've resumed";
 
         // Even when the camera pointer goes out of scope, the FrameHandler object will
         // keep the stream alive unless we tell it to shutdown.
diff --git a/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
index 583a455..58423c8 100644
--- a/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
+++ b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <fuzzer/FuzzedDataProvider.h>
 #include <cmath>
 #include <cstdlib>
 #include <cstring>
@@ -21,36 +22,43 @@
 #include "FormatConvert.h"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, std::size_t size) {
-    if (size < 256) {
+    // 1 random value (4bytes) + min imagesize = 16*2 times bytes per pixel (worse case 2)
+    if (size < (4 + 16 * 2 * 2)) {
         return 0;
     }
+    FuzzedDataProvider fdp(data, size);
+    std::size_t image_pixel_size = size - 4;
+    image_pixel_size = (image_pixel_size & INT_MAX) / 2;
 
-    std::srand(std::time(nullptr));  // use current time as seed for random generator
-    int random_variable = std::rand() % 10;
-    int width = (int)sqrt(size);
-    int height = width * ((float)random_variable / 10.0);
+    // API have a requirement that width must be divied by 16 except yuyvtorgb
+    int min_height = 2;
+    int max_height = (image_pixel_size / 16) & ~(1);  // must be even number
+    int height = fdp.ConsumeIntegralInRange<uint32_t>(min_height, max_height);
+    int width = (image_pixel_size / height) & ~(16);  // must be divisible by 16
 
-    uint8_t* src = (uint8_t*)malloc(sizeof(uint8_t) * size);
-    memcpy(src, data, sizeof(uint8_t) * (size));
-    uint32_t* tgt = (uint32_t*)malloc(sizeof(uint32_t) * size);
+    uint8_t* src = (uint8_t*)(data + 4);
+    uint32_t* tgt = (uint32_t*)malloc(sizeof(uint32_t) * image_pixel_size);
 
 #ifdef COPY_NV21_TO_RGB32
-    android::hardware::automotive::evs::common::Utils::copyNV21toRGB32(width, height, src, tgt, 0);
+    android::hardware::automotive::evs::common::Utils::copyNV21toRGB32(width, height, src, tgt,
+                                                                       width);
 #elif COPY_NV21_TO_BGR32
-    android::hardware::automotive::evs::common::Utils::copyNV21toBGR32(width, height, src, tgt, 0);
+    android::hardware::automotive::evs::common::Utils::copyNV21toBGR32(width, height, src, tgt,
+                                                                       width);
 #elif COPY_YV12_TO_RGB32
-    android::hardware::automotive::evs::common::Utils::copyYV12toRGB32(width, height, src, tgt, 0);
+    android::hardware::automotive::evs::common::Utils::copyYV12toRGB32(width, height, src, tgt,
+                                                                       width);
 #elif COPY_YV12_TO_BGR32
-    android::hardware::automotive::evs::common::Utils::copyYV12toBGR32(width, height, src, tgt, 0);
+    android::hardware::automotive::evs::common::Utils::copyYV12toBGR32(width, height, src, tgt,
+                                                                       width);
 #elif COPY_YUYV_TO_RGB32
-    android::hardware::automotive::evs::common::Utils::copyYUYVtoRGB32(width, height, src, 0, tgt,
-                                                                       0);
+    android::hardware::automotive::evs::common::Utils::copyYUYVtoRGB32(width, height, src, width,
+                                                                       tgt, width);
 #elif COPY_YUYV_TO_BGR32
-    android::hardware::automotive::evs::common::Utils::copyYUYVtoBGR32(width, height, src, 0, tgt,
-                                                                       0);
+    android::hardware::automotive::evs::common::Utils::copyYUYVtoBGR32(width, height, src, width,
+                                                                       tgt, width);
 #endif
 
-    free(src);
     free(tgt);
 
     return 0;
diff --git a/automotive/sv/1.0/vts/functional/OWNERS b/automotive/sv/1.0/vts/functional/OWNERS
new file mode 100644
index 0000000..2ba00a3
--- /dev/null
+++ b/automotive/sv/1.0/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 821659
+tanmayp@google.com
+ankitarora@google.com
diff --git a/automotive/vehicle/2.0/vts/functional/OWNERS b/automotive/vehicle/2.0/vts/functional/OWNERS
new file mode 100644
index 0000000..8a0f2af
--- /dev/null
+++ b/automotive/vehicle/2.0/vts/functional/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 533426
+kwangsudo@google.com
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl
new file mode 100644
index 0000000..177966b
--- /dev/null
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequest.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.automotive.vehicle;
+@VintfStability
+parcelable GetValueRequest {
+  long requestId;
+  android.hardware.automotive.vehicle.VehiclePropValue prop;
+}
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequests.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequests.aidl
index c263a9d..5ecf4dd 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequests.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/GetValueRequests.aidl
@@ -34,7 +34,6 @@
 package android.hardware.automotive.vehicle;
 @VintfStability
 parcelable GetValueRequests {
-  android.hardware.automotive.vehicle.VehiclePropValue[] payloads;
-  long[] requestId;
+  android.hardware.automotive.vehicle.GetValueRequest[] payloads;
   @nullable ParcelFileDescriptor sharedMemoryFd;
 }
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl
index 82e7551..d6cddb6 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/SetValueRequest.aidl
@@ -34,6 +34,6 @@
 package android.hardware.automotive.vehicle;
 @VintfStability
 parcelable SetValueRequest {
-  android.hardware.automotive.vehicle.VehiclePropValue value;
   long requestId;
+  android.hardware.automotive.vehicle.VehiclePropValue value;
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl
new file mode 100644
index 0000000..43a89d0
--- /dev/null
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequest.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package android.hardware.automotive.vehicle;
+
+import android.hardware.automotive.vehicle.VehiclePropValue;
+
+@VintfStability
+parcelable GetValueRequest {
+    // A unique request ID. For every client, the request ID must start with 1
+    // and monotonically increase for every SetValueRequest. If it hits
+    // LONG_MAX (very unlikely), it must loop back to 0.
+    long requestId;
+    // The property to get, for most properties, only the property ID or area
+    // ID would be used to identify the property, but for some properties, other
+    // fields might be used.
+    VehiclePropValue prop;
+}
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequests.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequests.aidl
index 149799e..6601233 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequests.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/GetValueRequests.aidl
@@ -16,18 +16,14 @@
 
 package android.hardware.automotive.vehicle;
 
-import android.hardware.automotive.vehicle.VehiclePropValue;
+import android.hardware.automotive.vehicle.GetValueRequest;
 import android.os.ParcelFileDescriptor;
 
 @VintfStability
 parcelable GetValueRequests {
-    // The list of properties to get if they fit the binder memory limitation.
-    VehiclePropValue[] payloads;
-    // A list of request IDs, one for each VehiclePropValue. For every client,
-    // the request ID must start with 1 and monotonically increase for every
-    // VehiclePropValue in GetValueRequests. If it hits LONG_MAX (very
-    // unlikely), it must loop back to 0.
-    long[] requestId;
+    // A list of GetValueRequest to get if they fit the binder memory
+    // limitation.
+    GetValueRequest[] payloads;
     // Shared memory file to store requests if they exceed binder memory
     // limitation. Created by client, readable only at VHAL during the call.
     // Caller could close it after the call.
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl
index 1771c63..f2b0e27 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/SetValueRequest.aidl
@@ -20,10 +20,10 @@
 
 @VintfStability
 parcelable SetValueRequest {
-    // The value to set.
-    VehiclePropValue value;
     // A unique request ID. For every client, the request ID must start with 1
     // and monotonically increase for every SetValueRequest. If it hits
     // LONG_MAX (very unlikely), it must loop back to 0.
     long requestId;
+    // The value to set.
+    VehiclePropValue value;
 }
diff --git a/automotive/vehicle/aidl/impl/Android.bp b/automotive/vehicle/aidl/impl/Android.bp
index fc3d40b..94f590d 100644
--- a/automotive/vehicle/aidl/impl/Android.bp
+++ b/automotive/vehicle/aidl/impl/Android.bp
@@ -22,6 +22,7 @@
     name: "VehicleHalDefaults",
     static_libs: [
         "android.hardware.automotive.vehicle-V1-ndk",
+        "libmath",
     ],
     shared_libs: [
         "libbase",
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
new file mode 100644
index 0000000..d614c6b
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/Android.bp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+    name: "FakeVehicleHardware",
+    vendor: true,
+    srcs: ["src/*.cpp"],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+    defaults: ["VehicleHalDefaults"],
+    header_libs: [
+        "IVehicleHardware",
+        "VehicleHalDefaultConfig",
+    ],
+    export_header_lib_headers: ["IVehicleHardware"],
+    static_libs: ["VehicleHalUtils"],
+    export_static_lib_headers: ["VehicleHalUtils"],
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
new file mode 100644
index 0000000..2aa949a
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2021 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_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
+#define android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
+
+#include <DefaultConfig.h>
+#include <IVehicleHardware.h>
+#include <VehicleHalTypes.h>
+#include <VehiclePropertyStore.h>
+#include <android-base/thread_annotations.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+class FakeVehicleHardware final : public IVehicleHardware {
+  public:
+    using SetValuesCallback = std::function<void(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueResult>&)>;
+    using GetValuesCallback = std::function<void(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueResult>&)>;
+    using OnPropertyChangeCallback = std::function<void(
+            const std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>&)>;
+    using OnPropertySetErrorCallback = std::function<void(const std::vector<SetValueErrorEvent>&)>;
+
+    FakeVehicleHardware();
+
+    explicit FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool);
+
+    // Get all the property configs.
+    std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
+    getAllPropertyConfigs() const override;
+
+    // Set property values asynchronously. Server could return before the property set requests
+    // are sent to vehicle bus or before property set confirmation is received. The callback is
+    // safe to be called after the function returns and is safe to be called in a different thread.
+    ::aidl::android::hardware::automotive::vehicle::StatusCode setValues(
+            SetValuesCallback&& callback,
+            const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
+                    requests) override;
+
+    // Get property values asynchronously. Server could return before the property values are ready.
+    // The callback is safe to be called after the function returns and is safe to be called in a
+    // different thread.
+    ::aidl::android::hardware::automotive::vehicle::StatusCode getValues(
+            GetValuesCallback&& callback,
+            const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
+                    requests) const override;
+
+    // Dump debug information in the server.
+    DumpResult dump(const std::vector<std::string>& options) override;
+
+    // Check whether the system is healthy, return {@code StatusCode::OK} for healthy.
+    ::aidl::android::hardware::automotive::vehicle::StatusCode checkHealth() override;
+
+    // Register a callback that would be called when there is a property change event from vehicle.
+    void registerOnPropertyChangeEvent(OnPropertyChangeCallback&& callback) override;
+
+    // Register a callback that would be called when there is a property set error event from
+    // vehicle.
+    void registerOnPropertySetErrorEvent(OnPropertySetErrorCallback&& callback) override;
+
+  private:
+    void storePropInitialValue(const defaultconfig::ConfigDeclaration& config);
+    void init(std::shared_ptr<VehiclePropValuePool> valuePool);
+    void onValueChangeCallback(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value);
+
+    std::unique_ptr<VehiclePropertyStore> mServerSidePropStore;
+    // mValuePool is also used in mServerSidePropStore.
+    std::shared_ptr<VehiclePropValuePool> mValuePool;
+    std::mutex mCallbackLock;
+    OnPropertyChangeCallback mOnPropertyChangeCallback GUARDED_BY(mCallbackLock);
+    OnPropertySetErrorCallback mOnPropertySetErrorCallback GUARDED_BY(mCallbackLock);
+};
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_aidl_impl_fake_impl_hardware_include_FakeVehicleHardware_H_
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
new file mode 100644
index 0000000..b091517
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2021 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 "FakeVehicleHardware.h"
+
+#include <DefaultConfig.h>
+#include <VehicleHalTypes.h>
+#include <VehicleUtils.h>
+#include <utils/Log.h>
+#include <utils/SystemClock.h>
+
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+
+void FakeVehicleHardware::storePropInitialValue(const defaultconfig::ConfigDeclaration& config) {
+    const VehiclePropConfig& vehiclePropConfig = config.config;
+    int propId = vehiclePropConfig.prop;
+
+    // A global property will have only a single area
+    bool globalProp = isGlobalProp(propId);
+    size_t numAreas = globalProp ? 1 : vehiclePropConfig.areaConfigs.size();
+
+    for (size_t i = 0; i < numAreas; i++) {
+        int32_t curArea = globalProp ? 0 : vehiclePropConfig.areaConfigs[i].areaId;
+
+        // Create a separate instance for each individual zone
+        VehiclePropValue prop = {
+                .areaId = curArea,
+                .prop = propId,
+                .timestamp = elapsedRealtimeNano(),
+        };
+
+        if (config.initialAreaValues.empty()) {
+            if (config.initialValue == RawPropValues{}) {
+                // Skip empty initial values.
+                continue;
+            }
+            prop.value = config.initialValue;
+        } else if (auto valueForAreaIt = config.initialAreaValues.find(curArea);
+                   valueForAreaIt != config.initialAreaValues.end()) {
+            prop.value = valueForAreaIt->second;
+        } else {
+            ALOGW("failed to get default value for prop 0x%x area 0x%x", propId, curArea);
+            continue;
+        }
+
+        auto result =
+                mServerSidePropStore->writeValue(mValuePool->obtain(prop), /*updateStatus=*/true);
+        if (!result.ok()) {
+            ALOGE("failed to write default config value, error: %s",
+                  result.error().message().c_str());
+        }
+    }
+}
+
+FakeVehicleHardware::FakeVehicleHardware() {
+    mValuePool = std::make_shared<VehiclePropValuePool>();
+    init(mValuePool);
+}
+
+FakeVehicleHardware::FakeVehicleHardware(std::unique_ptr<VehiclePropValuePool> valuePool)
+    : mValuePool(std::move(valuePool)) {
+    init(mValuePool);
+}
+
+void FakeVehicleHardware::init(std::shared_ptr<VehiclePropValuePool> valuePool) {
+    mServerSidePropStore.reset(new VehiclePropertyStore(valuePool));
+    for (auto& it : defaultconfig::getDefaultConfigs()) {
+        VehiclePropConfig cfg = it.config;
+        mServerSidePropStore->registerProperty(cfg);
+        storePropInitialValue(it);
+    }
+
+    mServerSidePropStore->setOnValueChangeCallback(
+            [this](const VehiclePropValue& value) { return onValueChangeCallback(value); });
+}
+
+std::vector<VehiclePropConfig> FakeVehicleHardware::getAllPropertyConfigs() const {
+    return mServerSidePropStore->getAllConfigs();
+}
+
+StatusCode FakeVehicleHardware::setValues(FakeVehicleHardware::SetValuesCallback&&,
+                                          const std::vector<SetValueRequest>&) {
+    // TODO(b/201830716): Implement this.
+    return StatusCode::OK;
+}
+
+StatusCode FakeVehicleHardware::getValues(FakeVehicleHardware::GetValuesCallback&&,
+                                          const std::vector<GetValueRequest>&) const {
+    // TODO(b/201830716): Implement this.
+    return StatusCode::OK;
+}
+
+DumpResult FakeVehicleHardware::dump(const std::vector<std::string>&) {
+    DumpResult result;
+    // TODO(b/201830716): Implement this.
+    return result;
+}
+
+StatusCode FakeVehicleHardware::checkHealth() {
+    // TODO(b/201830716): Implement this.
+    return StatusCode::OK;
+}
+
+void FakeVehicleHardware::registerOnPropertyChangeEvent(OnPropertyChangeCallback&& callback) {
+    std::lock_guard<std::mutex> lockGuard(mCallbackLock);
+    mOnPropertyChangeCallback = std::move(callback);
+}
+
+void FakeVehicleHardware::registerOnPropertySetErrorEvent(OnPropertySetErrorCallback&& callback) {
+    std::lock_guard<std::mutex> lockGuard(mCallbackLock);
+    mOnPropertySetErrorCallback = std::move(callback);
+}
+
+void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
+    std::lock_guard<std::mutex> lockGuard(mCallbackLock);
+    if (mOnPropertyChangeCallback != nullptr) {
+        std::vector<VehiclePropValue> updatedValues;
+        updatedValues.push_back(value);
+        mOnPropertyChangeCallback(std::move(updatedValues));
+    }
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
new file mode 100644
index 0000000..9f76d09
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/Android.bp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+    name: "FakeVehicleHardwareTest",
+    vendor: true,
+    srcs: ["*.cpp"],
+    header_libs: [
+        "IVehicleHardware",
+        "VehicleHalDefaultConfig",
+    ],
+    static_libs: [
+        "VehicleHalUtils",
+        "FakeVehicleHardware",
+        "libgtest",
+        "libgmock",
+    ],
+    defaults: ["VehicleHalDefaults"],
+    test_suites: ["device-tests"],
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
new file mode 100644
index 0000000..d901b38
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2021 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 <DefaultConfig.h>
+#include <FakeVehicleHardware.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+namespace {
+
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::testing::ContainerEq;
+using ::testing::Eq;
+using ::testing::WhenSortedBy;
+
+}  // namespace
+
+class FakeVehicleHardwareTest : public ::testing::Test {
+  protected:
+    void SetUp() override {}
+
+    FakeVehicleHardware* getHardware() { return &mHardware; }
+
+    StatusCode setValues(const std::vector<SetValueRequest>& requests) {
+        return getHardware()->setValues(
+                [this](const std::vector<SetValueResult> results) { return onSetValues(results); },
+                requests);
+    }
+
+    StatusCode getValues(const std::vector<GetValueRequest>& requests) {
+        return getHardware()->getValues(
+                [this](const std::vector<GetValueResult> results) { return onGetValues(results); },
+                requests);
+    }
+
+    void onSetValues(const std::vector<SetValueResult> results) {
+        for (auto& result : results) {
+            mSetValueResults.push_back(result);
+        }
+    }
+
+    const std::vector<SetValueResult>& getSetValueResults() { return mSetValueResults; }
+
+    void onGetValues(const std::vector<GetValueResult> results) {
+        for (auto& result : results) {
+            mGetValueResults.push_back(result);
+        }
+    }
+
+    const std::vector<GetValueResult>& getGetValueResults() { return mGetValueResults; }
+
+    void onPropertyChangeEvent(const std::vector<VehiclePropValue>& values) {
+        for (auto& value : values) {
+            mChangedProperties.push_back(value);
+        }
+    }
+
+    const std::vector<VehiclePropValue>& getChangedProperties() { return mChangedProperties; }
+
+    static void addSetValueRequest(std::vector<SetValueRequest>& requests,
+                                   std::vector<SetValueResult>& expectedResults, int64_t requestId,
+                                   const VehiclePropValue& value, StatusCode expectedStatus) {
+        SetValueRequest request;
+        request.requestId = requestId;
+        request.value = value;
+        request.value.timestamp = elapsedRealtimeNano();
+        requests.push_back(std::move(request));
+
+        SetValueResult result;
+        result.requestId = requestId;
+        result.status = expectedStatus;
+        expectedResults.push_back(std::move(result));
+    }
+
+    static void addGetValueRequest(std::vector<GetValueRequest>& requests,
+                                   std::vector<GetValueResult>& expectedResults, int64_t requestId,
+                                   const VehiclePropValue& value, StatusCode expectedStatus) {
+        GetValueRequest request;
+        request.requestId = requestId;
+        request.prop.prop = value.prop;
+        request.prop.areaId = value.areaId;
+        requests.push_back(std::move(request));
+
+        GetValueResult result;
+        result.requestId = requestId;
+        result.status = expectedStatus;
+        if (expectedStatus == StatusCode::OK) {
+            result.prop = value;
+        }
+        expectedResults.push_back(std::move(result));
+    }
+
+    std::vector<VehiclePropValue> getTestPropValues() {
+        VehiclePropValue fuelCapacity = {
+                .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+                .value = {.floatValues = {1.0}},
+        };
+
+        VehiclePropValue leftTirePressure = {
+                .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+                .value = {.floatValues = {170.0}},
+                .areaId = WHEEL_FRONT_LEFT,
+        };
+
+        VehiclePropValue rightTirePressure = {
+                .prop = toInt(VehicleProperty::TIRE_PRESSURE),
+                .value = {.floatValues = {180.0}},
+                .areaId = WHEEL_FRONT_RIGHT,
+        };
+
+        return {fuelCapacity, leftTirePressure, rightTirePressure};
+    }
+
+    struct PropValueCmp {
+        bool operator()(const VehiclePropValue& a, const VehiclePropValue& b) const {
+            return (a.prop < b.prop) || ((a.prop == b.prop) && (a.value < b.value)) ||
+                   ((a.prop == b.prop) && (a.value == b.value) && (a.areaId < b.areaId));
+        }
+    } mPropValueCmp;
+
+  private:
+    FakeVehicleHardware mHardware;
+    std::vector<SetValueResult> mSetValueResults;
+    std::vector<GetValueResult> mGetValueResults;
+    std::vector<VehiclePropValue> mChangedProperties;
+};
+
+TEST_F(FakeVehicleHardwareTest, testGetAllPropertyConfigs) {
+    std::vector<VehiclePropConfig> configs = getHardware()->getAllPropertyConfigs();
+
+    ASSERT_EQ(configs.size(), defaultconfig::getDefaultConfigs().size());
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
index d5f2373..c742db5 100644
--- a/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/utils/proto_message_converter/test/proto_message_converter_test.cpp
@@ -45,7 +45,7 @@
 
 std::vector<aidl_vehicle::VehiclePropValue> prepareTestValues() {
     std::vector<aidl_vehicle::VehiclePropValue> values;
-    long timestamp = 1;
+    int64_t timestamp = 1;
     for (auto& property : defaultconfig::getDefaultConfigs()) {
         values.push_back({
                 .timestamp = timestamp,
diff --git a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
index 981088a..2e12327 100644
--- a/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/hardware/include/IVehicleHardware.h
@@ -36,14 +36,6 @@
     std::string buffer;
 };
 
-// A request type for 'setValues' or 'getValues' method.
-struct VehiclePropValueRequest {
-    // A unique request ID set by the sender.
-    int requestId;
-    // The property to get/set.
-    ::aidl::android::hardware::automotive::vehicle::VehiclePropValue value;
-};
-
 // A structure to represent a set value error event reported from vehicle.
 struct SetValueErrorEvent {
     ::aidl::android::hardware::automotive::vehicle::StatusCode errorCode;
@@ -70,7 +62,8 @@
             std::function<void(const std::vector<
                                ::aidl::android::hardware::automotive::vehicle::SetValueResult>&)>&&
                     callback,
-            const std::vector<VehiclePropValueRequest>& requests) = 0;
+            const std::vector<::aidl::android::hardware::automotive::vehicle::SetValueRequest>&
+                    requests) = 0;
 
     // Get property values asynchronously. Server could return before the property values are ready.
     // The callback is safe to be called after the function returns and is safe to be called in a
@@ -79,7 +72,8 @@
             std::function<void(const std::vector<
                                ::aidl::android::hardware::automotive::vehicle::GetValueResult>&)>&&
                     callback,
-            const std::vector<VehiclePropValueRequest>& requests) const = 0;
+            const std::vector<::aidl::android::hardware::automotive::vehicle::GetValueRequest>&
+                    requests) const = 0;
 
     // Dump debug information in the server.
     virtual DumpResult dump(const std::vector<std::string>& options) = 0;
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h b/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
new file mode 100644
index 0000000..68bd559
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/utils/common/include/ConcurrentQueue.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 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_aidl_impl_utils_common_include_ConcurrentQueue_H_
+#define android_hardware_automotive_vehicle_aidl_impl_utils_common_include_ConcurrentQueue_H_
+
+#include <android-base/thread_annotations.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <iostream>
+#include <queue>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+template <typename T>
+class ConcurrentQueue {
+  public:
+    void waitForItems() {
+        std::unique_lock<std::mutex> lockGuard(mLock);
+        ::android::base::ScopedLockAssertion lockAssertion(mLock);
+        while (mQueue.empty() && mIsActive) {
+            mCond.wait(lockGuard);
+        }
+    }
+
+    std::vector<T> flush() {
+        std::vector<T> items;
+
+        std::lock_guard<std::mutex> lockGuard(mLock);
+        if (mQueue.empty()) {
+            return items;
+        }
+        while (!mQueue.empty()) {
+            // Even if the queue is deactivated, we should still flush all the remaining values
+            // in the queue.
+            items.push_back(std::move(mQueue.front()));
+            mQueue.pop();
+        }
+        return items;
+    }
+
+    void push(T&& item) {
+        {
+            std::lock_guard<std::mutex> lockGuard(mLock);
+            if (!mIsActive) {
+                return;
+            }
+            mQueue.push(std::move(item));
+        }
+        mCond.notify_one();
+    }
+
+    // Deactivates the queue, thus no one can push items to it, also notifies all waiting thread.
+    // The items already in the queue could still be flushed even after the queue is deactivated.
+    void deactivate() {
+        {
+            std::lock_guard<std::mutex> lockGuard(mLock);
+            mIsActive = false;
+        }
+        // To unblock all waiting consumers.
+        mCond.notify_all();
+    }
+
+    ConcurrentQueue() = default;
+
+    ConcurrentQueue(const ConcurrentQueue&) = delete;
+    ConcurrentQueue& operator=(const ConcurrentQueue&) = delete;
+
+  private:
+    mutable std::mutex mLock;
+    bool mIsActive GUARDED_BY(mLock) = true;
+    std::condition_variable mCond;
+    std::queue<T> mQueue GUARDED_BY(mLock);
+};
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_aidl_impl_utils_common_include_ConcurrentQueue_H_
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
index 99f6431..545cf6a 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleHalTypes.h
@@ -21,8 +21,10 @@
 #include <aidl/android/hardware/automotive/vehicle/EvsServiceState.h>
 #include <aidl/android/hardware/automotive/vehicle/EvsServiceType.h>
 #include <aidl/android/hardware/automotive/vehicle/FuelType.h>
+#include <aidl/android/hardware/automotive/vehicle/GetValueRequest.h>
 #include <aidl/android/hardware/automotive/vehicle/GetValueResult.h>
 #include <aidl/android/hardware/automotive/vehicle/PortLocationType.h>
+#include <aidl/android/hardware/automotive/vehicle/SetValueRequest.h>
 #include <aidl/android/hardware/automotive/vehicle/SetValueResult.h>
 #include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
 #include <aidl/android/hardware/automotive/vehicle/VehicleApPowerStateReport.h>
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
index b19ab84..dcc7031 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehiclePropertyStore.h
@@ -24,6 +24,7 @@
 #include <unordered_map>
 
 #include <VehicleHalTypes.h>
+#include <VehicleObjectPool.h>
 #include <android-base/result.h>
 #include <android-base/thread_annotations.h>
 
@@ -39,8 +40,17 @@
 // to get value for all areas for particular property.
 //
 // This class is thread-safe, however it uses blocking synchronization across all methods.
-class VehiclePropertyStore {
+class VehiclePropertyStore final {
   public:
+    explicit VehiclePropertyStore(std::shared_ptr<VehiclePropValuePool> valuePool)
+        : mValuePool(valuePool) {}
+
+    ~VehiclePropertyStore();
+
+    // Callback when a property value has been updated or a new value added.
+    using OnValueChangeCallback = std::function<void(
+            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue&)>;
+
     // Function that used to calculate unique token for given VehiclePropValue.
     using TokenFunction = ::std::function<int64_t(
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value)>;
@@ -53,10 +63,13 @@
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig& config,
             TokenFunction tokenFunc = nullptr);
 
-    // Stores provided value. Returns true if value was written returns false if config wasn't
-    // registered.
-    ::android::base::Result<void> writeValue(
-            const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
+    // Stores provided value. Returns error if config wasn't registered. If 'updateStatus' is
+    // true, the 'status' in 'propValue' would be stored. Otherwise, if this is a new value,
+    // 'status' would be initialized to {@code VehiclePropertyStatus::AVAILABLE}, if this is to
+    // override an existing value, the status for the existing value would be used for the
+    // overridden value.
+    ::android::base::Result<void> writeValue(VehiclePropValuePool::RecyclableType propValue,
+                                             bool updateStatus = false);
 
     // Remove a given property value from the property store. The 'propValue' would be used to
     // generate the key for the value to remove.
@@ -67,24 +80,23 @@
     void removeValuesForProperty(int32_t propId);
 
     // Read all the stored values.
-    std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue> readAllValues()
-            const;
+    std::vector<VehiclePropValuePool::RecyclableType> readAllValues() const;
 
     // Read all the values for the property.
-    ::android::base::Result<
-            std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
+    ::android::base::Result<std::vector<VehiclePropValuePool::RecyclableType>>
     readValuesForProperty(int32_t propId) const;
 
-    // Read the value for the requested property.
-    ::android::base::Result<
-            std::unique_ptr<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
-    readValue(
+    // Read the value for the requested property. Returns {@code StatusCode::NOT_AVAILABLE} if the
+    // value has not been set yet. Returns {@code StatusCode::INVALID_ARG} if the property is
+    // not configured.
+    ::android::base::Result<VehiclePropValuePool::RecyclableType> readValue(
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& request) const;
 
-    // Read the value for the requested property.
-    ::android::base::Result<
-            std::unique_ptr<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
-    readValue(int32_t prop, int32_t area = 0, int64_t token = 0) const;
+    // Read the value for the requested property. Returns {@code StatusCode::NOT_AVAILABLE} if the
+    // value has not been set yet. Returns {@code StatusCode::INVALID_ARG} if the property is
+    // not configured.
+    ::android::base::Result<VehiclePropValuePool::RecyclableType> readValue(
+            int32_t prop, int32_t area = 0, int64_t token = 0) const;
 
     // Get all property configs.
     std::vector<::aidl::android::hardware::automotive::vehicle::VehiclePropConfig> getAllConfigs()
@@ -95,25 +107,34 @@
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig*>
     getConfig(int32_t propId) const;
 
+    // Set a callback that would be called when a property value has been updated.
+    void setOnValueChangeCallback(const OnValueChangeCallback& callback);
+
   private:
     struct RecordId {
         int32_t area;
         int64_t token;
 
-        bool operator==(const RecordId& other) const;
-        bool operator<(const RecordId& other) const;
-
         std::string toString() const;
+
+        bool operator==(const RecordId& other) const;
+    };
+
+    struct RecordIdHash {
+        size_t operator()(RecordId const& recordId) const;
     };
 
     struct Record {
         ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig propConfig;
         TokenFunction tokenFunction;
-        std::map<RecordId, ::aidl::android::hardware::automotive::vehicle::VehiclePropValue> values;
+        std::unordered_map<RecordId, VehiclePropValuePool::RecyclableType, RecordIdHash> values;
     };
 
+    // {@code VehiclePropValuePool} is thread-safe.
+    std::shared_ptr<VehiclePropValuePool> mValuePool;
     mutable std::mutex mLock;
     std::unordered_map<int32_t, Record> mRecordsByPropId GUARDED_BY(mLock);
+    OnValueChangeCallback mOnValueChangeCallback GUARDED_BY(mLock);
 
     const Record* getRecordLocked(int32_t propId) const;
 
@@ -123,9 +144,8 @@
             const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue,
             const Record& record) const;
 
-    ::android::base::Result<
-            std::unique_ptr<::aidl::android::hardware::automotive::vehicle::VehiclePropValue>>
-    readValueLocked(const RecordId& recId, const Record& record) const;
+    ::android::base::Result<VehiclePropValuePool::RecyclableType> readValueLocked(
+            const RecordId& recId, const Record& record) const;
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
index b660f36..8d12c2b 100644
--- a/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehiclePropertyStore.cpp
@@ -19,31 +19,47 @@
 
 #include "VehiclePropertyStore.h"
 
+#include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
 #include <android-base/format.h>
+#include <math/HashCombine.h>
 
 namespace android {
 namespace hardware {
 namespace automotive {
 namespace vehicle {
 
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::Error;
 using ::android::base::Result;
 
 bool VehiclePropertyStore::RecordId::operator==(const VehiclePropertyStore::RecordId& other) const {
     return area == other.area && token == other.token;
 }
 
-bool VehiclePropertyStore::RecordId::operator<(const VehiclePropertyStore::RecordId& other) const {
-    return area < other.area || (area == other.area && token < other.token);
-}
-
 std::string VehiclePropertyStore::RecordId::toString() const {
     return ::fmt::format("RecordID{{.areaId={:d}, .token={:d}}}", area, token);
 }
 
+size_t VehiclePropertyStore::RecordIdHash::operator()(RecordId const& recordId) const {
+    size_t res = 0;
+    hashCombine(res, recordId.area);
+    hashCombine(res, recordId.token);
+    return res;
+}
+
+VehiclePropertyStore::~VehiclePropertyStore() {
+    std::lock_guard<std::mutex> lockGuard(mLock);
+
+    // Recycling record requires mValuePool, so need to recycle them before destroying mValuePool.
+    mRecordsByPropId.clear();
+    mValuePool.reset();
+}
+
 const VehiclePropertyStore::Record* VehiclePropertyStore::getRecordLocked(int32_t propId) const
         REQUIRES(mLock) {
     auto RecordIt = mRecordsByPropId.find(propId);
@@ -68,13 +84,13 @@
     return recId;
 }
 
-Result<std::unique_ptr<VehiclePropValue>> VehiclePropertyStore::readValueLocked(
+Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValueLocked(
         const RecordId& recId, const Record& record) const REQUIRES(mLock) {
-    auto it = record.values.find(recId);
-    if (it == record.values.end()) {
-        return Errorf("Record ID: {} is not found", recId.toString());
+    if (auto it = record.values.find(recId); it != record.values.end()) {
+        return mValuePool->obtain(*(it->second));
     }
-    return std::make_unique<VehiclePropValue>(it->second);
+    return Error(toInt(StatusCode::NOT_AVAILABLE))
+           << "Record ID: " << recId.toString() << " is not found";
 }
 
 void VehiclePropertyStore::registerProperty(const VehiclePropConfig& config,
@@ -87,36 +103,49 @@
     };
 }
 
-Result<void> VehiclePropertyStore::writeValue(const VehiclePropValue& propValue) {
+Result<void> VehiclePropertyStore::writeValue(VehiclePropValuePool::RecyclableType propValue,
+                                              bool updateStatus) {
     std::lock_guard<std::mutex> g(mLock);
 
-    VehiclePropertyStore::Record* record = getRecordLocked(propValue.prop);
+    int32_t propId = propValue->prop;
+
+    VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Errorf("property: {:d} not registered", propValue.prop);
+        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
     }
 
-    if (!isGlobalProp(propValue.prop) && getAreaConfig(propValue, record->propConfig) == nullptr) {
-        return Errorf("no config for property: {:d} area: {:d}", propValue.prop, propValue.areaId);
+    if (!isGlobalProp(propId) && getAreaConfig(*propValue, record->propConfig) == nullptr) {
+        return Error(toInt(StatusCode::INVALID_ARG))
+               << "no config for property: " << propId << " area: " << propValue->areaId;
     }
 
-    VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
-    auto it = record->values.find(recId);
-    if (it == record->values.end()) {
-        record->values[recId] = propValue;
-        return {};
-    }
-    VehiclePropValue* valueToUpdate = &(it->second);
+    VehiclePropertyStore::RecordId recId = getRecordIdLocked(*propValue, *record);
+    bool valueUpdated = true;
+    if (auto it = record->values.find(recId); it != record->values.end()) {
+        const VehiclePropValue* valueToUpdate = it->second.get();
+        int64_t oldTimestamp = valueToUpdate->timestamp;
+        VehiclePropertyStatus oldStatus = valueToUpdate->status;
+        // propValue is outdated and drops it.
+        if (oldTimestamp > propValue->timestamp) {
+            return Error(toInt(StatusCode::INVALID_ARG))
+                   << "outdated timestamp: " << propValue->timestamp;
+        }
+        if (!updateStatus) {
+            propValue->status = oldStatus;
+        }
 
-    // propValue is outdated and drops it.
-    if (valueToUpdate->timestamp > propValue.timestamp) {
-        return Errorf("outdated timestamp: {:d}", propValue.timestamp);
+        valueUpdated = (valueToUpdate->value != propValue->value ||
+                        valueToUpdate->status != propValue->status ||
+                        valueToUpdate->prop != propValue->prop ||
+                        valueToUpdate->areaId != propValue->areaId);
+    } else if (!updateStatus) {
+        propValue->status = VehiclePropertyStatus::AVAILABLE;
     }
-    // Update the propertyValue.
-    // The timestamp in propertyStore should only be updated by the server side. It indicates
-    // the time when the event is generated by the server.
-    valueToUpdate->timestamp = propValue.timestamp;
-    valueToUpdate->value = propValue.value;
-    valueToUpdate->status = propValue.status;
+
+    record->values[recId] = std::move(propValue);
+    if (valueUpdated && mOnValueChangeCallback != nullptr) {
+        mOnValueChangeCallback(*(record->values[recId]));
+    }
     return {};
 }
 
@@ -145,58 +174,59 @@
     record->values.clear();
 }
 
-std::vector<VehiclePropValue> VehiclePropertyStore::readAllValues() const {
+std::vector<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readAllValues() const {
     std::lock_guard<std::mutex> g(mLock);
 
-    std::vector<VehiclePropValue> allValues;
+    std::vector<VehiclePropValuePool::RecyclableType> allValues;
 
     for (auto const& [_, record] : mRecordsByPropId) {
         for (auto const& [_, value] : record.values) {
-            allValues.push_back(value);
+            allValues.push_back(std::move(mValuePool->obtain(*value)));
         }
     }
 
     return allValues;
 }
 
-Result<std::vector<VehiclePropValue>> VehiclePropertyStore::readValuesForProperty(
-        int32_t propId) const {
+Result<std::vector<VehiclePropValuePool::RecyclableType>>
+VehiclePropertyStore::readValuesForProperty(int32_t propId) const {
     std::lock_guard<std::mutex> g(mLock);
 
-    std::vector<VehiclePropValue> values;
+    std::vector<VehiclePropValuePool::RecyclableType> values;
 
     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Errorf("property: {:d} not registered", propId);
+        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
     }
 
     for (auto const& [_, value] : record->values) {
-        values.push_back(value);
+        values.push_back(std::move(mValuePool->obtain(*value)));
     }
     return values;
 }
 
-Result<std::unique_ptr<VehiclePropValue>> VehiclePropertyStore::readValue(
+Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValue(
         const VehiclePropValue& propValue) const {
     std::lock_guard<std::mutex> g(mLock);
 
-    const VehiclePropertyStore::Record* record = getRecordLocked(propValue.prop);
+    int32_t propId = propValue.prop;
+    const VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Errorf("property: {:d} not registered", propValue.prop);
+        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
     }
 
     VehiclePropertyStore::RecordId recId = getRecordIdLocked(propValue, *record);
     return readValueLocked(recId, *record);
 }
 
-Result<std::unique_ptr<VehiclePropValue>> VehiclePropertyStore::readValue(int32_t propId,
-                                                                          int32_t areaId,
-                                                                          int64_t token) const {
+Result<VehiclePropValuePool::RecyclableType> VehiclePropertyStore::readValue(int32_t propId,
+                                                                             int32_t areaId,
+                                                                             int64_t token) const {
     std::lock_guard<std::mutex> g(mLock);
 
     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Errorf("property: {:d} not registered", propId);
+        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
     }
 
     VehiclePropertyStore::RecordId recId{.area = isGlobalProp(propId) ? 0 : areaId, .token = token};
@@ -219,12 +249,19 @@
 
     const VehiclePropertyStore::Record* record = getRecordLocked(propId);
     if (record == nullptr) {
-        return Errorf("property: {:d} not registered", propId);
+        return Error(toInt(StatusCode::INVALID_ARG)) << "property: " << propId << " not registered";
     }
 
     return &record->propConfig;
 }
 
+void VehiclePropertyStore::setOnValueChangeCallback(
+        const VehiclePropertyStore::OnValueChangeCallback& callback) {
+    std::lock_guard<std::mutex> g(mLock);
+
+    mOnValueChangeCallback = callback;
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
index 8c70fea..1f230e7 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehiclePropertyStoreTest.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <PropertyUtils.h>
+#include <VehicleHalTypes.h>
 #include <VehiclePropertyStore.h>
 #include <VehicleUtils.h>
 #include <gmock/gmock.h>
@@ -27,11 +28,14 @@
 
 namespace {
 
+using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::base::Result;
 using ::testing::ElementsAre;
@@ -51,6 +55,17 @@
     return value.timestamp;
 }
 
+// A helper function to turn value pointer to value structure for easier comparison.
+std::vector<VehiclePropValue> convertValuePtrsToValues(
+        const std::vector<VehiclePropValuePool::RecyclableType>& values) {
+    std::vector<VehiclePropValue> returnValues;
+    returnValues.reserve(values.size());
+    for (auto& value : values) {
+        returnValues.push_back(*value);
+    }
+    return returnValues;
+}
+
 }  // namespace
 
 class VehiclePropertyStoreTest : public ::testing::Test {
@@ -70,32 +85,36 @@
                                 VehicleAreaConfig{.areaId = WHEEL_REAR_LEFT},
                                 VehicleAreaConfig{.areaId = WHEEL_REAR_RIGHT}},
         };
-        mStore.registerProperty(mConfigFuelCapacity);
-        mStore.registerProperty(configTirePressure);
+        mValuePool = std::make_shared<VehiclePropValuePool>();
+        mStore.reset(new VehiclePropertyStore(mValuePool));
+        mStore->registerProperty(mConfigFuelCapacity);
+        mStore->registerProperty(configTirePressure);
     }
 
-    VehiclePropertyStore mStore;
     VehiclePropConfig mConfigFuelCapacity;
+    std::shared_ptr<VehiclePropValuePool> mValuePool;
+    std::unique_ptr<VehiclePropertyStore> mStore;
 };
 
 TEST_F(VehiclePropertyStoreTest, testGetAllConfigs) {
-    std::vector<VehiclePropConfig> configs = mStore.getAllConfigs();
+    std::vector<VehiclePropConfig> configs = mStore->getAllConfigs();
 
     ASSERT_EQ(configs.size(), static_cast<size_t>(2));
 }
 
 TEST_F(VehiclePropertyStoreTest, testGetConfig) {
     Result<const VehiclePropConfig*> result =
-            mStore.getConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
+            mStore->getConfig(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
 
     ASSERT_RESULT_OK(result);
     ASSERT_EQ(*(result.value()), mConfigFuelCapacity);
 }
 
 TEST_F(VehiclePropertyStoreTest, testGetConfigWithInvalidPropId) {
-    Result<const VehiclePropConfig*> result = mStore.getConfig(INVALID_PROP_ID);
+    Result<const VehiclePropConfig*> result = mStore->getConfig(INVALID_PROP_ID);
 
-    ASSERT_FALSE(result.ok()) << "expect error when getting a config for an invalid property ID";
+    EXPECT_FALSE(result.ok()) << "expect error when getting a config for an invalid property ID";
+    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
 }
 
 std::vector<VehiclePropValue> getTestPropValues() {
@@ -122,54 +141,56 @@
 TEST_F(VehiclePropertyStoreTest, testWriteValueOk) {
     auto values = getTestPropValues();
 
-    ASSERT_RESULT_OK(mStore.writeValue(values[0]));
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(values[0])));
 }
 
 TEST_F(VehiclePropertyStoreTest, testReadAllValues) {
     auto values = getTestPropValues();
     for (const auto& value : values) {
-        ASSERT_RESULT_OK(mStore.writeValue(value));
+        ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(value)));
     }
 
-    auto gotValues = mStore.readAllValues();
+    auto gotValues = mStore->readAllValues();
 
-    ASSERT_THAT(gotValues, WhenSortedBy(propValueCmp, Eq(values)));
+    ASSERT_THAT(convertValuePtrsToValues(gotValues), WhenSortedBy(propValueCmp, Eq(values)));
 }
 
 TEST_F(VehiclePropertyStoreTest, testReadValuesForPropertyOneValue) {
     auto values = getTestPropValues();
     for (const auto& value : values) {
-        ASSERT_RESULT_OK(mStore.writeValue(value));
+        ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(value)));
     }
 
-    auto result = mStore.readValuesForProperty(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
+    auto result = mStore->readValuesForProperty(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
 
     ASSERT_RESULT_OK(result);
-    ASSERT_THAT(result.value(), ElementsAre(values[0]));
+    ASSERT_THAT(convertValuePtrsToValues(result.value()), ElementsAre(values[0]));
 }
 
 TEST_F(VehiclePropertyStoreTest, testReadValuesForPropertyMultipleValues) {
     auto values = getTestPropValues();
     for (const auto& value : values) {
-        ASSERT_RESULT_OK(mStore.writeValue(value));
+        ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(value)));
     }
 
-    auto result = mStore.readValuesForProperty(toInt(VehicleProperty::TIRE_PRESSURE));
+    auto result = mStore->readValuesForProperty(toInt(VehicleProperty::TIRE_PRESSURE));
 
     ASSERT_RESULT_OK(result);
-    ASSERT_THAT(result.value(), WhenSortedBy(propValueCmp, ElementsAre(values[1], values[2])));
+    ASSERT_THAT(convertValuePtrsToValues(result.value()),
+                WhenSortedBy(propValueCmp, ElementsAre(values[1], values[2])));
 }
 
 TEST_F(VehiclePropertyStoreTest, testReadValuesForPropertyError) {
-    auto result = mStore.readValuesForProperty(INVALID_PROP_ID);
+    auto result = mStore->readValuesForProperty(INVALID_PROP_ID);
 
-    ASSERT_FALSE(result.ok()) << "expect error when reading values for an invalid property";
+    EXPECT_FALSE(result.ok()) << "expect error when reading values for an invalid property";
+    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
 }
 
 TEST_F(VehiclePropertyStoreTest, testReadValueOk) {
     auto values = getTestPropValues();
     for (const auto& value : values) {
-        ASSERT_RESULT_OK(mStore.writeValue(value));
+        ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(value)));
     }
 
     VehiclePropValue requestValue = {
@@ -177,7 +198,7 @@
             .areaId = WHEEL_FRONT_LEFT,
     };
 
-    auto result = mStore.readValue(requestValue);
+    auto result = mStore->readValue(requestValue);
 
     ASSERT_RESULT_OK(result);
     ASSERT_EQ(*(result.value()), values[1]);
@@ -186,10 +207,10 @@
 TEST_F(VehiclePropertyStoreTest, testReadValueByPropIdOk) {
     auto values = getTestPropValues();
     for (const auto& value : values) {
-        ASSERT_RESULT_OK(mStore.writeValue(value));
+        ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(value)));
     }
 
-    auto result = mStore.readValue(toInt(VehicleProperty::TIRE_PRESSURE), WHEEL_FRONT_RIGHT);
+    auto result = mStore->readValue(toInt(VehicleProperty::TIRE_PRESSURE), WHEEL_FRONT_RIGHT);
 
     ASSERT_EQ(*(result.value()), values[2]);
 }
@@ -197,51 +218,58 @@
 TEST_F(VehiclePropertyStoreTest, testReadValueError) {
     auto values = getTestPropValues();
     for (const auto& value : values) {
-        ASSERT_RESULT_OK(mStore.writeValue(value));
+        ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(value)));
     }
 
-    auto result = mStore.readValue(toInt(VehicleProperty::TIRE_PRESSURE), WHEEL_REAR_LEFT);
+    auto result = mStore->readValue(toInt(VehicleProperty::TIRE_PRESSURE), WHEEL_REAR_LEFT);
 
-    ASSERT_FALSE(result.ok()) << "expect error when reading a value that has not been written";
+    EXPECT_FALSE(result.ok()) << "expect error when reading a value that has not been written";
+    EXPECT_EQ(result.error().code(), toInt(StatusCode::NOT_AVAILABLE));
 }
 
 TEST_F(VehiclePropertyStoreTest, testWriteValueError) {
-    ASSERT_FALSE(mStore.writeValue({
-                                           .prop = INVALID_PROP_ID,
-                                           .value = {.floatValues = {1.0}},
-                                   })
-                         .ok())
-            << "expect error when writing value for an invalid property ID";
+    auto v = mValuePool->obtain(VehiclePropertyType::FLOAT);
+    v->prop = INVALID_PROP_ID;
+    v->value.floatValues = {1.0};
+
+    auto result = mStore->writeValue(std::move(v));
+
+    EXPECT_FALSE(result.ok()) << "expect error when writing value for an invalid property ID";
+    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
 }
 
 TEST_F(VehiclePropertyStoreTest, testWriteValueNoAreaConfig) {
-    ASSERT_FALSE(mStore.writeValue({
-                                           .prop = toInt(VehicleProperty::TIRE_PRESSURE),
-                                           .value = {.floatValues = {180.0}},
-                                           // There is no config for ALL_WHEELS.
-                                           .areaId = ALL_WHEELS,
-                                   })
-                         .ok())
-            << "expect error when writing value for an area without config";
+    auto v = mValuePool->obtain(VehiclePropertyType::FLOAT);
+    v->prop = toInt(VehicleProperty::TIRE_PRESSURE);
+    v->value.floatValues = {1.0};
+    // There is no config for ALL_WHEELS.
+    v->areaId = ALL_WHEELS;
+
+    auto result = mStore->writeValue(std::move(v));
+
+    EXPECT_FALSE(result.ok()) << "expect error when writing value for an area without config";
+    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
 }
 
 TEST_F(VehiclePropertyStoreTest, testWriteOutdatedValue) {
-    ASSERT_RESULT_OK(mStore.writeValue({
-            .timestamp = 1,
-            .prop = toInt(VehicleProperty::TIRE_PRESSURE),
-            .value = {.floatValues = {180.0}},
-            .areaId = WHEEL_FRONT_LEFT,
-    }));
+    auto v = mValuePool->obtain(VehiclePropertyType::FLOAT);
+    v->timestamp = 1;
+    v->prop = toInt(VehicleProperty::TIRE_PRESSURE);
+    v->value.floatValues = {180.0};
+    v->areaId = WHEEL_FRONT_LEFT;
+    ASSERT_RESULT_OK(mStore->writeValue(std::move(v)));
 
     // Write an older value.
-    ASSERT_FALSE(mStore.writeValue({
-                                           .timestamp = 0,
-                                           .prop = toInt(VehicleProperty::TIRE_PRESSURE),
-                                           .value = {.floatValues = {180.0}},
-                                           .areaId = WHEEL_FRONT_LEFT,
-                                   })
-                         .ok())
-            << "expect error when writing an outdated value";
+    auto v2 = mValuePool->obtain(VehiclePropertyType::FLOAT);
+    v2->timestamp = 0;
+    v2->prop = toInt(VehicleProperty::TIRE_PRESSURE);
+    v2->value.floatValues = {180.0};
+    v2->areaId = WHEEL_FRONT_LEFT;
+
+    auto result = mStore->writeValue(std::move(v2));
+
+    EXPECT_FALSE(result.ok()) << "expect error when writing an outdated value";
+    EXPECT_EQ(result.error().code(), toInt(StatusCode::INVALID_ARG));
 }
 
 TEST_F(VehiclePropertyStoreTest, testToken) {
@@ -251,7 +279,7 @@
     };
 
     // Replace existing config.
-    mStore.registerProperty(config, timestampToken);
+    mStore->registerProperty(config, timestampToken);
 
     VehiclePropValue fuelCapacityValueToken1 = {
             .timestamp = 1,
@@ -265,15 +293,15 @@
             .value = {.floatValues = {2.0}},
     };
 
-    ASSERT_RESULT_OK(mStore.writeValue(fuelCapacityValueToken1));
-    ASSERT_RESULT_OK(mStore.writeValue(fuelCapacityValueToken2));
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacityValueToken1)));
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacityValueToken2)));
 
-    auto result = mStore.readValuesForProperty(propId);
+    auto result = mStore->readValuesForProperty(propId);
 
     ASSERT_RESULT_OK(result);
     ASSERT_EQ(result.value().size(), static_cast<size_t>(2));
 
-    auto tokenResult = mStore.readValue(propId, /*areaId=*/0, /*token=*/2);
+    auto tokenResult = mStore->readValue(propId, /*areaId=*/0, /*token=*/2);
 
     ASSERT_RESULT_OK(tokenResult);
     ASSERT_EQ(*(tokenResult.value()), fuelCapacityValueToken2);
@@ -282,14 +310,16 @@
 TEST_F(VehiclePropertyStoreTest, testRemoveValue) {
     auto values = getTestPropValues();
     for (const auto& value : values) {
-        ASSERT_RESULT_OK(mStore.writeValue(value));
+        ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(value)));
     }
 
-    mStore.removeValue(values[0]);
+    mStore->removeValue(values[0]);
+    auto result = mStore->readValue(values[0]);
 
-    ASSERT_FALSE(mStore.readValue(values[0]).ok()) << "expect error when reading a removed value";
+    EXPECT_FALSE(result.ok()) << "expect error when reading a removed value";
+    EXPECT_EQ(result.error().code(), toInt(StatusCode::NOT_AVAILABLE));
 
-    auto leftTirePressureResult = mStore.readValue(values[1]);
+    auto leftTirePressureResult = mStore->readValue(values[1]);
 
     ASSERT_RESULT_OK(leftTirePressureResult);
     ASSERT_EQ(*(leftTirePressureResult.value()), values[1]);
@@ -298,16 +328,127 @@
 TEST_F(VehiclePropertyStoreTest, testRemoveValuesForProperty) {
     auto values = getTestPropValues();
     for (const auto& value : values) {
-        ASSERT_RESULT_OK(mStore.writeValue(value));
+        ASSERT_RESULT_OK(mStore->writeValue(std::move(mValuePool->obtain(value))));
     }
 
-    mStore.removeValuesForProperty(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
-    mStore.removeValuesForProperty(toInt(VehicleProperty::TIRE_PRESSURE));
+    mStore->removeValuesForProperty(toInt(VehicleProperty::INFO_FUEL_CAPACITY));
+    mStore->removeValuesForProperty(toInt(VehicleProperty::TIRE_PRESSURE));
 
-    auto gotValues = mStore.readAllValues();
+    auto gotValues = mStore->readAllValues();
     ASSERT_TRUE(gotValues.empty());
 }
 
+TEST_F(VehiclePropertyStoreTest, testWriteValueUpdateStatus) {
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), true));
+
+    fuelCapacity.status = VehiclePropertyStatus::UNAVAILABLE;
+
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), true));
+
+    VehiclePropValue requestValue = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+    };
+
+    auto result = mStore->readValue(requestValue);
+
+    ASSERT_RESULT_OK(result);
+    ASSERT_EQ(result.value()->status, VehiclePropertyStatus::UNAVAILABLE);
+}
+
+TEST_F(VehiclePropertyStoreTest, testWriteValueNoUpdateStatus) {
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), true));
+
+    fuelCapacity.status = VehiclePropertyStatus::UNAVAILABLE;
+
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), false));
+
+    VehiclePropValue requestValue = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+    };
+
+    auto result = mStore->readValue(requestValue);
+
+    ASSERT_RESULT_OK(result);
+    ASSERT_EQ(result.value()->status, VehiclePropertyStatus::AVAILABLE);
+}
+
+TEST_F(VehiclePropertyStoreTest, testWriteValueNoUpdateStatusForNewValue) {
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+            .status = VehiclePropertyStatus::UNAVAILABLE,
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity), false));
+
+    VehiclePropValue requestValue = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+    };
+
+    auto result = mStore->readValue(requestValue);
+
+    ASSERT_RESULT_OK(result);
+    ASSERT_EQ(result.value()->status, VehiclePropertyStatus::AVAILABLE);
+}
+
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackNewValue) {
+    VehiclePropValue updatedValue;
+    mStore->setOnValueChangeCallback(
+            [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    ASSERT_EQ(updatedValue, fuelCapacity);
+}
+
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackUpdateValue) {
+    VehiclePropValue updatedValue;
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    mStore->setOnValueChangeCallback(
+            [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+
+    fuelCapacity.value.floatValues[0] = 2.0;
+    fuelCapacity.timestamp = 1;
+
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    ASSERT_EQ(updatedValue, fuelCapacity);
+}
+
+TEST_F(VehiclePropertyStoreTest, testPropertyChangeCallbackNoUpdate) {
+    VehiclePropValue updatedValue{
+            .prop = INVALID_PROP_ID,
+    };
+    VehiclePropValue fuelCapacity = {
+            .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
+            .value = {.floatValues = {1.0}},
+    };
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    mStore->setOnValueChangeCallback(
+            [&updatedValue](const VehiclePropValue& value) { updatedValue = value; });
+
+    // Write the same value again should succeed but should not trigger callback.
+    ASSERT_RESULT_OK(mStore->writeValue(mValuePool->obtain(fuelCapacity)));
+
+    ASSERT_EQ(updatedValue.prop, INVALID_PROP_ID);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index 7ad3d31..131eb3b 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
+#include <ConcurrentQueue.h>
 #include <PropertyUtils.h>
 #include <VehicleUtils.h>
 
 #include <gtest/gtest.h>
+
+#include <atomic>
+#include <thread>
 #include <vector>
 
 namespace android {
@@ -231,7 +235,7 @@
             << "vector size should always be 1 for single value type";
 }
 
-TEST(VehicleUtilsTest, testCreateVehiclePropValueFloVecatVec) {
+TEST(VehicleUtilsTest, testCreateVehiclePropValueFloatVecMultiValues) {
     std::unique_ptr<VehiclePropValue> value =
             createVehiclePropValueVec(VehiclePropertyType::FLOAT_VEC, /*vecSize=*/2);
 
@@ -247,6 +251,90 @@
     ASSERT_EQ(2u, value->value.byteValues.size());
 }
 
+TEST(VehicleUtilsTest, testConcurrentQueueOneThread) {
+    ConcurrentQueue<int> queue;
+
+    queue.push(1);
+    queue.push(2);
+    auto result = queue.flush();
+
+    ASSERT_EQ(result, std::vector<int>({1, 2}));
+}
+
+TEST(VehicleUtilsTest, testConcurrentQueueMultipleThreads) {
+    ConcurrentQueue<int> queue;
+    std::vector<int> results;
+    std::atomic<bool> stop = false;
+
+    std::thread t1([&queue]() {
+        for (int i = 0; i < 100; i++) {
+            queue.push(0);
+        }
+    });
+    std::thread t2([&queue]() {
+        for (int i = 0; i < 100; i++) {
+            queue.push(1);
+        }
+    });
+    std::thread t3([&queue, &results, &stop]() {
+        while (!stop) {
+            queue.waitForItems();
+            for (int i : queue.flush()) {
+                results.push_back(i);
+            }
+        }
+
+        // After we stop, get all the remaining values in the queue.
+        for (int i : queue.flush()) {
+            results.push_back(i);
+        }
+    });
+
+    t1.join();
+    t2.join();
+
+    stop = true;
+    queue.deactivate();
+    t3.join();
+
+    size_t zeroCount = 0;
+    size_t oneCount = 0;
+    for (int i : results) {
+        if (i == 0) {
+            zeroCount++;
+        }
+        if (i == 1) {
+            oneCount++;
+        }
+    }
+
+    EXPECT_EQ(results.size(), static_cast<size_t>(200));
+    EXPECT_EQ(zeroCount, static_cast<size_t>(100));
+    EXPECT_EQ(oneCount, static_cast<size_t>(100));
+}
+
+TEST(VehicleUtilsTest, testConcurrentQueuePushAfterDeactivate) {
+    ConcurrentQueue<int> queue;
+
+    queue.deactivate();
+    queue.push(1);
+
+    ASSERT_TRUE(queue.flush().empty());
+}
+
+TEST(VehicleUtilsTest, testConcurrentQueueDeactivateNotifyWaitingThread) {
+    ConcurrentQueue<int> queue;
+
+    std::thread t([&queue]() {
+        // This would block until queue is deactivated.
+        queue.waitForItems();
+    });
+
+    queue.deactivate();
+
+    t.join();
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/camera/metadata/3.8/types.hal b/camera/metadata/3.8/types.hal
new file mode 100644
index 0000000..dcee775
--- /dev/null
+++ b/camera/metadata/3.8/types.hal
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.8;
+
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+import android.hardware.camera.metadata@3.4;
+import android.hardware.camera.metadata@3.5;
+import android.hardware.camera.metadata@3.6;
+import android.hardware.camera.metadata@3.7;
+
+// No new metadata sections added in this revision
+
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.7::CameraMetadataTag {
+    /** android.flash.info.strengthMaximumLevel [static, int32, public]
+     *
+     * <p>Maximum flashlight brightness level.</p>
+     */
+    ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_FLASH_INFO_END,
+
+    /** android.flash.info.strengthDefaultLevel [static, int32, public]
+     *
+     * <p>Default flashlight brightness level to be set via
+     * {android.hardware.camera2.CameraManager#setTorchStrengthLevel}.</p>
+     */
+    ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,
+
+    ANDROID_FLASH_INFO_END_3_8,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index a1f1de9..92f9263 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -418,6 +418,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.neuralnetworks</name>
+        <version>1-2</version>
         <interface>
             <name>IDevice</name>
             <regex-instance>.*</regex-instance>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index d8c9170..1def738 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -57,6 +57,7 @@
             "android.hardware.graphics.common",
             "android.hardware.keymaster",
             "android.hardware.radio",
+            "android.hardware.uwb.fira_android",
 
             // Fastboot HAL is only used by recovery. Recovery is owned by OEM. Framework
             // does not depend on this HAL, hence it is not declared in any manifests or matrices.
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index 1a33a9e..f254cd5 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -1,7 +1,5 @@
+# Bug component: 156070
 #Context Hub team
 arthuri@google.com
 bduddie@google.com
 stange@google.com
-
-#VTS team
-dshi@google.com
diff --git a/contexthub/1.1/vts/functional/OWNERS b/contexthub/1.1/vts/functional/OWNERS
index 1a33a9e..2cf5bca 100644
--- a/contexthub/1.1/vts/functional/OWNERS
+++ b/contexthub/1.1/vts/functional/OWNERS
@@ -1,7 +1,2 @@
-#Context Hub team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-#VTS team
-dshi@google.com
+# Bug component: 156070
+include ../../../1.0/vts/functional/OWNERS
diff --git a/contexthub/1.2/vts/functional/OWNERS b/contexthub/1.2/vts/functional/OWNERS
index 1a33a9e..2cf5bca 100644
--- a/contexthub/1.2/vts/functional/OWNERS
+++ b/contexthub/1.2/vts/functional/OWNERS
@@ -1,7 +1,2 @@
-#Context Hub team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-#VTS team
-dshi@google.com
+# Bug component: 156070
+include ../../../1.0/vts/functional/OWNERS
diff --git a/current.txt b/current.txt
index cb91843..1dbf5ab 100644
--- a/current.txt
+++ b/current.txt
@@ -906,7 +906,7 @@
 
 # ABI preserving changes to HALs during Android T
 62ace52d9c3ff1f60f94118557a2aaf0b953513e59dcd34d5f94ae28d4c7e780 android.hardware.fastboot@1.0::IFastboot
-b4a59462aa7d1346ee3eaa06a8e13682462746cf1be62ed2a2bd46bf404d01b7 android.hardware.graphics.composer@2.4::IComposerClient
+f767a132ef28275294db15353f14f3876a4048770751931a77d038d4228f2cb7 android.hardware.graphics.composer@2.4::IComposerClient
 ca62a2a95d173ed323309e5e00f653ad3cceec82a6e5e4976a249cb5aafe2515 android.hardware.neuralnetworks@1.2::types
 fa76bced6b1b71c40fc706c508a9011284c57f57831cd0cf5f45653ed4ea463e android.hardware.neuralnetworks@1.3::types
 
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index fe59a9d..2d4cc7d 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -61,18 +61,18 @@
 void TestRenderEngine::drawLayers() {
     base::unique_fd bufferFence;
 
-    std::vector<const renderengine::LayerSettings*> compositionLayerPointers;
-    compositionLayerPointers.reserve(mCompositionLayers.size());
+    std::vector<renderengine::LayerSettings> compositionLayers;
+    compositionLayers.reserve(mCompositionLayers.size());
     std::transform(mCompositionLayers.begin(), mCompositionLayers.end(),
-                   std::back_insert_iterator(compositionLayerPointers),
-                   [](renderengine::LayerSettings& settings) -> renderengine::LayerSettings* {
-                       return &settings;
+                   std::back_insert_iterator(compositionLayers),
+                   [](renderengine::LayerSettings& settings) -> renderengine::LayerSettings {
+                       return settings;
                    });
     auto texture = std::make_shared<renderengine::ExternalTexture>(
             mGraphicBuffer, *mRenderEngine, renderengine::ExternalTexture::Usage::WRITEABLE);
     auto [status, readyFence] = mRenderEngine
-                                        ->drawLayers(mDisplaySettings, compositionLayerPointers,
-                                                     texture, true, std::move(bufferFence))
+                                        ->drawLayers(mDisplaySettings, compositionLayers, texture,
+                                                     true, std::move(bufferFence))
                                         .get();
     int fd = readyFence.release();
     if (fd != -1) {
diff --git a/graphics/composer/2.2/vts/functional/OWNERS b/graphics/composer/2.2/vts/functional/OWNERS
index ea06752..31b0dc7 100644
--- a/graphics/composer/2.2/vts/functional/OWNERS
+++ b/graphics/composer/2.2/vts/functional/OWNERS
@@ -1,7 +1,5 @@
+# Bug component: 25423
 # Graphics team
 adyabr@google.com
 lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+sumir@google.com
diff --git a/graphics/composer/2.3/vts/functional/OWNERS b/graphics/composer/2.3/vts/functional/OWNERS
index ea06752..31b0dc7 100644
--- a/graphics/composer/2.3/vts/functional/OWNERS
+++ b/graphics/composer/2.3/vts/functional/OWNERS
@@ -1,7 +1,5 @@
+# Bug component: 25423
 # Graphics team
 adyabr@google.com
 lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+sumir@google.com
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
index e27fd6e..476302f 100644
--- a/graphics/composer/2.4/IComposerClient.hal
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -34,9 +34,7 @@
         /**
          * The configuration group ID (as int32_t) this config is associated to.
          * Switching between configurations within the same group may be done seamlessly
-         * in some conditions via setActiveConfigWithConstraints. Configurations which
-         * share the same config group are similar in all attributes except for the
-         * vsync period.
+         * in some conditions via setActiveConfigWithConstraints.
          */
         CONFIG_GROUP = 7,
     };
diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS
index ea06752..31b0dc7 100644
--- a/graphics/composer/2.4/vts/functional/OWNERS
+++ b/graphics/composer/2.4/vts/functional/OWNERS
@@ -1,7 +1,5 @@
+# Bug component: 25423
 # Graphics team
 adyabr@google.com
 lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+sumir@google.com
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index 5aceda7..b071f71 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -19,8 +19,6 @@
 #include <algorithm>
 #include <regex>
 #include <thread>
-#include <unordered_map>
-#include <utility>
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
@@ -317,59 +315,6 @@
     }
 }
 
-TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4_ConfigsInAGroupDifferOnlyByVsyncPeriod) {
-    struct Resolution {
-        int32_t width, height;
-    };
-    struct Dpi {
-        int32_t x, y;
-    };
-    for (const auto& display : mDisplays) {
-        std::vector<Config> configs = mComposerClient->getDisplayConfigs(display.get());
-        std::unordered_map<int32_t, Resolution> configGroupToResolutionMap;
-        std::unordered_map<int32_t, Dpi> configGroupToDpiMap;
-        for (auto config : configs) {
-            const auto configGroup = mComposerClient->getDisplayAttribute_2_4(
-                    display.get(), config, IComposerClient::Attribute::CONFIG_GROUP);
-            const auto width = mComposerClient->getDisplayAttribute_2_4(
-                    display.get(), config, IComposerClient::Attribute::WIDTH);
-            const auto height = mComposerClient->getDisplayAttribute_2_4(
-                    display.get(), config, IComposerClient::Attribute::HEIGHT);
-            if (configGroupToResolutionMap.find(configGroup) == configGroupToResolutionMap.end()) {
-                configGroupToResolutionMap[configGroup] = {width, height};
-            }
-            EXPECT_EQ(configGroupToResolutionMap[configGroup].width, width);
-            EXPECT_EQ(configGroupToResolutionMap[configGroup].height, height);
-
-            int32_t dpiX = -1;
-            mComposerClient->getRaw()->getDisplayAttribute_2_4(
-                    display.get(), config, IComposerClient::Attribute::DPI_X,
-                    [&](const auto& tmpError, const auto& value) {
-                        if (tmpError == Error::NONE) {
-                            dpiX = value;
-                        }
-                    });
-            int32_t dpiY = -1;
-            mComposerClient->getRaw()->getDisplayAttribute_2_4(
-                    display.get(), config, IComposerClient::Attribute::DPI_Y,
-                    [&](const auto& tmpError, const auto& value) {
-                        if (tmpError == Error::NONE) {
-                            dpiY = value;
-                        }
-                    });
-            if (dpiX == -1 && dpiY == -1) {
-                continue;
-            }
-
-            if (configGroupToDpiMap.find(configGroup) == configGroupToDpiMap.end()) {
-                configGroupToDpiMap[configGroup] = {dpiX, dpiY};
-            }
-            EXPECT_EQ(configGroupToDpiMap[configGroup].x, dpiX);
-            EXPECT_EQ(configGroupToDpiMap[configGroup].y, dpiY);
-        }
-    }
-}
-
 TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) {
     VsyncPeriodNanos vsyncPeriodNanos;
     EXPECT_EQ(Error::BAD_DISPLAY,
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index 5006185..e33c653 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -67,3 +67,22 @@
     ],
     export_include_dirs: ["include"],
 }
+
+cc_library_headers {
+    name: "android.hardware.graphics.composer3-command-buffer",
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer3-V1-ndk",
+        "libbase",
+        "libfmq",
+        "libsync",
+    ],
+    static_libs: [
+        "libaidlcommonsupport",
+    ],
+    export_shared_lib_headers: [
+        "libfmq",
+        "libsync",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/aidl/OWNERS b/graphics/composer/aidl/OWNERS
new file mode 100644
index 0000000..9028d9d
--- /dev/null
+++ b/graphics/composer/aidl/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 1075131
+
+# Graphics team
+adyabr@google.com
+alecmouri@google.com
+sumir@google.com
\ No newline at end of file
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
index 557b3f8..9c49583 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Capability.aidl
@@ -38,4 +38,5 @@
   SIDEBAND_STREAM = 1,
   SKIP_CLIENT_COLOR_TRANSFORM = 2,
   PRESENT_FENCE_IS_NOT_RELIABLE = 3,
+  SKIP_VALIDATE = 4,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Command.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Command.aidl
index 3b31149..e19105d 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Command.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/Command.aidl
@@ -72,4 +72,5 @@
   SET_LAYER_PER_FRAME_METADATA_BLOBS = 50593792,
   SET_CLIENT_TARGET_PROPERTY = 17104896,
   SET_LAYER_GENERIC_METADATA = 68026368,
+  SET_LAYER_WHITE_POINT_NITS = 50659328,
 }
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
index 531fd14..5c37018 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -40,7 +40,6 @@
   void destroyVirtualDisplay(long display);
   android.hardware.graphics.composer3.ExecuteCommandsStatus executeCommands(int inLength, in android.hardware.common.NativeHandle[] inHandles);
   int getActiveConfig(long display);
-  void getClientTargetSupport(long display, int width, int height, android.hardware.graphics.common.PixelFormat format, android.hardware.graphics.common.Dataspace dataspace);
   android.hardware.graphics.composer3.ColorMode[] getColorModes(long display);
   float[] getDataspaceSaturationMatrix(android.hardware.graphics.common.Dataspace dataspace);
   int getDisplayAttribute(long display, int config, android.hardware.graphics.composer3.DisplayAttribute attribute);
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
index 028b6f5..ea619ae 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Capability.aidl
@@ -46,4 +46,15 @@
      * representation of the actual present time of a frame.
      */
     PRESENT_FENCE_IS_NOT_RELIABLE = 3,
+    /**
+     * Specifies that a device is able to skip the validateDisplay call before
+     * receiving a call to presentDisplay. The client will always skip
+     * validateDisplay and try to call presentDisplay regardless of the changes
+     * in the properties of the layers. If the device returns anything else than
+     * no error, it will call validateDisplay then presentDisplay again.
+     * For this capability to be worthwhile the device implementation of
+     * presentDisplay should fail as fast as possible in the case a
+     * validateDisplay step is needed.
+     */
+    SKIP_VALIDATE = 4,
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/Command.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/Command.aidl
index 5f987d0..95c07ac 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/Command.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/Command.aidl
@@ -689,8 +689,16 @@
      *
      *     0 - 3: clientTargetProperty.pixelFormat
      *     4 - 7: clientTargetProperty.dataspace
+     *     8 - 11: whitePointNits
      *
-     *   setClientTargetProperty(ClientTargetProperty clientTargetProperty);
+     * The white point parameter describes the intended white point of the client target buffer.
+     * When client composition blends both HDR and SDR content, the client must composite to the
+     * brightness space as specified by the hardware composer. This is so that adjusting the real
+     * display brightness may be applied atomically with compensating the client target output. For
+     * instance, client-compositing a list of SDR layers requires dimming the brightness space of
+     * the SDR buffers when an HDR layer is simultaneously device-composited.
+     *
+     *   setClientTargetProperty(ClientTargetProperty clientTargetProperty, float whitePointNits);
      */
     SET_CLIENT_TARGET_PROPERTY = 0x105 << OPCODE_SHIFT,
 
@@ -738,4 +746,18 @@
      *        corresponding to the key as described above
      */
     SET_LAYER_GENERIC_METADATA = 0x40e << OPCODE_SHIFT,
+
+    /**
+     * SET_LAYER_WHITE_POINT_NITS has this pseudo prototype
+     *
+     *   setLayerWhitePointNits(float sdrWhitePointNits);
+     *
+     * Sets the desired white point for the layer. This is intended to be used when presenting
+     * an SDR layer alongside HDR content. The HDR content will be presented at the display
+     * brightness in nits, and accordingly SDR content shall be dimmed to the desired white point
+     * provided.
+     *
+     * @param whitePointNits is the white point in nits.
+     */
+    SET_LAYER_WHITE_POINT_NITS = 0x305 << OPCODE_SHIFT,
 }
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index 87a3a50..2a9545d 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -189,28 +189,6 @@
     int getActiveConfig(long display);
 
     /**
-     * Returns whether a client target with the given properties can be
-     * handled by the device.
-     *
-     * This function must return true for a client target with width and
-     * height equal to the active display configuration dimensions,
-     * PixelFormat::RGBA_8888, and Dataspace::UNKNOWN. It is not required to
-     * return true for any other configuration.
-     *
-     * @param display is the display to query.
-     * @param width is the client target width in pixels.
-     * @param height is the client target height in pixels.
-     * @param format is the client target format.
-     * @param dataspace is the client target dataspace, as described in
-     *     setLayerDataspace.
-     * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
-     * @exception EX_UNSUPPORTED when the given configuration is not supported.
-     */
-    void getClientTargetSupport(long display, int width, int height,
-            android.hardware.graphics.common.PixelFormat format,
-            android.hardware.graphics.common.Dataspace dataspace);
-
-    /**
      * Returns the color modes supported on this display.
      *
      * All devices must support at least ColorMode::NATIVE.
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp
index a593e90..d59190d 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/translate-ndk.cpp
@@ -70,6 +70,9 @@
         static_cast<aidl::android::hardware::graphics::composer3::Capability>(
                 ::android::hardware::graphics::composer::V2_1::IComposer::Capability::
                         PRESENT_FENCE_IS_NOT_RELIABLE));
+// HWC2_CAPABILITY_SKIP_VALIDATE was never defined for HIDL, so we just hardcode its value
+static_assert(aidl::android::hardware::graphics::composer3::Capability::SKIP_VALIDATE ==
+              static_cast<aidl::android::hardware::graphics::composer3::Capability>(4));
 
 static_assert(aidl::android::hardware::graphics::composer3::LayerRequest::CLEAR_CLIENT_TARGET ==
               static_cast<aidl::android::hardware::graphics::composer3::LayerRequest>(
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
index d892681..40dfe06 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/vts/functional/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -13,17 +13,15 @@
 #undef LOG_TAG
 #define LOG_TAG "VtsHalGraphicsComposer3_TargetTest"
 
-typedef uint64_t DisplayId;
-
 namespace aidl::android::hardware::graphics::composer3::vts {
 namespace {
 
 class VtsDisplay {
   public:
-    VtsDisplay(DisplayId displayId, int32_t displayWidth, int32_t displayHeight)
+    VtsDisplay(uint64_t displayId, int32_t displayWidth, int32_t displayHeight)
         : mDisplayId(displayId), mDisplayWidth(displayWidth), mDisplayHeight(displayHeight) {}
 
-    DisplayId get() const { return mDisplayId; }
+    uint64_t get() const { return mDisplayId; }
 
     void setDimensions(int32_t displayWidth, int32_t displayHeight) {
         mDisplayWidth = displayWidth;
@@ -31,7 +29,7 @@
     }
 
   private:
-    const DisplayId mDisplayId;
+    const uint64_t mDisplayId;
     int32_t mDisplayWidth;
     int32_t mDisplayHeight;
 };
@@ -51,7 +49,7 @@
     // returns an invalid display id (one that has not been registered to a
     // display.  Currently assuming that a device will never have close to
     // std::numeric_limit<uint64_t>::max() displays registered while running tests
-    DisplayId GetInvalidDisplayId() {
+    uint64_t GetInvalidDisplayId() {
         uint64_t id = std::numeric_limits<uint64_t>::max();
         while (id > 0) {
             if (std::none_of(mDisplays.begin(), mDisplays.end(),
@@ -65,8 +63,8 @@
     }
 
     std::shared_ptr<IComposer> mComposer;
-    std::shared_ptr<IComposerClient> mComposerClient{};
-    DisplayId mInvalidDisplayId;
+    std::shared_ptr<IComposerClient> mComposerClient;
+    uint64_t mInvalidDisplayId;
     std::vector<VtsDisplay>
             mDisplays;  // TODO(b/202401906) populate all the displays available for test.
 };
@@ -74,15 +72,16 @@
 TEST_P(GraphicsComposerAidlTest, getDisplayCapabilitiesBadDisplay) {
     std::vector<DisplayCapability> capabilities;
     const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
+
+    EXPECT_FALSE(error.isOk());
     EXPECT_EQ(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
 }
 
 TEST_P(GraphicsComposerAidlTest, getDisplayCapabilities) {
     for (const auto& display : mDisplays) {
         std::vector<DisplayCapability> capabilities;
-        const auto error = mComposerClient->getDisplayCapabilities(display.get(), &capabilities);
 
-        EXPECT_NE(IComposerClient::EX_BAD_DISPLAY, error.getServiceSpecificError());
+        EXPECT_TRUE(mComposerClient->getDisplayCapabilities(display.get(), &capabilities).isOk());
     }
 }
 
diff --git a/graphics/composer/aidl/include/android/hardware/graphics/composer3/command-buffer.h b/graphics/composer/aidl/include/android/hardware/graphics/composer3/command-buffer.h
new file mode 100644
index 0000000..d02cf9c
--- /dev/null
+++ b/graphics/composer/aidl/include/android/hardware/graphics/composer3/command-buffer.h
@@ -0,0 +1,895 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <limits>
+#include <memory>
+#include <vector>
+
+#include <inttypes.h>
+#include <string.h>
+
+#include <aidl/android/hardware/graphics/composer3/BlendMode.h>
+#include <aidl/android/hardware/graphics/composer3/ClientTargetProperty.h>
+#include <aidl/android/hardware/graphics/composer3/Color.h>
+#include <aidl/android/hardware/graphics/composer3/Command.h>
+#include <aidl/android/hardware/graphics/composer3/Composition.h>
+#include <aidl/android/hardware/graphics/composer3/FloatColor.h>
+#include <aidl/android/hardware/graphics/composer3/HandleIndex.h>
+#include <aidl/android/hardware/graphics/composer3/IComposer.h>
+#include <aidl/android/hardware/graphics/composer3/IComposerClient.h>
+#include <aidl/android/hardware/graphics/composer3/PerFrameMetadata.h>
+#include <aidl/android/hardware/graphics/composer3/PerFrameMetadataBlob.h>
+
+#include <aidl/android/hardware/graphics/common/ColorTransform.h>
+#include <aidl/android/hardware/graphics/common/FRect.h>
+#include <aidl/android/hardware/graphics/common/Rect.h>
+#include <aidl/android/hardware/graphics/common/Transform.h>
+
+#include <fmq/AidlMessageQueue.h>
+#include <log/log.h>
+#include <sync/sync.h>
+
+#include <aidlcommonsupport/NativeHandle.h>
+
+using aidl::android::hardware::graphics::common::ColorTransform;
+using aidl::android::hardware::graphics::common::Dataspace;
+using aidl::android::hardware::graphics::common::FRect;
+using aidl::android::hardware::graphics::common::Rect;
+using aidl::android::hardware::graphics::common::Transform;
+
+using aidl::android::hardware::graphics::composer3::BlendMode;
+using aidl::android::hardware::graphics::composer3::ClientTargetProperty;
+using aidl::android::hardware::graphics::composer3::Color;
+using aidl::android::hardware::graphics::composer3::Command;
+using aidl::android::hardware::graphics::composer3::Composition;
+using aidl::android::hardware::graphics::composer3::FloatColor;
+using aidl::android::hardware::graphics::composer3::HandleIndex;
+using aidl::android::hardware::graphics::composer3::PerFrameMetadata;
+using aidl::android::hardware::graphics::composer3::PerFrameMetadataBlob;
+
+using aidl::android::hardware::common::NativeHandle;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using android::AidlMessageQueue;
+using CommandQueueType = AidlMessageQueue<int32_t, SynchronizedReadWrite>;
+using aidl::android::hardware::common::fmq::MQDescriptor;
+using DescriptorType = MQDescriptor<int32_t, SynchronizedReadWrite>;
+
+namespace aidl::android::hardware::graphics::composer3 {
+
+// This class helps build a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase {
+  public:
+    CommandWriterBase(uint32_t initialMaxSize) : mDataMaxSize(initialMaxSize) {
+        mData = std::make_unique<int32_t[]>(mDataMaxSize);
+        reset();
+    }
+
+    virtual ~CommandWriterBase() { reset(); }
+
+    void reset() {
+        mDataWritten = 0;
+        mCommandEnd = 0;
+
+        // handles in mDataHandles are owned by the caller
+        mDataHandles.clear();
+
+        // handles in mTemporaryHandles are owned by the writer
+        for (auto handle : mTemporaryHandles) {
+            native_handle_close(handle);
+            native_handle_delete(handle);
+        }
+        mTemporaryHandles.clear();
+    }
+
+    Command getCommand(uint32_t offset) {
+        uint32_t val = (offset < mDataWritten) ? mData[offset] : 0;
+        return static_cast<Command>(val & static_cast<uint32_t>(Command::OPCODE_MASK));
+    }
+
+    bool writeQueue(bool* outQueueChanged, int32_t* outCommandLength,
+                    std::vector<NativeHandle>* outCommandHandles) {
+        if (mDataWritten == 0) {
+            *outQueueChanged = false;
+            *outCommandLength = 0;
+            outCommandHandles->clear();
+            return true;
+        }
+
+        // After data are written to the queue, it may not be read by the
+        // remote reader when
+        //
+        //  - the writer does not send them (because of other errors)
+        //  - the hwbinder transaction fails
+        //  - the reader does not read them (because of other errors)
+        //
+        // Discard the stale data here.
+        size_t staleDataSize = mQueue ? mQueue->availableToRead() : 0;
+        if (staleDataSize > 0) {
+            ALOGW("discarding stale data from message queue");
+            CommandQueueType::MemTransaction tx;
+            if (mQueue->beginRead(staleDataSize, &tx)) {
+                mQueue->commitRead(staleDataSize);
+            }
+        }
+
+        // write data to queue, optionally resizing it
+        if (mQueue && (mDataMaxSize <= mQueue->getQuantumCount())) {
+            if (!mQueue->write(mData.get(), mDataWritten)) {
+                ALOGE("failed to write commands to message queue");
+                return false;
+            }
+
+            *outQueueChanged = false;
+        } else {
+            auto newQueue = std::make_unique<CommandQueueType>(mDataMaxSize);
+            if (!newQueue->isValid() || !newQueue->write(mData.get(), mDataWritten)) {
+                ALOGE("failed to prepare a new message queue ");
+                return false;
+            }
+
+            mQueue = std::move(newQueue);
+            *outQueueChanged = true;
+        }
+
+        *outCommandLength = mDataWritten;
+        *outCommandHandles = std::move(mDataHandles);
+
+        return true;
+    }
+
+    DescriptorType getMQDescriptor() const {
+        return (mQueue) ? mQueue->dupeDesc() : DescriptorType{};
+    }
+
+    static constexpr uint16_t kSelectDisplayLength = 2;
+    void selectDisplay(int64_t display) {
+        beginCommand(Command::SELECT_DISPLAY, kSelectDisplayLength);
+        write64(display);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSelectLayerLength = 2;
+    void selectLayer(int64_t layer) {
+        beginCommand(Command::SELECT_LAYER, kSelectLayerLength);
+        write64(layer);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetErrorLength = 2;
+    void setError(uint32_t location, int32_t error) {
+        beginCommand(Command::SET_ERROR, kSetErrorLength);
+        write(location);
+        writeSigned(error);
+        endCommand();
+    }
+
+    static constexpr uint32_t kPresentOrValidateDisplayResultLength = 1;
+    void setPresentOrValidateResult(uint32_t state) {
+        beginCommand(Command::SET_PRESENT_OR_VALIDATE_DISPLAY_RESULT,
+                     kPresentOrValidateDisplayResultLength);
+        write(state);
+        endCommand();
+    }
+
+    void setChangedCompositionTypes(const std::vector<int64_t>& layers,
+                                    const std::vector<Composition>& types) {
+        size_t totalLayers = std::min(layers.size(), types.size());
+        size_t currentLayer = 0;
+
+        while (currentLayer < totalLayers) {
+            size_t count =
+                    std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength) / 3);
+
+            beginCommand(Command::SET_CHANGED_COMPOSITION_TYPES, count * 3);
+            for (size_t i = 0; i < count; i++) {
+                write64(layers[currentLayer + i]);
+                writeSigned(static_cast<int32_t>(types[currentLayer + i]));
+            }
+            endCommand();
+
+            currentLayer += count;
+        }
+    }
+
+    void setDisplayRequests(uint32_t displayRequestMask, const std::vector<int64_t>& layers,
+                            const std::vector<uint32_t>& layerRequestMasks) {
+        size_t totalLayers = std::min(layers.size(), layerRequestMasks.size());
+        size_t currentLayer = 0;
+
+        while (currentLayer < totalLayers) {
+            size_t count =
+                    std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength - 1) / 3);
+
+            beginCommand(Command::SET_DISPLAY_REQUESTS, 1 + count * 3);
+            write(displayRequestMask);
+            for (size_t i = 0; i < count; i++) {
+                write64(layers[currentLayer + i]);
+                write(static_cast<int32_t>(layerRequestMasks[currentLayer + i]));
+            }
+            endCommand();
+
+            currentLayer += count;
+        }
+    }
+
+    static constexpr uint16_t kSetPresentFenceLength = 1;
+    void setPresentFence(int presentFence) {
+        beginCommand(Command::SET_PRESENT_FENCE, kSetPresentFenceLength);
+        writeFence(presentFence);
+        endCommand();
+    }
+
+    void setReleaseFences(const std::vector<int64_t>& layers,
+                          const std::vector<int>& releaseFences) {
+        size_t totalLayers = std::min(layers.size(), releaseFences.size());
+        size_t currentLayer = 0;
+
+        while (currentLayer < totalLayers) {
+            size_t count =
+                    std::min(totalLayers - currentLayer, static_cast<size_t>(kMaxLength) / 3);
+
+            beginCommand(Command::SET_RELEASE_FENCES, count * 3);
+            for (size_t i = 0; i < count; i++) {
+                write64(layers[currentLayer + i]);
+                writeFence(releaseFences[currentLayer + i]);
+            }
+            endCommand();
+
+            currentLayer += count;
+        }
+    }
+
+    static constexpr uint16_t kSetColorTransformLength = 17;
+    void setColorTransform(const float* matrix, ColorTransform hint) {
+        beginCommand(Command::SET_COLOR_TRANSFORM, kSetColorTransformLength);
+        for (int i = 0; i < 16; i++) {
+            writeFloat(matrix[i]);
+        }
+        writeSigned(static_cast<int32_t>(hint));
+        endCommand();
+    }
+
+    void setClientTarget(uint32_t slot, const native_handle_t* target, int acquireFence,
+                         Dataspace dataspace, const std::vector<Rect>& damage) {
+        setClientTargetInternal(slot, target, acquireFence, static_cast<int32_t>(dataspace),
+                                damage);
+    }
+
+    static constexpr uint16_t kSetOutputBufferLength = 3;
+    void setOutputBuffer(uint32_t slot, const native_handle_t* buffer, int releaseFence) {
+        beginCommand(Command::SET_OUTPUT_BUFFER, kSetOutputBufferLength);
+        write(slot);
+        writeHandle(buffer, true);
+        writeFence(releaseFence);
+        endCommand();
+    }
+
+    static constexpr uint16_t kValidateDisplayLength = 0;
+    void validateDisplay() {
+        beginCommand(Command::VALIDATE_DISPLAY, kValidateDisplayLength);
+        endCommand();
+    }
+
+    static constexpr uint16_t kPresentOrValidateDisplayLength = 0;
+    void presentOrvalidateDisplay() {
+        beginCommand(Command::PRESENT_OR_VALIDATE_DISPLAY, kPresentOrValidateDisplayLength);
+        endCommand();
+    }
+
+    static constexpr uint16_t kAcceptDisplayChangesLength = 0;
+    void acceptDisplayChanges() {
+        beginCommand(Command::ACCEPT_DISPLAY_CHANGES, kAcceptDisplayChangesLength);
+        endCommand();
+    }
+
+    static constexpr uint16_t kPresentDisplayLength = 0;
+    void presentDisplay() {
+        beginCommand(Command::PRESENT_DISPLAY, kPresentDisplayLength);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerCursorPositionLength = 2;
+    void setLayerCursorPosition(int32_t x, int32_t y) {
+        beginCommand(Command::SET_LAYER_CURSOR_POSITION, kSetLayerCursorPositionLength);
+        writeSigned(x);
+        writeSigned(y);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerBufferLength = 3;
+    void setLayerBuffer(uint32_t slot, const native_handle_t* buffer, int acquireFence) {
+        beginCommand(Command::SET_LAYER_BUFFER, kSetLayerBufferLength);
+        write(slot);
+        writeHandle(buffer, true);
+        writeFence(acquireFence);
+        endCommand();
+    }
+
+    void setLayerSurfaceDamage(const std::vector<Rect>& damage) {
+        bool doWrite = (damage.size() <= kMaxLength / 4);
+        size_t length = (doWrite) ? damage.size() * 4 : 0;
+
+        beginCommand(Command::SET_LAYER_SURFACE_DAMAGE, length);
+        // When there are too many rectangles in the damage region and doWrite
+        // is false, we write no rectangle at all which means the entire
+        // layer is damaged.
+        if (doWrite) {
+            writeRegion(damage);
+        }
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerBlendModeLength = 1;
+    void setLayerBlendMode(BlendMode mode) {
+        beginCommand(Command::SET_LAYER_BLEND_MODE, kSetLayerBlendModeLength);
+        writeSigned(static_cast<int32_t>(mode));
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerColorLength = 1;
+    void setLayerColor(Color color) {
+        beginCommand(Command::SET_LAYER_COLOR, kSetLayerColorLength);
+        writeColor(color);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerCompositionTypeLength = 1;
+    void setLayerCompositionType(Composition type) {
+        beginCommand(Command::SET_LAYER_COMPOSITION_TYPE, kSetLayerCompositionTypeLength);
+        writeSigned(static_cast<int32_t>(type));
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerDataspaceLength = 1;
+    void setLayerDataspace(Dataspace dataspace) {
+        setLayerDataspaceInternal(static_cast<int32_t>(dataspace));
+    }
+
+    static constexpr uint16_t kSetLayerDisplayFrameLength = 4;
+    void setLayerDisplayFrame(const Rect& frame) {
+        beginCommand(Command::SET_LAYER_DISPLAY_FRAME, kSetLayerDisplayFrameLength);
+        writeRect(frame);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerPlaneAlphaLength = 1;
+    void setLayerPlaneAlpha(float alpha) {
+        beginCommand(Command::SET_LAYER_PLANE_ALPHA, kSetLayerPlaneAlphaLength);
+        writeFloat(alpha);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerSidebandStreamLength = 1;
+    void setLayerSidebandStream(const native_handle_t* stream) {
+        beginCommand(Command::SET_LAYER_SIDEBAND_STREAM, kSetLayerSidebandStreamLength);
+        writeHandle(stream);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerSourceCropLength = 4;
+    void setLayerSourceCrop(const FRect& crop) {
+        beginCommand(Command::SET_LAYER_SOURCE_CROP, kSetLayerSourceCropLength);
+        writeFRect(crop);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerTransformLength = 1;
+    void setLayerTransform(Transform transform) {
+        beginCommand(Command::SET_LAYER_TRANSFORM, kSetLayerTransformLength);
+        writeSigned(static_cast<int32_t>(transform));
+        endCommand();
+    }
+
+    void setLayerVisibleRegion(const std::vector<Rect>& visible) {
+        bool doWrite = (visible.size() <= kMaxLength / 4);
+        size_t length = (doWrite) ? visible.size() * 4 : 0;
+
+        beginCommand(Command::SET_LAYER_VISIBLE_REGION, length);
+        // When there are too many rectangles in the visible region and
+        // doWrite is false, we write no rectangle at all which means the
+        // entire layer is visible.
+        if (doWrite) {
+            writeRegion(visible);
+        }
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerZOrderLength = 1;
+    void setLayerZOrder(uint32_t z) {
+        beginCommand(Command::SET_LAYER_Z_ORDER, kSetLayerZOrderLength);
+        write(z);
+        endCommand();
+    }
+
+    void setLayerPerFrameMetadata(const std::vector<PerFrameMetadata>& metadataVec) {
+        beginCommand(Command::SET_LAYER_PER_FRAME_METADATA, metadataVec.size() * 2);
+        for (const auto& metadata : metadataVec) {
+            writeSigned(static_cast<int32_t>(metadata.key));
+            writeFloat(metadata.value);
+        }
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerColorTransformLength = 16;
+    void setLayerColorTransform(const float* matrix) {
+        beginCommand(Command::SET_LAYER_COLOR_TRANSFORM, kSetLayerColorTransformLength);
+        for (int i = 0; i < 16; i++) {
+            writeFloat(matrix[i]);
+        }
+        endCommand();
+    }
+
+    void setLayerPerFrameMetadataBlobs(const std::vector<PerFrameMetadataBlob>& metadata) {
+        // in units of uint32_t's
+        size_t commandLength = 0;
+
+        if (metadata.size() > std::numeric_limits<uint32_t>::max()) {
+            LOG_FATAL("too many metadata blobs - dynamic metadata size is too large");
+            return;
+        }
+
+        // space for numElements
+        commandLength += 1;
+
+        for (auto metadataBlob : metadata) {
+            commandLength += 1;  // key of metadata blob
+            commandLength += 1;  // size information of metadata blob
+
+            // metadata content size
+            size_t metadataSize = metadataBlob.blob.size() / sizeof(uint32_t);
+            commandLength += metadataSize;
+            commandLength +=
+                    (metadataBlob.blob.size() - (metadataSize * sizeof(uint32_t)) > 0) ? 1 : 0;
+        }
+
+        if (commandLength > std::numeric_limits<uint16_t>::max()) {
+            LOG_FATAL("dynamic metadata size is too large");
+            return;
+        }
+
+        // Blobs are written as:
+        // {numElements, key1, size1, blob1, key2, size2, blob2, key3, size3...}
+        uint16_t length = static_cast<uint16_t>(commandLength);
+        beginCommand(Command::SET_LAYER_PER_FRAME_METADATA_BLOBS, length);
+        write(static_cast<uint32_t>(metadata.size()));
+        for (auto metadataBlob : metadata) {
+            writeSigned(static_cast<int32_t>(metadataBlob.key));
+            write(static_cast<uint32_t>(metadataBlob.blob.size()));
+            writeBlob(static_cast<uint32_t>(metadataBlob.blob.size()), metadataBlob.blob.data());
+        }
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetLayerFloatColorLength = 4;
+    void setLayerFloatColor(FloatColor color) {
+        beginCommand(Command::SET_LAYER_FLOAT_COLOR, kSetLayerFloatColorLength);
+        writeFloatColor(color);
+        endCommand();
+    }
+
+    static constexpr uint16_t kSetClientTargetPropertyLength = 2;
+    void setClientTargetProperty(const ClientTargetProperty& clientTargetProperty) {
+        beginCommand(Command::SET_CLIENT_TARGET_PROPERTY, kSetClientTargetPropertyLength);
+        writeSigned(static_cast<int32_t>(clientTargetProperty.pixelFormat));
+        writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
+        endCommand();
+    }
+
+    void setLayerGenericMetadata(const std::string& key, const bool mandatory,
+                                 const std::vector<uint8_t>& value) {
+        const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size());
+        if (commandSize > std::numeric_limits<uint16_t>::max()) {
+            LOG_FATAL("Too much generic metadata (%zu elements)", commandSize);
+            return;
+        }
+
+        beginCommand(Command::SET_LAYER_GENERIC_METADATA, static_cast<uint16_t>(commandSize));
+        write(key.size());
+        writeBlob(key.size(), reinterpret_cast<const unsigned char*>(key.c_str()));
+        write(mandatory);
+        write(value.size());
+        writeBlob(value.size(), value.data());
+        endCommand();
+    }
+
+  protected:
+    template <typename T>
+    void beginCommand(T command, uint16_t length) {
+        beginCommandBase(static_cast<Command>(command), length);
+    }
+
+    void setClientTargetInternal(uint32_t slot, const native_handle_t* target, int acquireFence,
+                                 int32_t dataspace, const std::vector<Rect>& damage) {
+        bool doWrite = (damage.size() <= (kMaxLength - 4) / 4);
+        size_t length = 4 + ((doWrite) ? damage.size() * 4 : 0);
+
+        beginCommand(Command::SET_CLIENT_TARGET, length);
+        write(slot);
+        writeHandle(target, true);
+        writeFence(acquireFence);
+        writeSigned(dataspace);
+        // When there are too many rectangles in the damage region and doWrite
+        // is false, we write no rectangle at all which means the entire
+        // client target is damaged.
+        if (doWrite) {
+            writeRegion(damage);
+        }
+        endCommand();
+    }
+
+    void setLayerDataspaceInternal(int32_t dataspace) {
+        beginCommand(Command::SET_LAYER_DATASPACE, kSetLayerDataspaceLength);
+        writeSigned(dataspace);
+        endCommand();
+    }
+
+    void beginCommandBase(Command command, uint16_t length) {
+        if (mCommandEnd) {
+            LOG_FATAL("endCommand was not called before command 0x%x", command);
+        }
+
+        growData(1 + length);
+        write(static_cast<uint32_t>(command) | length);
+
+        mCommandEnd = mDataWritten + length;
+    }
+
+    void endCommand() {
+        if (!mCommandEnd) {
+            LOG_FATAL("beginCommand was not called");
+        } else if (mDataWritten > mCommandEnd) {
+            LOG_FATAL("too much data written");
+            mDataWritten = mCommandEnd;
+        } else if (mDataWritten < mCommandEnd) {
+            LOG_FATAL("too little data written");
+            while (mDataWritten < mCommandEnd) {
+                write(0);
+            }
+        }
+
+        mCommandEnd = 0;
+    }
+
+    void write(uint32_t val) { mData[mDataWritten++] = val; }
+
+    void writeSigned(int32_t val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); }
+
+    void writeFloat(float val) { memcpy(&mData[mDataWritten++], &val, sizeof(val)); }
+
+    void write64(uint64_t val) {
+        uint32_t lo = static_cast<uint32_t>(val & 0xffffffff);
+        uint32_t hi = static_cast<uint32_t>(val >> 32);
+        write(lo);
+        write(hi);
+    }
+
+    void writeRect(const Rect& rect) {
+        writeSigned(rect.left);
+        writeSigned(rect.top);
+        writeSigned(rect.right);
+        writeSigned(rect.bottom);
+    }
+
+    void writeRegion(const std::vector<Rect>& region) {
+        for (const auto& rect : region) {
+            writeRect(rect);
+        }
+    }
+
+    void writeFRect(const FRect& rect) {
+        writeFloat(rect.left);
+        writeFloat(rect.top);
+        writeFloat(rect.right);
+        writeFloat(rect.bottom);
+    }
+
+    void writeColor(const Color& color) {
+        write((color.r << 0) | (color.g << 8) | (color.b << 16) | (color.a << 24));
+    }
+
+    void writeFloatColor(const FloatColor& color) {
+        writeFloat(color.r);
+        writeFloat(color.g);
+        writeFloat(color.b);
+        writeFloat(color.a);
+    }
+
+    void writeBlob(uint32_t length, const unsigned char* blob) {
+        memcpy(&mData[mDataWritten], blob, length);
+        uint32_t numElements = length / 4;
+        mDataWritten += numElements;
+        mDataWritten += (length - (numElements * 4) > 0) ? 1 : 0;
+    }
+
+    // ownership of handle is not transferred
+    void writeHandle(const native_handle_t* handle, bool useCache) {
+        if (!handle) {
+            writeSigned(
+                    static_cast<int32_t>((useCache) ? HandleIndex::CACHED : HandleIndex::EMPTY));
+            return;
+        }
+
+        mDataHandles.push_back(::android::dupToAidl(handle));
+        writeSigned(mDataHandles.size() - 1);
+    }
+
+    void writeHandle(const native_handle_t* handle) { writeHandle(handle, false); }
+
+    // ownership of fence is transferred
+    void writeFence(int fence) {
+        native_handle_t* handle = nullptr;
+        if (fence >= 0) {
+            handle = getTemporaryHandle(1, 0);
+            if (handle) {
+                handle->data[0] = fence;
+            } else {
+                ALOGW("failed to get temporary handle for fence %d", fence);
+                sync_wait(fence, -1);
+                close(fence);
+            }
+        }
+
+        writeHandle(handle);
+    }
+
+    native_handle_t* getTemporaryHandle(int numFds, int numInts) {
+        native_handle_t* handle = native_handle_create(numFds, numInts);
+        if (handle) {
+            mTemporaryHandles.push_back(handle);
+        }
+        return handle;
+    }
+
+    static constexpr uint16_t kMaxLength = std::numeric_limits<uint16_t>::max();
+
+    std::unique_ptr<int32_t[]> mData;
+    uint32_t mDataWritten;
+
+  private:
+    void growData(uint32_t grow) {
+        uint32_t newWritten = mDataWritten + grow;
+        if (newWritten < mDataWritten) {
+            LOG_ALWAYS_FATAL("buffer overflowed; data written %" PRIu32 ", growing by %" PRIu32,
+                             mDataWritten, grow);
+        }
+
+        if (newWritten <= mDataMaxSize) {
+            return;
+        }
+
+        uint32_t newMaxSize = mDataMaxSize << 1;
+        if (newMaxSize < newWritten) {
+            newMaxSize = newWritten;
+        }
+
+        auto newData = std::make_unique<int32_t[]>(newMaxSize);
+        std::copy_n(mData.get(), mDataWritten, newData.get());
+        mDataMaxSize = newMaxSize;
+        mData = std::move(newData);
+    }
+
+    uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; }
+
+    uint32_t mDataMaxSize;
+    // end offset of the current command
+    uint32_t mCommandEnd;
+
+    std::vector<NativeHandle> mDataHandles;
+    std::vector<native_handle_t*> mTemporaryHandles;
+
+    std::unique_ptr<CommandQueueType> mQueue;
+};
+
+// This class helps parse a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase {
+  public:
+    CommandReaderBase() : mDataMaxSize(0) { reset(); }
+
+    bool setMQDescriptor(const DescriptorType& descriptor) {
+        mQueue = std::make_unique<CommandQueueType>(descriptor, false);
+        if (mQueue->isValid()) {
+            return true;
+        } else {
+            mQueue = nullptr;
+            return false;
+        }
+    }
+
+    bool readQueue(int32_t commandLength, std::vector<NativeHandle> commandHandles) {
+        if (!mQueue) {
+            return false;
+        }
+
+        auto quantumCount = mQueue->getQuantumCount();
+        if (mDataMaxSize < quantumCount) {
+            mDataMaxSize = quantumCount;
+            mData = std::make_unique<int32_t[]>(mDataMaxSize);
+        }
+
+        if (commandLength > mDataMaxSize || !mQueue->read(mData.get(), commandLength)) {
+            ALOGE("failed to read commands from message queue");
+            return false;
+        }
+
+        mDataSize = commandLength;
+        mDataRead = 0;
+        mCommandBegin = 0;
+        mCommandEnd = 0;
+        mDataHandles = std::move(commandHandles);
+        return true;
+    }
+
+    void reset() {
+        mDataSize = 0;
+        mDataRead = 0;
+        mCommandBegin = 0;
+        mCommandEnd = 0;
+        mDataHandles.clear();
+    }
+
+  protected:
+    template <typename T>
+    bool beginCommand(T* outCommand, uint16_t* outLength) {
+        return beginCommandBase(reinterpret_cast<Command*>(outCommand), outLength);
+    }
+
+    bool isEmpty() const { return (mDataRead >= mDataSize); }
+
+    bool beginCommandBase(Command* outCommand, uint16_t* outLength) {
+        if (mCommandEnd) {
+            LOG_FATAL("endCommand was not called for last command");
+        }
+
+        constexpr uint32_t opcode_mask = static_cast<uint32_t>(Command::OPCODE_MASK);
+        constexpr uint32_t length_mask = static_cast<uint32_t>(Command::LENGTH_MASK);
+
+        uint32_t val = read();
+        *outCommand = static_cast<Command>(val & opcode_mask);
+        *outLength = static_cast<uint16_t>(val & length_mask);
+
+        if (mDataRead + *outLength > mDataSize) {
+            ALOGE("command 0x%x has invalid command length %" PRIu16, *outCommand, *outLength);
+            // undo the read() above
+            mDataRead--;
+            return false;
+        }
+
+        mCommandEnd = mDataRead + *outLength;
+
+        return true;
+    }
+
+    void endCommand() {
+        if (!mCommandEnd) {
+            LOG_FATAL("beginCommand was not called");
+        } else if (mDataRead > mCommandEnd) {
+            LOG_FATAL("too much data read");
+            mDataRead = mCommandEnd;
+        } else if (mDataRead < mCommandEnd) {
+            LOG_FATAL("too little data read");
+            mDataRead = mCommandEnd;
+        }
+
+        mCommandBegin = mCommandEnd;
+        mCommandEnd = 0;
+    }
+
+    uint32_t getCommandLoc() const { return mCommandBegin; }
+
+    uint32_t read() { return mData[mDataRead++]; }
+
+    int32_t readSigned() {
+        int32_t val;
+        memcpy(&val, &mData[mDataRead++], sizeof(val));
+        return val;
+    }
+
+    float readFloat() {
+        float val;
+        memcpy(&val, &mData[mDataRead++], sizeof(val));
+        return val;
+    }
+
+    uint64_t read64() {
+        uint32_t lo = read();
+        uint32_t hi = read();
+        return (static_cast<uint64_t>(hi) << 32) | lo;
+    }
+
+    Color readColor() {
+        uint32_t val = read();
+        return Color{
+                static_cast<int8_t>((val >> 0) & 0xff),
+                static_cast<int8_t>((val >> 8) & 0xff),
+                static_cast<int8_t>((val >> 16) & 0xff),
+                static_cast<int8_t>((val >> 24) & 0xff),
+        };
+    }
+
+    // ownership of handle is not transferred
+    const native_handle_t* readHandle(bool* outUseCache) {
+        const native_handle_t* handle = nullptr;
+
+        int32_t index = readSigned();
+        switch (index) {
+            case static_cast<int32_t>(HandleIndex::EMPTY):
+                *outUseCache = false;
+                break;
+            case static_cast<int32_t>(HandleIndex::CACHED):
+                *outUseCache = true;
+                break;
+            default:
+                if (static_cast<size_t>(index) < mDataHandles.size()) {
+                    handle = ::android::makeFromAidl(mDataHandles[index]);
+                } else {
+                    ALOGE("invalid handle index %zu", static_cast<size_t>(index));
+                }
+                *outUseCache = false;
+                break;
+        }
+
+        return handle;
+    }
+
+    const native_handle_t* readHandle() {
+        bool useCache;
+        return readHandle(&useCache);
+    }
+
+    // ownership of fence is transferred
+    int readFence() {
+        auto handle = readHandle();
+        if (!handle || handle->numFds == 0) {
+            return -1;
+        }
+
+        if (handle->numFds != 1) {
+            ALOGE("invalid fence handle with %d fds", handle->numFds);
+            return -1;
+        }
+
+        int fd = dup(handle->data[0]);
+        if (fd < 0) {
+            ALOGW("failed to dup fence %d", handle->data[0]);
+            sync_wait(handle->data[0], -1);
+            fd = -1;
+        }
+
+        return fd;
+    }
+
+    std::unique_ptr<int32_t[]> mData;
+    uint32_t mDataRead;
+
+  private:
+    std::unique_ptr<CommandQueueType> mQueue;
+    uint32_t mDataMaxSize;
+
+    uint32_t mDataSize;
+
+    // begin/end offsets of the current command
+    uint32_t mCommandBegin;
+    uint32_t mCommandEnd;
+
+    std::vector<NativeHandle> mDataHandles;
+};
+
+}  // namespace aidl::android::hardware::graphics::composer3
diff --git a/graphics/mapper/2.0/vts/OWNERS b/graphics/mapper/2.0/vts/OWNERS
index 4177296..62e3f2a 100644
--- a/graphics/mapper/2.0/vts/OWNERS
+++ b/graphics/mapper/2.0/vts/OWNERS
@@ -1,8 +1,5 @@
-# Graphics team
+# Bug component: 25423
 chrisforbes@google.com
 jreck@google.com
 lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+sumir@google.com
diff --git a/graphics/mapper/2.0/vts/functional/OWNERS b/graphics/mapper/2.0/vts/functional/OWNERS
deleted file mode 100644
index a2ed8c8..0000000
--- a/graphics/mapper/2.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-sumir@google.com
diff --git a/graphics/mapper/2.1/vts/OWNERS b/graphics/mapper/2.1/vts/OWNERS
index 4177296..43c018a 100644
--- a/graphics/mapper/2.1/vts/OWNERS
+++ b/graphics/mapper/2.1/vts/OWNERS
@@ -1,8 +1,2 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
-
-# VTS team
-yim@google.com
-zhuoyao@google.com
+# Bug component: 25423
+include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/2.1/vts/functional/OWNERS b/graphics/mapper/2.1/vts/functional/OWNERS
deleted file mode 100644
index a2ed8c8..0000000
--- a/graphics/mapper/2.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 25423
-sumir@google.com
diff --git a/graphics/mapper/3.0/vts/OWNERS b/graphics/mapper/3.0/vts/OWNERS
index c9f24d0..43c018a 100644
--- a/graphics/mapper/3.0/vts/OWNERS
+++ b/graphics/mapper/3.0/vts/OWNERS
@@ -1,4 +1,2 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
+# Bug component: 25423
+include ../../2.0/vts/OWNERS
diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS
index c9f24d0..43c018a 100644
--- a/graphics/mapper/4.0/vts/OWNERS
+++ b/graphics/mapper/4.0/vts/OWNERS
@@ -1,4 +1,2 @@
-# Graphics team
-chrisforbes@google.com
-jreck@google.com
-lpy@google.com
+# Bug component: 25423
+include ../../2.0/vts/OWNERS
diff --git a/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp b/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
index 9e1cc70..3c353e6 100644
--- a/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
+++ b/health/2.0/utils/libhealthhalutils/HealthHalUtils.cpp
@@ -25,7 +25,26 @@
 namespace V2_0 {
 
 sp<IHealth> get_health_service() {
-    for (auto&& instanceName : {"default", "backup"}) {
+    // For the core and vendor variant, the "backup" instance points to healthd,
+    // which is removed.
+    // For the recovery variant, the "backup" instance has a different
+    // meaning. It points to android.hardware.health@2.0-impl-default.recovery
+    // which was assumed by OEMs to be always installed when a
+    // vendor-specific libhealthd is not necessary. Hence, its behavior
+    // is kept. See health/2.0/README.md.
+    // android.hardware.health@2.0-impl-default.recovery, and subsequently the
+    // special handling of recovery mode below, can be removed once health@2.1
+    // is the minimum required version (i.e. compatibility matrix level 5 is the
+    // minimum supported level). Health 2.1 requires OEMs to install the
+    // implementation to the recovery partition when it is necessary (i.e. on
+    // non-A/B devices, where IsBatteryOk() is needed in recovery).
+    for (auto&& instanceName :
+#ifdef __ANDROID_RECOVERY__
+         { "default", "backup" }
+#else
+         {"default"}
+#endif
+    ) {
         auto ret = IHealth::getService(instanceName);
         if (ret != nullptr) {
             return ret;
diff --git a/health/aidl/OWNERS b/health/aidl/OWNERS
new file mode 100644
index 0000000..cd06415
--- /dev/null
+++ b/health/aidl/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 30545
+elsk@google.com
diff --git a/neuralnetworks/1.0/utils/Android.bp b/neuralnetworks/1.0/utils/Android.bp
index 8c51c67..71a190e 100644
--- a/neuralnetworks/1.0/utils/Android.bp
+++ b/neuralnetworks/1.0/utils/Android.bp
@@ -49,7 +49,7 @@
     static_libs: [
         "android.hardware.neuralnetworks@1.0",
         "libgmock",
-        "libneuralnetworks_common",
+        "libneuralnetworks_common_hidl",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
         "neuralnetworks_utils_hal_1_0",
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
index 1baabdf..360b338 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h
@@ -50,8 +50,8 @@
 }
 
 template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
-    const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(nn::validate(canonical));
     if (version > kVersion) {
         return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
     }
diff --git a/neuralnetworks/1.0/utils/src/PreparedModel.cpp b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
index 00970c0..3060c65 100644
--- a/neuralnetworks/1.0/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.0/utils/src/PreparedModel.cpp
@@ -63,12 +63,11 @@
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
-    const nn::Request& requestInShared =
-            NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
-                    &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
-                    &maybeRequestInShared, &relocation)));
+    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+            &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
+            &maybeRequestInShared, &relocation));
 
-    const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
+    const auto hidlRequest = NN_TRY(convert(requestInShared));
 
     return executeInternal(hidlRequest, relocation);
 }
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index b33c581..ae9ff0a 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -50,7 +50,7 @@
         "libgmock",
         "libhidlmemory",
         "libneuralnetworks_generated_test_harness",
-        "libneuralnetworks_utils",
+        "libneuralnetworks_common_hidl",
     ],
     header_libs: [
         "libneuralnetworks_headers",
@@ -81,7 +81,7 @@
         "libgmock",
         "libhidlmemory",
         "libneuralnetworks_generated_test_harness",
-        "libneuralnetworks_utils",
+        "libneuralnetworks_common_hidl",
     ],
     whole_static_libs: [
         "neuralnetworks_generated_V1_0_example",
diff --git a/neuralnetworks/1.1/utils/Android.bp b/neuralnetworks/1.1/utils/Android.bp
index 737ff58..478a742 100644
--- a/neuralnetworks/1.1/utils/Android.bp
+++ b/neuralnetworks/1.1/utils/Android.bp
@@ -52,7 +52,7 @@
         "android.hardware.neuralnetworks@1.0",
         "android.hardware.neuralnetworks@1.1",
         "libgmock",
-        "libneuralnetworks_common",
+        "libneuralnetworks_common_hidl",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
         "neuralnetworks_utils_hal_1_0",
diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
index a8cf8cf..09d9fe8 100644
--- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
+++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h
@@ -52,8 +52,8 @@
 }
 
 template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
-    const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(nn::validate(canonical));
     if (version > kVersion) {
         return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
     }
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index c001112..4c57788 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -48,7 +48,7 @@
         "libgmock",
         "libhidlmemory",
         "libneuralnetworks_generated_test_harness",
-        "libneuralnetworks_utils",
+        "libneuralnetworks_common_hidl",
     ],
     whole_static_libs: [
         "neuralnetworks_generated_V1_0_example",
diff --git a/neuralnetworks/1.2/utils/Android.bp b/neuralnetworks/1.2/utils/Android.bp
index 4eefb0f..2a86a00 100644
--- a/neuralnetworks/1.2/utils/Android.bp
+++ b/neuralnetworks/1.2/utils/Android.bp
@@ -71,7 +71,7 @@
         "android.hardware.neuralnetworks@1.1",
         "android.hardware.neuralnetworks@1.2",
         "libgmock",
-        "libneuralnetworks_common",
+        "libneuralnetworks_common_hidl",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
         "neuralnetworks_utils_hal_1_0",
diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
index 09691b6..5c3b8a7 100644
--- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
+++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h
@@ -61,8 +61,8 @@
 }
 
 template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
-    const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(nn::validate(canonical));
     if (version > kVersion) {
         return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
     }
diff --git a/neuralnetworks/1.2/utils/src/Callbacks.cpp b/neuralnetworks/1.2/utils/src/Callbacks.cpp
index 9f54bb1..01b5e12 100644
--- a/neuralnetworks/1.2/utils/src/Callbacks.cpp
+++ b/neuralnetworks/1.2/utils/src/Callbacks.cpp
@@ -75,8 +75,7 @@
                << "execution failed with " << toString(status);
     }
     HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
-    return hal::utils::makeExecutionFailure(
-            convertExecutionGeneralResultsHelper(outputShapes, timing));
+    return convertExecutionGeneralResultsHelper(outputShapes, timing);
 }
 
 Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp
index 29945b7..6a80b42 100644
--- a/neuralnetworks/1.2/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.2/utils/src/Conversions.cpp
@@ -120,9 +120,8 @@
             NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor));
     auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
 
-    auto table = NN_TRY(hal::utils::makeGeneralFailure(
-            Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
-            nn::ErrorStatus::GENERAL_FAILURE));
+    auto table =
+            NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
 
     return Capabilities{
             .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16PerformanceScalar,
diff --git a/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp b/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp
index b4b6f68..2746965 100644
--- a/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp
+++ b/neuralnetworks/1.2/utils/src/ExecutionBurstController.cpp
@@ -176,7 +176,10 @@
         std::lock_guard guard(mMutex);
         const int32_t slot = mMemoryIdToSlot.at(memory);
         if (mBurstContext) {
-            mBurstContext->freeMemory(slot);
+            const auto ret = mBurstContext->freeMemory(slot);
+            if (!ret.isOk()) {
+                LOG(ERROR) << "IBustContext::freeMemory failed: " << ret.description();
+            }
         }
         mMemoryIdToSlot.erase(memory);
         mMemoryCache[slot] = {};
@@ -317,8 +320,7 @@
 
     // if the request is valid but of a higher version than what's supported in burst execution,
     // fall back to another execution path
-    if (const auto version = NN_TRY(hal::utils::makeExecutionFailure(nn::validate(request)));
-        version > nn::Version::ANDROID_Q) {
+    if (const auto version = NN_TRY(nn::validate(request)); version > nn::Version::ANDROID_Q) {
         // fallback to another execution path if the packet could not be sent
         return kPreparedModel->execute(request, measure, deadline, loopTimeoutDuration);
     }
@@ -326,17 +328,15 @@
     // ensure that request is ready for IPC
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
-    const nn::Request& requestInShared =
-            NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
-                    &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
-                    &maybeRequestInShared, &relocation)));
+    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+            &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
+            &maybeRequestInShared, &relocation));
 
     // clear pools field of request, as they will be provided via slots
     const auto requestWithoutPools = nn::Request{
             .inputs = requestInShared.inputs, .outputs = requestInShared.outputs, .pools = {}};
-    auto hidlRequest = NN_TRY(
-            hal::utils::makeExecutionFailure(V1_0::utils::unvalidatedConvert(requestWithoutPools)));
-    const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
+    auto hidlRequest = NN_TRY(V1_0::utils::unvalidatedConvert(requestWithoutPools));
+    const auto hidlMeasure = NN_TRY(convert(measure));
 
     std::vector<int32_t> slots;
     std::vector<OptionalCacheHold> holds;
@@ -364,8 +364,7 @@
 
     // if the request is valid but of a higher version than what's supported in burst execution,
     // fall back to another execution path
-    if (const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(request)));
-        version > nn::Version::ANDROID_Q) {
+    if (const auto version = NN_TRY(nn::validate(request)); version > nn::Version::ANDROID_Q) {
         // fallback to another execution path if the packet could not be sent
         return kPreparedModel->createReusableExecution(request, measure, loopTimeoutDuration);
     }
@@ -427,8 +426,7 @@
     }
 
     // get result packet
-    const auto [status, outputShapes, timing] =
-            NN_TRY(hal::utils::makeExecutionFailure(mResultChannelReceiver->getBlocking()));
+    const auto [status, outputShapes, timing] = NN_TRY(mResultChannelReceiver->getBlocking());
 
     if (relocation.output) {
         relocation.output->flush();
diff --git a/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp b/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp
index c67159e..65ec7f5 100644
--- a/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp
+++ b/neuralnetworks/1.2/utils/src/ExecutionBurstServer.cpp
@@ -45,8 +45,6 @@
 namespace android::hardware::neuralnetworks::V1_2::utils {
 namespace {
 
-using neuralnetworks::utils::makeExecutionFailure;
-
 constexpr V1_2::Timing kNoTiming = {std::numeric_limits<uint64_t>::max(),
                                     std::numeric_limits<uint64_t>::max()};
 
@@ -241,28 +239,25 @@
                  "ExecutionBurstServer getting memory, executing, and returning results");
 
     // ensure executor with cache has required memory
-    const auto cacheEntries =
-            NN_TRY(makeExecutionFailure(mMemoryCache.getCacheEntries(slotsOfPools)));
+    const auto cacheEntries = NN_TRY(mMemoryCache.getCacheEntries(slotsOfPools));
 
     // convert request, populating its pools
     // This code performs an unvalidated convert because the request object without its pools is
     // invalid because it is incomplete. Instead, the validation is performed after the memory pools
     // have been added to the request.
-    auto canonicalRequest =
-            NN_TRY(makeExecutionFailure(nn::unvalidatedConvert(requestWithoutPools)));
+    auto canonicalRequest = NN_TRY(nn::unvalidatedConvert(requestWithoutPools));
     CHECK(canonicalRequest.pools.empty());
     std::transform(cacheEntries.begin(), cacheEntries.end(),
                    std::back_inserter(canonicalRequest.pools),
                    [](const auto& cacheEntry) { return cacheEntry.first; });
-    NN_TRY(makeExecutionFailure(validate(canonicalRequest)));
+    NN_TRY(validate(canonicalRequest));
 
-    nn::MeasureTiming canonicalMeasure = NN_TRY(makeExecutionFailure(nn::convert(measure)));
+    nn::MeasureTiming canonicalMeasure = NN_TRY(nn::convert(measure));
 
     const auto [outputShapes, timing] =
             NN_TRY(mBurstExecutor->execute(canonicalRequest, canonicalMeasure, {}, {}));
 
-    return std::make_pair(NN_TRY(makeExecutionFailure(convert(outputShapes))),
-                          NN_TRY(makeExecutionFailure(convert(timing))));
+    return std::make_pair(NN_TRY(convert(outputShapes)), NN_TRY(convert(timing)));
 }
 
 }  // namespace android::hardware::neuralnetworks::V1_2::utils
diff --git a/neuralnetworks/1.2/utils/src/PreparedModel.cpp b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
index d0ef36e..c261184 100644
--- a/neuralnetworks/1.2/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.2/utils/src/PreparedModel.cpp
@@ -95,13 +95,12 @@
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
-    const nn::Request& requestInShared =
-            NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
-                    &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
-                    &maybeRequestInShared, &relocation)));
+    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+            &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
+            &maybeRequestInShared, &relocation));
 
-    const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
-    const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
+    const auto hidlRequest = NN_TRY(convert(requestInShared));
+    const auto hidlMeasure = NN_TRY(convert(measure));
 
     return executeInternal(hidlRequest, hidlMeasure, relocation);
 }
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index e313b47..15a5d2f 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -71,7 +71,7 @@
         "libgmock",
         "libhidlmemory",
         "libneuralnetworks_generated_test_harness",
-        "libneuralnetworks_utils",
+        "libneuralnetworks_common_hidl",
     ],
     whole_static_libs: [
         "neuralnetworks_generated_V1_0_example",
diff --git a/neuralnetworks/1.3/utils/Android.bp b/neuralnetworks/1.3/utils/Android.bp
index 7acb4fc..8ae509f 100644
--- a/neuralnetworks/1.3/utils/Android.bp
+++ b/neuralnetworks/1.3/utils/Android.bp
@@ -69,7 +69,7 @@
         "android.hardware.neuralnetworks@1.2",
         "android.hardware.neuralnetworks@1.3",
         "libgmock",
-        "libneuralnetworks_common",
+        "libneuralnetworks_common_hidl",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
         "neuralnetworks_utils_hal_1_0",
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
index 1d76caa..28525bd 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h
@@ -61,8 +61,8 @@
 }
 
 template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
-    const auto version = NN_TRY(hal::utils::makeGeneralFailure(nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(nn::validate(canonical));
     if (version > kVersion) {
         return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
     }
diff --git a/neuralnetworks/1.3/utils/src/Callbacks.cpp b/neuralnetworks/1.3/utils/src/Callbacks.cpp
index 8e9fb83..156216f 100644
--- a/neuralnetworks/1.3/utils/src/Callbacks.cpp
+++ b/neuralnetworks/1.3/utils/src/Callbacks.cpp
@@ -91,8 +91,7 @@
                << "execution failed with " << toString(status);
     }
     HANDLE_HAL_STATUS(status) << "execution failed with " << toString(status);
-    return hal::utils::makeExecutionFailure(
-            convertExecutionGeneralResultsHelper(outputShapes, timing));
+    return convertExecutionGeneralResultsHelper(outputShapes, timing);
 }
 
 Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus status,
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index 11225cf..b35b2cd 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -131,9 +131,8 @@
     }
 
     auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
-    auto table = NN_TRY(hal::utils::makeGeneralFailure(
-            Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
-            nn::ErrorStatus::GENERAL_FAILURE));
+    auto table =
+            NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
 
     return Capabilities{
             .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
diff --git a/neuralnetworks/1.3/utils/src/Execution.cpp b/neuralnetworks/1.3/utils/src/Execution.cpp
index 3d17cc3..4dc0ddf 100644
--- a/neuralnetworks/1.3/utils/src/Execution.cpp
+++ b/neuralnetworks/1.3/utils/src/Execution.cpp
@@ -65,7 +65,7 @@
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Execution::compute(
         const nn::OptionalTimePoint& deadline) const {
-    const auto hidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
+    const auto hidlDeadline = NN_TRY(convert(deadline));
     return kPreparedModel->executeInternal(kRequest, kMeasure, hidlDeadline, kLoopTimeoutDuration,
                                            kRelocation);
 }
diff --git a/neuralnetworks/1.3/utils/src/PreparedModel.cpp b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
index 1623de5..d5dee9d 100644
--- a/neuralnetworks/1.3/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/1.3/utils/src/PreparedModel.cpp
@@ -62,8 +62,7 @@
     auto resultSyncFence = nn::SyncFence::createAsSignaled();
     if (syncFence.getNativeHandle() != nullptr) {
         auto sharedHandle = NN_TRY(nn::convert(syncFence));
-        resultSyncFence = NN_TRY(hal::utils::makeGeneralFailure(
-                nn::SyncFence::create(std::move(sharedHandle)), nn::ErrorStatus::GENERAL_FAILURE));
+        resultSyncFence = NN_TRY(nn::SyncFence::create(std::move(sharedHandle)));
     }
 
     if (callback == nullptr) {
@@ -141,16 +140,14 @@
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
-    const nn::Request& requestInShared =
-            NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
-                    &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
-                    &maybeRequestInShared, &relocation)));
+    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+            &request, nn::kDefaultRequestMemoryAlignment, nn::kMinMemoryPadding,
+            &maybeRequestInShared, &relocation));
 
-    const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
-    const auto hidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
-    const auto hidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
-    const auto hidlLoopTimeoutDuration =
-            NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
+    const auto hidlRequest = NN_TRY(convert(requestInShared));
+    const auto hidlMeasure = NN_TRY(convert(measure));
+    const auto hidlDeadline = NN_TRY(convert(deadline));
+    const auto hidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
 
     return executeInternal(hidlRequest, hidlMeasure, hidlDeadline, hidlLoopTimeoutDuration,
                            relocation);
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 1382bdb..ca59cc2 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -66,7 +66,6 @@
         "VtsHalNeuralNetworksV1_0_utils",
         "VtsHalNeuralNetworksV1_2_utils",
         "VtsHalNeuralNetworksV1_3_utils",
-        "android.hardware.neuralnetworks-V1-ndk",
         "android.hardware.neuralnetworks@1.0",
         "android.hardware.neuralnetworks@1.1",
         "android.hardware.neuralnetworks@1.2",
@@ -76,7 +75,7 @@
         "libgmock",
         "libhidlmemory",
         "libneuralnetworks_generated_test_harness",
-        "libneuralnetworks_utils",
+        "libneuralnetworks_common_hidl",
         "libsync",
     ],
     whole_static_libs: [
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl
index de3b438..2eff11b 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/OperationType.aidl
@@ -136,4 +136,6 @@
   HARD_SWISH = 99,
   FILL = 100,
   RANK = 101,
+  BATCH_MATMUL = 102,
+  PACK = 103,
 }
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
index 52d2d70..2ec91ac 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/OperationType.aidl
@@ -1471,6 +1471,7 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
+     * * {@link OperandType::TENSOR_INT32} (since NNAPI feature level 6)
      *
      * Supported tensor rank: up to 4.
      *
@@ -5236,4 +5237,89 @@
      *      of the input tensor.
      */
     RANK = 101,
+
+    /**
+     * Performs multiplication of two tensors in batches.
+     *
+     * Multiplies all slices of two input tensors and arranges the individual
+     * results in a single output tensor of the same batch size. Each pair of
+     * slices in the same batch have identical {@link OperandType}. Each
+     * slice can optionally be adjointed (transpose and conjugate) before
+     * multiplication.
+     *
+     * The two input tensors and the output tensor must be 2-D or higher and
+     * have the same batch size.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+     * * {@link OperandType::TENSOR_INT32}
+     *
+     * Supported tensor rank: at least 2 and up to 4
+     *
+     * Inputs:
+     * * 0: A tensor with 2-D or higher shape [..., r_x, c_x].
+     * * 1: A tensor with 2-D or higher shape [..., r_y, c_y]. It has the same
+     *      {@link OperandType} and batch size as input0.
+     * * 2: An optional {@link OperandType::BOOL} scalar adj_x, default
+     *      to false. Set to true to adjoint the slices of input0.
+     * * 3: An optional {@link OperandType::BOOL} scalar adj_y, default
+     *      to false. Set to true to adjoint the slices of input1.
+     *
+     * Outputs:
+     * * 0: A tensor with 2-D or higher shape [..., r_o, c_o], where
+     *      r_o = c_x if adj_x else r_x
+     *      c_o = r_y if adj_y else c_y
+     */
+    BATCH_MATMUL = 102,
+
+    /**
+     * Packs N input tensors (N >= 1) of rank R into one output tensor of rank R+1.
+     * The tensors are packed along a given axis.
+     *
+     * The input tensors must have identical {@link OperandType} and dimensions.
+     *
+     * For example, suppose there are N input tensors of shape (A, B, C).
+     * If axis is 0, the output tensor will have shape (N, A, B, C).
+     * If axis is 1, the output tensor will have shape (A, N, B, C).
+     *
+     * All dimensions through the axis dimension determine the output tile count;
+     * the remaining dimensions determine the tile shape.
+     *
+     * Return to the example of N input tensors of shape (A, B, C).
+     * If axis is 0, there are N tiles in the output, each of shape (A, B, C).
+     * If axis is 1, there are A*N tiles in the output, each of shape (B, C).
+     *
+     * The coordinates of a tile within the output tensor are (t[0],...,t[axis]).
+     * The coordinates of a tile within an input tensor are (t[0],...,t[axis-1]).
+     * (If axis is 0, an input tensor consists of a single tile.)
+     * If we index input tensors starting with 0 (rather than by operand number),
+     * then output_tile[t[0],...,t[axis]] = input_tile[t[axis]][t[0],...,t[axis-1]].
+     * That is, all output tile coordinates except for the axis coordinate select
+     * the corresponding location within some input tensor; and the axis coordinate
+     * selects the input tensor.
+     *
+     * Supported tensor {@link OperandType}:
+     * * {@link OperandType::TENSOR_FLOAT16}
+     * * {@link OperandType::TENSOR_FLOAT32}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
+     * * {@link OperandType::TENSOR_INT32}
+     *
+     * Supported input tensor rank: from 1
+     *
+     * Inputs:
+     * * 0: A scalar of type {@link OperandType::INT32}, specifying
+     *      the axis along which to pack.  The valid range is [0, R+1).
+     * * 1 ~ N: Input tensors to be packed together.
+     *          For {@link OperandType::TENSOR_QUANT8_ASYMM} and
+     *          {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensors,
+     *          the scales and zeroPoint must be the same for all input tensors,
+     *          and will be the same for the output tensor.
+     *
+     * Outputs:
+     * * 0: The packed tensor.
+     */
+    PACK = 103,
 }
diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp
index 3c80d75..2c2419b 100644
--- a/neuralnetworks/aidl/utils/Android.bp
+++ b/neuralnetworks/aidl/utils/Android.bp
@@ -23,8 +23,8 @@
     default_applicable_licenses: ["hardware_interfaces_license"],
 }
 
-cc_library_static {
-    name: "neuralnetworks_utils_hal_aidl",
+cc_defaults {
+    name: "neuralnetworks_utils_hal_aidl_defaults",
     defaults: ["neuralnetworks_utils_defaults"],
     srcs: ["src/*"],
     local_include_dirs: ["include/nnapi/hal/aidl/"],
@@ -38,7 +38,6 @@
         "neuralnetworks_utils_hal_common",
     ],
     shared_libs: [
-        "android.hardware.neuralnetworks-V1-ndk",
         "libbinder_ndk",
         "libhidlbase",
     ],
@@ -49,21 +48,49 @@
     },
 }
 
+cc_library_static {
+    name: "neuralnetworks_utils_hal_aidl_v1",
+    defaults: ["neuralnetworks_utils_hal_aidl_defaults"],
+    shared_libs: [
+        "android.hardware.neuralnetworks-V1-ndk",
+    ],
+}
+
+cc_library_static {
+    name: "neuralnetworks_utils_hal_aidl_v2",
+    defaults: ["neuralnetworks_utils_hal_aidl_defaults"],
+    shared_libs: [
+        "android.hardware.neuralnetworks-V2-ndk",
+    ],
+}
+
+// A cc_defaults that includes the latest non-experimental AIDL utilities and other AIDL libraries
+// that are commonly used together. Modules that always depend on the latest non-experimental
+// AIDL features can include this cc_defaults to avoid managing dependency versions explicitly.
+cc_defaults {
+    name: "neuralnetworks_use_latest_utils_hal_aidl",
+    static_libs: [
+        "android.hardware.common-V2-ndk",
+        "android.hardware.graphics.common-V3-ndk",
+        "android.hardware.neuralnetworks-V2-ndk",
+        "neuralnetworks_utils_hal_aidl_v2",
+    ],
+}
+
 cc_test {
     name: "neuralnetworks_utils_hal_aidl_test",
-    defaults: ["neuralnetworks_utils_defaults"],
+    defaults: [
+        "neuralnetworks_use_latest_utils_hal_aidl",
+        "neuralnetworks_utils_defaults",
+    ],
     srcs: [
         "test/*.cpp",
     ],
     static_libs: [
-        "android.hardware.common-V2-ndk",
-        "android.hardware.graphics.common-V3-ndk",
-        "android.hardware.neuralnetworks-V1-ndk",
         "libaidlcommonsupport",
         "libgmock",
         "libneuralnetworks_common",
         "neuralnetworks_types",
-        "neuralnetworks_utils_hal_aidl",
         "neuralnetworks_utils_hal_common",
     ],
     shared_libs: [
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
index 1457646..d558f66 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Device.h
@@ -43,11 +43,12 @@
 
   public:
     static nn::GeneralResult<std::shared_ptr<const Device>> create(
-            std::string name, std::shared_ptr<aidl_hal::IDevice> device);
+            std::string name, std::shared_ptr<aidl_hal::IDevice> device, nn::Version featureLevel);
 
     Device(PrivateConstructorTag tag, std::string name, std::string versionString,
-           nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
-           nn::Capabilities capabilities, std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded,
+           nn::Version featureLevel, nn::DeviceType deviceType,
+           std::vector<nn::Extension> extensions, nn::Capabilities capabilities,
+           std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded,
            std::shared_ptr<aidl_hal::IDevice> device, DeathHandler deathHandler);
 
     const std::string& getName() const override;
@@ -84,6 +85,7 @@
   private:
     const std::string kName;
     const std::string kVersionString;
+    const nn::Version kFeatureLevel;
     const nn::DeviceType kDeviceType;
     const std::vector<nn::Extension> kExtensions;
     const nn::Capabilities kCapabilities;
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
index 316d34f..1b149e4 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Utils.h
@@ -50,9 +50,8 @@
 }
 
 template <typename Type>
-nn::GeneralResult<void> compliantVersion(const Type& canonical) {
-    const auto version = NN_TRY(::android::hardware::neuralnetworks::utils::makeGeneralFailure(
-            nn::validate(canonical)));
+nn::Result<void> compliantVersion(const Type& canonical) {
+    const auto version = NN_TRY(nn::validate(canonical));
     if (version > kVersion) {
         return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion;
     }
diff --git a/neuralnetworks/aidl/utils/src/Burst.cpp b/neuralnetworks/aidl/utils/src/Burst.cpp
index 800ac32..c59c10b 100644
--- a/neuralnetworks/aidl/utils/src/Burst.cpp
+++ b/neuralnetworks/aidl/utils/src/Burst.cpp
@@ -176,16 +176,14 @@
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
-    const nn::Request& requestInShared =
-            NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
-                    &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
-                    &maybeRequestInShared, &relocation)));
+    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+            &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
+            &maybeRequestInShared, &relocation));
 
-    const auto aidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
-    const auto aidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
-    const auto aidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
-    const auto aidlLoopTimeoutDuration =
-            NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
+    const auto aidlRequest = NN_TRY(convert(requestInShared));
+    const auto aidlMeasure = NN_TRY(convert(measure));
+    const auto aidlDeadline = NN_TRY(convert(deadline));
+    const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
 
     std::vector<int64_t> memoryIdentifierTokens;
     std::vector<OptionalCacheHold> holds;
@@ -233,8 +231,8 @@
         return NN_ERROR(nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, std::move(canonicalOutputShapes))
                << "execution failed with " << nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
     }
-    auto [outputShapes, timing] = NN_TRY(hal::utils::makeExecutionFailure(
-            convertExecutionResults(executionResult.outputShapes, executionResult.timing)));
+    auto [outputShapes, timing] =
+            NN_TRY(convertExecutionResults(executionResult.outputShapes, executionResult.timing));
 
     if (relocation.output) {
         relocation.output->flush();
@@ -308,7 +306,7 @@
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> BurstExecution::compute(
         const nn::OptionalTimePoint& deadline) const {
-    const auto aidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
+    const auto aidlDeadline = NN_TRY(convert(deadline));
     return kBurst->executeInternal(kRequest, kMemoryIdentifierTokens, kMeasure, aidlDeadline,
                                    kLoopTimeoutDuration, kRelocation);
 }
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index f087156..ddff3f2 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -178,9 +178,8 @@
     }
 
     auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
-    auto table = NN_TRY(hal::utils::makeGeneralFailure(
-            Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)),
-            nn::ErrorStatus::GENERAL_FAILURE));
+    auto table =
+            NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
 
     return Capabilities{
             .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
diff --git a/neuralnetworks/aidl/utils/src/Device.cpp b/neuralnetworks/aidl/utils/src/Device.cpp
index e80de0b..5b7ec4e 100644
--- a/neuralnetworks/aidl/utils/src/Device.cpp
+++ b/neuralnetworks/aidl/utils/src/Device.cpp
@@ -125,7 +125,7 @@
 }  // namespace
 
 nn::GeneralResult<std::shared_ptr<const Device>> Device::create(
-        std::string name, std::shared_ptr<aidl_hal::IDevice> device) {
+        std::string name, std::shared_ptr<aidl_hal::IDevice> device, nn::Version featureLevel) {
     if (name.empty()) {
         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
                << "aidl_hal::utils::Device::create must have non-empty name";
@@ -143,18 +143,19 @@
 
     auto deathHandler = NN_TRY(DeathHandler::create(device));
     return std::make_shared<const Device>(
-            PrivateConstructorTag{}, std::move(name), std::move(versionString), deviceType,
-            std::move(extensions), std::move(capabilities), numberOfCacheFilesNeeded,
+            PrivateConstructorTag{}, std::move(name), std::move(versionString), featureLevel,
+            deviceType, std::move(extensions), std::move(capabilities), numberOfCacheFilesNeeded,
             std::move(device), std::move(deathHandler));
 }
 
 Device::Device(PrivateConstructorTag /*tag*/, std::string name, std::string versionString,
-               nn::DeviceType deviceType, std::vector<nn::Extension> extensions,
-               nn::Capabilities capabilities,
+               nn::Version featureLevel, nn::DeviceType deviceType,
+               std::vector<nn::Extension> extensions, nn::Capabilities capabilities,
                std::pair<uint32_t, uint32_t> numberOfCacheFilesNeeded,
                std::shared_ptr<aidl_hal::IDevice> device, DeathHandler deathHandler)
     : kName(std::move(name)),
       kVersionString(std::move(versionString)),
+      kFeatureLevel(featureLevel),
       kDeviceType(deviceType),
       kExtensions(std::move(extensions)),
       kCapabilities(std::move(capabilities)),
@@ -171,7 +172,7 @@
 }
 
 nn::Version Device::getFeatureLevel() const {
-    return nn::Version::ANDROID_S;
+    return kFeatureLevel;
 }
 
 nn::DeviceType Device::getType() const {
diff --git a/neuralnetworks/aidl/utils/src/Execution.cpp b/neuralnetworks/aidl/utils/src/Execution.cpp
index 2aee8a6..13d4f32 100644
--- a/neuralnetworks/aidl/utils/src/Execution.cpp
+++ b/neuralnetworks/aidl/utils/src/Execution.cpp
@@ -60,7 +60,7 @@
 
 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> Execution::compute(
         const nn::OptionalTimePoint& deadline) const {
-    const auto aidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
+    const auto aidlDeadline = NN_TRY(convert(deadline));
     return kPreparedModel->executeInternal(kRequest, kMeasure, aidlDeadline, kLoopTimeoutDuration,
                                            kRelocation);
 }
diff --git a/neuralnetworks/aidl/utils/src/PreparedModel.cpp b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
index f861d74..0769016 100644
--- a/neuralnetworks/aidl/utils/src/PreparedModel.cpp
+++ b/neuralnetworks/aidl/utils/src/PreparedModel.cpp
@@ -78,16 +78,14 @@
     // Ensure that request is ready for IPC.
     std::optional<nn::Request> maybeRequestInShared;
     hal::utils::RequestRelocation relocation;
-    const nn::Request& requestInShared =
-            NN_TRY(hal::utils::makeExecutionFailure(hal::utils::convertRequestFromPointerToShared(
-                    &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
-                    &maybeRequestInShared, &relocation)));
+    const nn::Request& requestInShared = NN_TRY(hal::utils::convertRequestFromPointerToShared(
+            &request, nn::kDefaultRequestMemoryAlignment, nn::kDefaultRequestMemoryPadding,
+            &maybeRequestInShared, &relocation));
 
-    const auto aidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
-    const auto aidlMeasure = NN_TRY(hal::utils::makeExecutionFailure(convert(measure)));
-    const auto aidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
-    const auto aidlLoopTimeoutDuration =
-            NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
+    const auto aidlRequest = NN_TRY(convert(requestInShared));
+    const auto aidlMeasure = NN_TRY(convert(measure));
+    const auto aidlDeadline = NN_TRY(convert(deadline));
+    const auto aidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
     return executeInternal(aidlRequest, aidlMeasure, aidlDeadline, aidlLoopTimeoutDuration,
                            relocation);
 }
@@ -110,8 +108,8 @@
         return NN_ERROR(nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, std::move(canonicalOutputShapes))
                << "execution failed with " << nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
     }
-    auto [outputShapes, timing] = NN_TRY(hal::utils::makeExecutionFailure(
-            convertExecutionResults(executionResult.outputShapes, executionResult.timing)));
+    auto [outputShapes, timing] =
+            NN_TRY(convertExecutionResults(executionResult.outputShapes, executionResult.timing));
 
     if (relocation.output) {
         relocation.output->flush();
diff --git a/neuralnetworks/aidl/utils/src/Service.cpp b/neuralnetworks/aidl/utils/src/Service.cpp
index ac182a2..01772ee 100644
--- a/neuralnetworks/aidl/utils/src/Service.cpp
+++ b/neuralnetworks/aidl/utils/src/Service.cpp
@@ -17,6 +17,7 @@
 #include "Service.h"
 
 #include <AndroidVersionUtil.h>
+#include <aidl/android/hardware/neuralnetworks/IDevice.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
@@ -28,8 +29,33 @@
 #include <string>
 
 #include "Device.h"
+#include "Utils.h"
 
 namespace aidl::android::hardware::neuralnetworks::utils {
+namespace {
+
+// Map the AIDL version of an IDevice to NNAPI canonical feature level.
+nn::GeneralResult<nn::Version> getAidlServiceFeatureLevel(IDevice* service) {
+    CHECK(service != nullptr);
+    int aidlVersion;
+    const auto ret = service->getInterfaceVersion(&aidlVersion);
+    HANDLE_ASTATUS(ret) << "getInterfaceVersion failed";
+
+    // For service AIDL versions greater than or equal to the AIDL library version that the runtime
+    // was built against, clamp it to the runtime AIDL library version.
+    aidlVersion = std::min(aidlVersion, IDevice::version);
+
+    // Map stable AIDL versions to canonical versions.
+    switch (aidlVersion) {
+        case 1:
+            return nn::Version::ANDROID_S;
+        case 2:
+            return nn::Version::FEATURE_LEVEL_6;
+    }
+    return NN_ERROR() << "Unknown AIDL service version: " << aidlVersion;
+}
+
+}  // namespace
 
 nn::GeneralResult<nn::SharedDevice> getDevice(const std::string& instanceName) {
     auto fullName = std::string(IDevice::descriptor) + "/" + instanceName;
@@ -55,7 +81,8 @@
                    << " returned nullptr";
         }
         ABinderProcess_startThreadPool();
-        return Device::create(instanceName, std::move(service));
+        const auto featureLevel = NN_TRY(getAidlServiceFeatureLevel(service.get()));
+        return Device::create(instanceName, std::move(service), featureLevel);
     };
 
     return hal::utils::ResilientDevice::create(std::move(makeDevice));
diff --git a/neuralnetworks/aidl/utils/test/DeviceTest.cpp b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
index f121aca..79abe1b 100644
--- a/neuralnetworks/aidl/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
@@ -146,28 +146,45 @@
     return ndk::ScopedAStatus::fromStatus(STATUS_DEAD_OBJECT);
 };
 
+class DeviceTest : public ::testing::TestWithParam<nn::Version> {
+  protected:
+    const nn::Version kVersion = GetParam();
+};
+
+std::string printDeviceTest(const testing::TestParamInfo<nn::Version>& info) {
+    switch (info.param) {
+        case nn::Version::ANDROID_S:
+            return "v1";
+        case nn::Version::FEATURE_LEVEL_6:
+            return "v2";
+        default:
+            LOG(FATAL) << "Invalid AIDL version: " << info.param;
+            return "invalid";
+    }
+}
+
 }  // namespace
 
-TEST(DeviceTest, invalidName) {
+TEST_P(DeviceTest, invalidName) {
     // run test
     const auto device = MockDevice::create();
-    const auto result = Device::create(kInvalidName, device);
+    const auto result = Device::create(kInvalidName, device, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::INVALID_ARGUMENT);
 }
 
-TEST(DeviceTest, invalidDevice) {
+TEST_P(DeviceTest, invalidDevice) {
     // run test
-    const auto result = Device::create(kName, kInvalidDevice);
+    const auto result = Device::create(kName, kInvalidDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::INVALID_ARGUMENT);
 }
 
-TEST(DeviceTest, getVersionStringError) {
+TEST_P(DeviceTest, getVersionStringError) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getVersionString(_))
@@ -175,14 +192,14 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getVersionStringTransportFailure) {
+TEST_P(DeviceTest, getVersionStringTransportFailure) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getVersionString(_))
@@ -190,14 +207,14 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getVersionStringDeadObject) {
+TEST_P(DeviceTest, getVersionStringDeadObject) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getVersionString(_))
@@ -205,27 +222,27 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, getTypeError) {
+TEST_P(DeviceTest, getTypeError) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getType(_)).Times(1).WillOnce(InvokeWithoutArgs(makeGeneralFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getTypeTransportFailure) {
+TEST_P(DeviceTest, getTypeTransportFailure) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getType(_))
@@ -233,14 +250,14 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getTypeDeadObject) {
+TEST_P(DeviceTest, getTypeDeadObject) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getType(_))
@@ -248,14 +265,14 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, getSupportedExtensionsError) {
+TEST_P(DeviceTest, getSupportedExtensionsError) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getSupportedExtensions(_))
@@ -263,14 +280,14 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getSupportedExtensionsTransportFailure) {
+TEST_P(DeviceTest, getSupportedExtensionsTransportFailure) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getSupportedExtensions(_))
@@ -278,14 +295,14 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getSupportedExtensionsDeadObject) {
+TEST_P(DeviceTest, getSupportedExtensionsDeadObject) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getSupportedExtensions(_))
@@ -293,20 +310,20 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, getNumberOfCacheFilesNeeded) {
+TEST_P(DeviceTest, getNumberOfCacheFilesNeeded) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_)).Times(1);
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_TRUE(result.has_value());
@@ -315,7 +332,7 @@
     EXPECT_EQ(result.value()->getNumberOfCacheFilesNeeded(), kNumberOfCacheFilesPair);
 }
 
-TEST(DeviceTest, getNumberOfCacheFilesNeededError) {
+TEST_P(DeviceTest, getNumberOfCacheFilesNeededError) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_))
@@ -323,14 +340,14 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, dataCacheFilesExceedsSpecifiedMax) {
+TEST_P(DeviceTest, dataCacheFilesExceedsSpecifiedMax) {
     // setup test
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_))
@@ -341,14 +358,14 @@
                             InvokeWithoutArgs(makeStatusOk)));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, modelCacheFilesExceedsSpecifiedMax) {
+TEST_P(DeviceTest, modelCacheFilesExceedsSpecifiedMax) {
     // setup test
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_))
@@ -359,14 +376,14 @@
                             InvokeWithoutArgs(makeStatusOk)));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getNumberOfCacheFilesNeededTransportFailure) {
+TEST_P(DeviceTest, getNumberOfCacheFilesNeededTransportFailure) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_))
@@ -374,14 +391,14 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getNumberOfCacheFilesNeededDeadObject) {
+TEST_P(DeviceTest, getNumberOfCacheFilesNeededDeadObject) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_))
@@ -389,14 +406,14 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, getCapabilitiesError) {
+TEST_P(DeviceTest, getCapabilitiesError) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getCapabilities(_))
@@ -404,14 +421,14 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getCapabilitiesTransportFailure) {
+TEST_P(DeviceTest, getCapabilitiesTransportFailure) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getCapabilities(_))
@@ -419,14 +436,14 @@
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getCapabilitiesDeadObject) {
+TEST_P(DeviceTest, getCapabilitiesDeadObject) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getCapabilities(_))
@@ -434,17 +451,17 @@
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
 
     // run test
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
 
     // verify result
     ASSERT_FALSE(result.has_value());
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, getName) {
+TEST_P(DeviceTest, getName) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
 
     // run test
     const auto& name = device->getName();
@@ -453,19 +470,19 @@
     EXPECT_EQ(name, kName);
 }
 
-TEST(DeviceTest, getFeatureLevel) {
+TEST_P(DeviceTest, getFeatureLevel) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
 
     // run test
     const auto featureLevel = device->getFeatureLevel();
 
     // verify result
-    EXPECT_EQ(featureLevel, nn::Version::ANDROID_S);
+    EXPECT_EQ(featureLevel, kVersion);
 }
 
-TEST(DeviceTest, getCachedData) {
+TEST_P(DeviceTest, getCachedData) {
     // setup call
     const auto mockDevice = createMockDevice();
     EXPECT_CALL(*mockDevice, getVersionString(_)).Times(1);
@@ -474,7 +491,7 @@
     EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_)).Times(1);
     EXPECT_CALL(*mockDevice, getCapabilities(_)).Times(1);
 
-    const auto result = Device::create(kName, mockDevice);
+    const auto result = Device::create(kName, mockDevice, kVersion);
     ASSERT_TRUE(result.has_value())
             << "Failed with " << result.error().code << ": " << result.error().message;
     const auto& device = result.value();
@@ -487,10 +504,10 @@
     EXPECT_EQ(device->getCapabilities(), device->getCapabilities());
 }
 
-TEST(DeviceTest, getSupportedOperations) {
+TEST_P(DeviceTest, getSupportedOperations) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, getSupportedOperations(_, _))
             .Times(1)
             .WillOnce(DoAll(
@@ -508,10 +525,10 @@
     EXPECT_THAT(supportedOperations, Each(testing::IsTrue()));
 }
 
-TEST(DeviceTest, getSupportedOperationsError) {
+TEST_P(DeviceTest, getSupportedOperationsError) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, getSupportedOperations(_, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
@@ -524,10 +541,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getSupportedOperationsTransportFailure) {
+TEST_P(DeviceTest, getSupportedOperationsTransportFailure) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, getSupportedOperations(_, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
@@ -540,10 +557,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, getSupportedOperationsDeadObject) {
+TEST_P(DeviceTest, getSupportedOperationsDeadObject) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, getSupportedOperations(_, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
@@ -556,10 +573,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, prepareModel) {
+TEST_P(DeviceTest, prepareModel) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     const auto mockPreparedModel = MockPreparedModel::create();
     EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _))
             .Times(1)
@@ -576,10 +593,10 @@
     EXPECT_NE(result.value(), nullptr);
 }
 
-TEST(DeviceTest, prepareModelLaunchError) {
+TEST_P(DeviceTest, prepareModelLaunchError) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(Invoke(makePreparedModelReturn(ErrorStatus::GENERAL_FAILURE,
@@ -594,10 +611,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, prepareModelReturnError) {
+TEST_P(DeviceTest, prepareModelReturnError) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(Invoke(makePreparedModelReturn(ErrorStatus::NONE,
@@ -612,10 +629,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, prepareModelNullptrError) {
+TEST_P(DeviceTest, prepareModelNullptrError) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(
@@ -630,10 +647,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, prepareModelTransportFailure) {
+TEST_P(DeviceTest, prepareModelTransportFailure) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
@@ -647,10 +664,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, prepareModelDeadObject) {
+TEST_P(DeviceTest, prepareModelDeadObject) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModel(_, _, _, _, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
@@ -664,10 +681,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, prepareModelAsyncCrash) {
+TEST_P(DeviceTest, prepareModelAsyncCrash) {
     // setup test
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     const auto ret = [&device]() {
         DeathMonitor::serviceDied(device->getDeathMonitor());
         return ndk::ScopedAStatus::ok();
@@ -685,10 +702,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, prepareModelFromCache) {
+TEST_P(DeviceTest, prepareModelFromCache) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     const auto mockPreparedModel = MockPreparedModel::create();
     EXPECT_CALL(*mockDevice, prepareModelFromCache(_, _, _, _, _))
             .Times(1)
@@ -704,10 +721,10 @@
     EXPECT_NE(result.value(), nullptr);
 }
 
-TEST(DeviceTest, prepareModelFromCacheLaunchError) {
+TEST_P(DeviceTest, prepareModelFromCacheLaunchError) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModelFromCache(_, _, _, _, _))
             .Times(1)
             .WillOnce(Invoke(makePreparedModelFromCacheReturn(
@@ -721,10 +738,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, prepareModelFromCacheReturnError) {
+TEST_P(DeviceTest, prepareModelFromCacheReturnError) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModelFromCache(_, _, _, _, _))
             .Times(1)
             .WillOnce(Invoke(makePreparedModelFromCacheReturn(
@@ -738,10 +755,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, prepareModelFromCacheNullptrError) {
+TEST_P(DeviceTest, prepareModelFromCacheNullptrError) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModelFromCache(_, _, _, _, _))
             .Times(1)
             .WillOnce(Invoke(makePreparedModelFromCacheReturn(ErrorStatus::NONE, ErrorStatus::NONE,
@@ -755,10 +772,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, prepareModelFromCacheTransportFailure) {
+TEST_P(DeviceTest, prepareModelFromCacheTransportFailure) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModelFromCache(_, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
@@ -771,10 +788,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, prepareModelFromCacheDeadObject) {
+TEST_P(DeviceTest, prepareModelFromCacheDeadObject) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, prepareModelFromCache(_, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
@@ -787,10 +804,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, prepareModelFromCacheAsyncCrash) {
+TEST_P(DeviceTest, prepareModelFromCacheAsyncCrash) {
     // setup test
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     const auto ret = [&device]() {
         DeathMonitor::serviceDied(device->getDeathMonitor());
         return ndk::ScopedAStatus::ok();
@@ -807,10 +824,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
-TEST(DeviceTest, allocate) {
+TEST_P(DeviceTest, allocate) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     const auto mockBuffer = DeviceBuffer{.buffer = MockBuffer::create(), .token = 1};
     EXPECT_CALL(*mockDevice, allocate(_, _, _, _, _))
             .Times(1)
@@ -825,10 +842,10 @@
     EXPECT_NE(result.value(), nullptr);
 }
 
-TEST(DeviceTest, allocateError) {
+TEST_P(DeviceTest, allocateError) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, allocate(_, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralFailure));
@@ -841,10 +858,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, allocateTransportFailure) {
+TEST_P(DeviceTest, allocateTransportFailure) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, allocate(_, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
@@ -857,10 +874,10 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
 }
 
-TEST(DeviceTest, allocateDeadObject) {
+TEST_P(DeviceTest, allocateDeadObject) {
     // setup call
     const auto mockDevice = createMockDevice();
-    const auto device = Device::create(kName, mockDevice).value();
+    const auto device = Device::create(kName, mockDevice, kVersion).value();
     EXPECT_CALL(*mockDevice, allocate(_, _, _, _, _))
             .Times(1)
             .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
@@ -873,4 +890,8 @@
     EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
 }
 
+INSTANTIATE_TEST_SUITE_P(TestDevice, DeviceTest,
+                         ::testing::Values(nn::Version::ANDROID_S, nn::Version::FEATURE_LEVEL_6),
+                         printDeviceTest);
+
 }  // namespace aidl::android::hardware::neuralnetworks::utils
diff --git a/neuralnetworks/aidl/vts/OWNERS b/neuralnetworks/aidl/vts/OWNERS
index 6719a5b..f1a757a 100644
--- a/neuralnetworks/aidl/vts/OWNERS
+++ b/neuralnetworks/aidl/vts/OWNERS
@@ -2,11 +2,8 @@
 butlermichael@google.com
 dgross@google.com
 jeanluc@google.com
-levp@google.com
 miaowang@google.com
 mikie@google.com
-mks@google.com
 pszczepaniak@google.com
-slavash@google.com
-vddang@google.com
 xusongw@google.com
+ianhua@google.com
diff --git a/neuralnetworks/aidl/vts/functional/Android.bp b/neuralnetworks/aidl/vts/functional/Android.bp
index 40da1fd..8fd8f4f 100644
--- a/neuralnetworks/aidl/vts/functional/Android.bp
+++ b/neuralnetworks/aidl/vts/functional/Android.bp
@@ -26,6 +26,7 @@
 cc_test {
     name: "VtsHalNeuralnetworksTargetTest",
     defaults: [
+        "neuralnetworks_use_latest_utils_hal_aidl",
         "neuralnetworks_vts_functional_defaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
@@ -51,16 +52,14 @@
     static_libs: [
         "android.hardware.common-V2-ndk",
         "android.hardware.graphics.common-V3-ndk",
-        "android.hardware.neuralnetworks-V1-ndk",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
         "libaidlcommonsupport",
         "libgmock",
         "libhidlmemory",
+        "libneuralnetworks_common",
         "libneuralnetworks_generated_test_harness",
-        "libneuralnetworks_utils",
         "libsync",
-        "neuralnetworks_utils_hal_aidl",
     ],
     whole_static_libs: [
         "neuralnetworks_generated_V1_0_example",
diff --git a/neuralnetworks/utils/adapter/src/PreparedModel.cpp b/neuralnetworks/utils/adapter/src/PreparedModel.cpp
index 8968c2c..7397def 100644
--- a/neuralnetworks/utils/adapter/src/PreparedModel.cpp
+++ b/neuralnetworks/utils/adapter/src/PreparedModel.cpp
@@ -57,6 +57,15 @@
     return result;
 }
 
+nn::GeneralResult<nn::Version> validateRequestForModel(const nn::Request& request,
+                                                       const nn::Model& model) {
+    nn::GeneralResult<nn::Version> version = nn::validateRequestForModel(request, model);
+    if (!version.ok()) {
+        version.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
+    }
+    return version;
+}
+
 class FencedExecutionCallback final : public V1_3::IFencedExecutionCallback {
   public:
     explicit FencedExecutionCallback(const nn::ExecuteFencedInfoCallback& callback)
@@ -148,8 +157,7 @@
     const std::any resource = preparedModel->getUnderlyingResource();
     if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
         CHECK(*model != nullptr);
-        NN_TRY(utils::makeGeneralFailure(nn::validateRequestForModel(nnRequest, **model),
-                                         nn::ErrorStatus::INVALID_ARGUMENT));
+        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
     }
 
     Task task = [preparedModel, nnRequest = std::move(nnRequest), callback] {
@@ -175,8 +183,7 @@
     const std::any resource = preparedModel->getUnderlyingResource();
     if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
         CHECK(*model != nullptr);
-        NN_TRY(utils::makeGeneralFailure(nn::validateRequestForModel(nnRequest, **model),
-                                         nn::ErrorStatus::INVALID_ARGUMENT));
+        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
     }
 
     Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, callback] {
@@ -206,8 +213,7 @@
     const std::any resource = preparedModel->getUnderlyingResource();
     if (const auto* model = std::any_cast<const nn::Model*>(&resource)) {
         CHECK(*model != nullptr);
-        NN_TRY(utils::makeGeneralFailure(nn::validateRequestForModel(nnRequest, **model),
-                                         nn::ErrorStatus::INVALID_ARGUMENT));
+        NN_TRY(adapter::validateRequestForModel(nnRequest, **model));
     }
 
     Task task = [preparedModel, nnRequest = std::move(nnRequest), nnMeasure, nnDeadline,
@@ -224,14 +230,14 @@
 nn::ExecutionResult<std::pair<hidl_vec<V1_2::OutputShape>, V1_2::Timing>> executeSynchronously(
         const nn::SharedPreparedModel& preparedModel, const V1_0::Request& request,
         V1_2::MeasureTiming measure) {
-    const auto nnRequest = NN_TRY(utils::makeExecutionFailure(convertInput(request)));
-    const auto nnMeasure = NN_TRY(utils::makeExecutionFailure(convertInput(measure)));
+    const auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnMeasure = NN_TRY(convertInput(measure));
 
     const auto [outputShapes, timing] =
             NN_TRY(preparedModel->execute(nnRequest, nnMeasure, {}, {}));
 
-    auto hidlOutputShapes = NN_TRY(utils::makeExecutionFailure(V1_2::utils::convert(outputShapes)));
-    const auto hidlTiming = NN_TRY(utils::makeExecutionFailure(V1_2::utils::convert(timing)));
+    auto hidlOutputShapes = NN_TRY(V1_2::utils::convert(outputShapes));
+    const auto hidlTiming = NN_TRY(V1_2::utils::convert(timing));
     return std::make_pair(std::move(hidlOutputShapes), hidlTiming);
 }
 
@@ -239,29 +245,30 @@
         const nn::SharedPreparedModel& preparedModel, const V1_3::Request& request,
         V1_2::MeasureTiming measure, const V1_3::OptionalTimePoint& deadline,
         const V1_3::OptionalTimeoutDuration& loopTimeoutDuration) {
-    const auto nnRequest = NN_TRY(utils::makeExecutionFailure(convertInput(request)));
-    const auto nnMeasure = NN_TRY(utils::makeExecutionFailure(convertInput(measure)));
-    const auto nnDeadline = NN_TRY(utils::makeExecutionFailure(convertInput(deadline)));
-    const auto nnLoopTimeoutDuration =
-            NN_TRY(utils::makeExecutionFailure(convertInput(loopTimeoutDuration)));
+    const auto nnRequest = NN_TRY(convertInput(request));
+    const auto nnMeasure = NN_TRY(convertInput(measure));
+    const auto nnDeadline = NN_TRY(convertInput(deadline));
+    const auto nnLoopTimeoutDuration = NN_TRY(convertInput(loopTimeoutDuration));
 
     const auto [outputShapes, timing] =
             NN_TRY(preparedModel->execute(nnRequest, nnMeasure, nnDeadline, nnLoopTimeoutDuration));
 
-    auto hidlOutputShapes = NN_TRY(utils::makeExecutionFailure(V1_3::utils::convert(outputShapes)));
-    const auto hidlTiming = NN_TRY(utils::makeExecutionFailure(V1_3::utils::convert(timing)));
+    auto hidlOutputShapes = NN_TRY(V1_3::utils::convert(outputShapes));
+    const auto hidlTiming = NN_TRY(V1_3::utils::convert(timing));
     return std::make_pair(std::move(hidlOutputShapes), hidlTiming);
 }
 
 nn::GeneralResult<std::vector<nn::SyncFence>> convertSyncFences(
         const hidl_vec<hidl_handle>& handles) {
+    auto nnHandles = NN_TRY(convertInput(handles));
     std::vector<nn::SyncFence> syncFences;
     syncFences.reserve(handles.size());
-    for (const auto& handle : handles) {
-        auto nativeHandle = NN_TRY(convertInput(handle));
-        auto syncFence = NN_TRY(utils::makeGeneralFailure(
-                nn::SyncFence::create(std::move(nativeHandle)), nn::ErrorStatus::INVALID_ARGUMENT));
-        syncFences.push_back(std::move(syncFence));
+    for (auto&& handle : nnHandles) {
+        if (auto syncFence = nn::SyncFence::create(std::move(handle)); !syncFence.ok()) {
+            return nn::error(nn::ErrorStatus::INVALID_ARGUMENT) << std::move(syncFence).error();
+        } else {
+            syncFences.push_back(std::move(syncFence).value());
+        }
     }
     return syncFences;
 }
diff --git a/neuralnetworks/utils/common/Android.bp b/neuralnetworks/utils/common/Android.bp
index 431885c..c0645b0 100644
--- a/neuralnetworks/utils/common/Android.bp
+++ b/neuralnetworks/utils/common/Android.bp
@@ -35,7 +35,6 @@
         "neuralnetworks_types",
     ],
     shared_libs: [
-        "android.hardware.neuralnetworks-V1-ndk",
         "libhidlbase",
         "libbinder_ndk",
     ],
@@ -53,7 +52,7 @@
     static_libs: [
         "android.hardware.neuralnetworks@1.0",
         "libgmock",
-        "libneuralnetworks_common",
+        "libneuralnetworks_common_hidl",
         "neuralnetworks_types",
         "neuralnetworks_utils_hal_common",
     ],
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
index 209b663..e51f916 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
@@ -52,38 +52,6 @@
         std::move(result).value();                                                           \
     })
 
-template <typename Type>
-nn::GeneralResult<Type> makeGeneralFailure(
-        nn::Result<Type> result, nn::ErrorStatus status = nn::ErrorStatus::GENERAL_FAILURE) {
-    if (!result.has_value()) {
-        return nn::error(status) << std::move(result).error();
-    }
-    if constexpr (!std::is_same_v<Type, void>) {
-        return std::move(result).value();
-    } else {
-        return {};
-    }
-}
-
-template <typename Type>
-nn::ExecutionResult<Type> makeExecutionFailure(nn::GeneralResult<Type> result) {
-    if (!result.has_value()) {
-        const auto [message, status] = std::move(result).error();
-        return nn::error(status) << message;
-    }
-    if constexpr (!std::is_same_v<Type, void>) {
-        return std::move(result).value();
-    } else {
-        return {};
-    }
-}
-
-template <typename Type>
-nn::ExecutionResult<Type> makeExecutionFailure(
-        nn::Result<Type> result, nn::ErrorStatus status = nn::ErrorStatus::GENERAL_FAILURE) {
-    return makeExecutionFailure(makeGeneralFailure(result, status));
-}
-
 #define HANDLE_HAL_STATUS(status)                                       \
     if (const auto canonical = ::android::nn::convert(status).value_or( \
                 ::android::nn::ErrorStatus::GENERAL_FAILURE);           \
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
index ae02c88..235ba29 100644
--- a/neuralnetworks/utils/common/src/CommonUtils.cpp
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -333,7 +333,7 @@
 
 nn::GeneralResult<std::vector<uint32_t>> countNumberOfConsumers(
         size_t numberOfOperands, const std::vector<nn::Operation>& operations) {
-    return makeGeneralFailure(nn::countNumberOfConsumers(numberOfOperands, operations));
+    return nn::countNumberOfConsumers(numberOfOperands, operations);
 }
 
 nn::GeneralResult<hidl_memory> createHidlMemoryFromSharedMemory(const nn::SharedMemory& memory) {
diff --git a/neuralnetworks/utils/service/Android.bp b/neuralnetworks/utils/service/Android.bp
index 653e51a..3288d05 100644
--- a/neuralnetworks/utils/service/Android.bp
+++ b/neuralnetworks/utils/service/Android.bp
@@ -25,7 +25,10 @@
 
 cc_library_static {
     name: "neuralnetworks_utils_hal_service",
-    defaults: ["neuralnetworks_utils_defaults"],
+    defaults: [
+        "neuralnetworks_use_latest_utils_hal_aidl",
+        "neuralnetworks_utils_defaults",
+    ],
     srcs: ["src/*"],
     local_include_dirs: ["include/nnapi/hal"],
     export_include_dirs: ["include"],
@@ -35,11 +38,9 @@
         "neuralnetworks_utils_hal_1_1",
         "neuralnetworks_utils_hal_1_2",
         "neuralnetworks_utils_hal_1_3",
-        "neuralnetworks_utils_hal_aidl",
         "neuralnetworks_utils_hal_common",
     ],
     shared_libs: [
-        "android.hardware.neuralnetworks-V1-ndk",
         "android.hardware.neuralnetworks@1.0",
         "android.hardware.neuralnetworks@1.1",
         "android.hardware.neuralnetworks@1.2",
diff --git a/oemlock/1.0/vts/functional/OWNERS b/oemlock/1.0/vts/functional/OWNERS
new file mode 100644
index 0000000..ec8c304
--- /dev/null
+++ b/oemlock/1.0/vts/functional/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 186411
+chengyouho@google.com
+frankwoo@google.com
diff --git a/power/1.0/vts/functional/OWNERS b/power/1.0/vts/OWNERS
similarity index 100%
copy from power/1.0/vts/functional/OWNERS
copy to power/1.0/vts/OWNERS
diff --git a/power/1.1/vts/OWNERS b/power/1.1/vts/OWNERS
new file mode 100644
index 0000000..3a64da7
--- /dev/null
+++ b/power/1.1/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 158088
+wvw@google.com
diff --git a/power/1.0/vts/functional/OWNERS b/power/1.1/vts/functional/OWNERS
similarity index 100%
rename from power/1.0/vts/functional/OWNERS
rename to power/1.1/vts/functional/OWNERS
diff --git a/power/1.2/vts/OWNERS b/power/1.2/vts/OWNERS
new file mode 100644
index 0000000..4d8c7e9
--- /dev/null
+++ b/power/1.2/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 158088
+include ../../1.1/vts/OWNERS
diff --git a/power/1.3/vts/OWNERS b/power/1.3/vts/OWNERS
new file mode 100644
index 0000000..4d8c7e9
--- /dev/null
+++ b/power/1.3/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 158088
+include ../../1.1/vts/OWNERS
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index e07d2ba..d3f0cf9 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -32,23 +32,17 @@
     EXPECT_EQ(std::cv_status::no_timeout, wait());
     EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
     EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-
-    if (getRadioHalCapabilities()) {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_v1_6->rspInfo.error,
-                {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
-    } else {
-        ASSERT_TRUE(CheckAnyOfErrors(
-                radioRsp_v1_6->rspInfo.error,
-                {::android::hardware::radio::V1_6::RadioError::NONE,
-                 ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
-                 ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED,
-                 ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED,
-                 ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
-                 ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
-                 ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
-                 ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES}));
-    }
+    ASSERT_TRUE(
+            CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
+                             {::android::hardware::radio::V1_6::RadioError::NONE,
+                              ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                              ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED,
+                              ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED,
+                              ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+                              ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+                              ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+                              ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED,
+                              ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES}));
 }
 
 /*
@@ -74,23 +68,17 @@
         EXPECT_EQ(std::cv_status::no_timeout, wait());
         EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type);
         EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial);
-
-        if (getRadioHalCapabilities()) {
-            ASSERT_TRUE(CheckAnyOfErrors(
-                    radioRsp_v1_6->rspInfo.error,
-                    {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED}));
-        } else {
-            ASSERT_TRUE(CheckAnyOfErrors(
-                    radioRsp_v1_6->rspInfo.error,
-                    {::android::hardware::radio::V1_6::RadioError::NONE,
-                     ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
-                     ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED,
-                     ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED,
-                     ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
-                     ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
-                     ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
-                     ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES}));
-        }
+        ASSERT_TRUE(CheckAnyOfErrors(
+                radioRsp_v1_6->rspInfo.error,
+                {::android::hardware::radio::V1_6::RadioError::NONE,
+                 ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
+                 ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED,
+                 ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED,
+                 ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+                 ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS,
+                 ::android::hardware::radio::V1_6::RadioError::MODEM_ERR,
+                 ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED,
+                 ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES}));
     }
 }
 
diff --git a/renderscript/1.0/vts/functional/OWNERS b/renderscript/1.0/vts/functional/OWNERS
new file mode 100644
index 0000000..d785790
--- /dev/null
+++ b/renderscript/1.0/vts/functional/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 43047
+butlermichael@google.com
+dgross@google.com
+jeanluc@google.com
+miaowang@google.com
+xusongw@google.com
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index d7abf07..6f2f189 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -64,7 +64,9 @@
  * attestation.
  */
 TEST_P(DeviceUniqueAttestationTest, RsaNonStrongBoxUnimplemented) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
@@ -91,7 +93,9 @@
  * attestation.
  */
 TEST_P(DeviceUniqueAttestationTest, EcdsaNonStrongBoxUnimplemented) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
@@ -117,7 +121,9 @@
  * attestation correctly, if implemented.
  */
 TEST_P(DeviceUniqueAttestationTest, RsaDeviceUniqueAttestation) {
-    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+    if (SecLevel() != SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to non-StrongBox device";
+    }
 
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
@@ -174,7 +180,9 @@
  * attestation correctly, if implemented.
  */
 TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestation) {
-    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+    if (SecLevel() != SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to non-StrongBox device";
+    }
 
     vector<uint8_t> key_blob;
     vector<KeyCharacteristics> key_characteristics;
@@ -226,7 +234,9 @@
  * local device.
  */
 TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationID) {
-    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+    if (SecLevel() != SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to non-StrongBox device";
+    }
 
     // Collection of valid attestation ID tags.
     auto attestation_id_tags = AuthorizationSetBuilder();
@@ -292,7 +302,9 @@
  * don't match the local device.
  */
 TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationMismatchID) {
-    if (SecLevel() != SecurityLevel::STRONGBOX) return;
+    if (SecLevel() != SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to non-StrongBox device";
+    }
 
     // Collection of invalid attestation ID tags.
     auto attestation_id_tags =
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index d8db5c7..53d980d 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1482,6 +1482,7 @@
                               .Authorization(TAG_TRUSTED_CONFIRMATION_REQUIRED)
                               .Authorization(TAG_UNLOCKED_DEVICE_REQUIRED)
                               .Authorization(TAG_CREATION_DATETIME, 1619621648000);
+
     for (const KeyParameter& tag : extra_tags) {
         SCOPED_TRACE(testing::Message() << "tag-" << tag);
         vector<uint8_t> key_blob;
@@ -1520,19 +1521,19 @@
         CheckedDeleteKey(&key_blob);
     }
 
-    // Device attestation IDs should be rejected for normal attestation requests; these fields
-    // are only used for device unique attestation.
-    auto invalid_tags = AuthorizationSetBuilder()
-                                .Authorization(TAG_ATTESTATION_ID_BRAND, "brand")
-                                .Authorization(TAG_ATTESTATION_ID_DEVICE, "device")
-                                .Authorization(TAG_ATTESTATION_ID_PRODUCT, "product")
-                                .Authorization(TAG_ATTESTATION_ID_SERIAL, "serial")
-                                .Authorization(TAG_ATTESTATION_ID_IMEI, "imei")
-                                .Authorization(TAG_ATTESTATION_ID_MEID, "meid")
-                                .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer")
-                                .Authorization(TAG_ATTESTATION_ID_MODEL, "model");
+    // Collection of invalid attestation ID tags.
+    auto invalid_tags =
+            AuthorizationSetBuilder()
+                    .Authorization(TAG_ATTESTATION_ID_BRAND, "bogus-brand")
+                    .Authorization(TAG_ATTESTATION_ID_DEVICE, "devious-device")
+                    .Authorization(TAG_ATTESTATION_ID_PRODUCT, "punctured-product")
+                    .Authorization(TAG_ATTESTATION_ID_SERIAL, "suspicious-serial")
+                    .Authorization(TAG_ATTESTATION_ID_IMEI, "invalid-imei")
+                    .Authorization(TAG_ATTESTATION_ID_MEID, "mismatching-meid")
+                    .Authorization(TAG_ATTESTATION_ID_MANUFACTURER, "malformed-manufacturer")
+                    .Authorization(TAG_ATTESTATION_ID_MODEL, "malicious-model");
     for (const KeyParameter& tag : invalid_tags) {
-        SCOPED_TRACE(testing::Message() << "tag-" << tag);
+        SCOPED_TRACE(testing::Message() << "-incorrect-tag-" << tag);
         vector<uint8_t> key_blob;
         vector<KeyCharacteristics> key_characteristics;
         AuthorizationSetBuilder builder =
@@ -1552,6 +1553,74 @@
 }
 
 /*
+ * NewKeyGenerationTest.EcdsaAttestationIdTags
+ *
+ * Verifies that creation of an attested ECDSA key includes various ID tags in the
+ * attestation extension.
+ */
+TEST_P(NewKeyGenerationTest, EcdsaAttestationIdTags) {
+    auto challenge = "hello";
+    auto app_id = "foo";
+    auto subject = "cert subj 2";
+    vector<uint8_t> subject_der(make_name_from_str(subject));
+    uint64_t serial_int = 0x1010;
+    vector<uint8_t> serial_blob(build_serial_blob(serial_int));
+    const AuthorizationSetBuilder base_builder =
+            AuthorizationSetBuilder()
+                    .Authorization(TAG_NO_AUTH_REQUIRED)
+                    .EcdsaSigningKey(EcCurve::P_256)
+                    .Digest(Digest::NONE)
+                    .AttestationChallenge(challenge)
+                    .AttestationApplicationId(app_id)
+                    .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob)
+                    .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
+                    .SetDefaultValidity();
+
+    // Various ATTESTATION_ID_* tags that map to fields in the attestation extension ASN.1 schema.
+    auto extra_tags = AuthorizationSetBuilder();
+    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
+    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
+    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
+    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serial");
+    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MANUFACTURER, "ro.product.manufacturer");
+    add_tag_from_prop(&extra_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
+
+    for (const KeyParameter& tag : extra_tags) {
+        SCOPED_TRACE(testing::Message() << "tag-" << tag);
+        vector<uint8_t> key_blob;
+        vector<KeyCharacteristics> key_characteristics;
+        AuthorizationSetBuilder builder = base_builder;
+        builder.push_back(tag);
+        auto result = GenerateKey(builder, &key_blob, &key_characteristics);
+        if (result == ErrorCode::CANNOT_ATTEST_IDS) {
+            // Device ID attestation is optional; KeyMint may not support it at all.
+            continue;
+        }
+        ASSERT_EQ(result, ErrorCode::OK);
+        ASSERT_GT(key_blob.size(), 0U);
+
+        EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
+        ASSERT_GT(cert_chain_.size(), 0);
+        verify_subject_and_serial(cert_chain_[0], serial_int, subject, /* self_signed = */ false);
+
+        AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
+        AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
+
+        // The attested key characteristics will not contain APPLICATION_ID_* fields (their
+        // spec definitions all have "Must never appear in KeyCharacteristics"), but the
+        // attestation extension should contain them, so make sure the extra tag is added.
+        hw_enforced.push_back(tag);
+
+        // Verifying the attestation record will check for the specific tag because
+        // it's included in the authorizations.
+        EXPECT_TRUE(verify_attestation_record(challenge, app_id, sw_enforced, hw_enforced,
+                                              SecLevel(), cert_chain_[0].encodedCertificate));
+
+        CheckedDeleteKey(&key_blob);
+    }
+}
+
+/*
  * NewKeyGenerationTest.EcdsaAttestationTagNoApplicationId
  *
  * Verifies that creation of an attested ECDSA key does not include APPLICATION_ID.
@@ -1840,7 +1909,9 @@
  * INVALID_ARGUMENT.
  */
 TEST_P(NewKeyGenerationTest, EcdsaMismatchKeySize) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     auto result = GenerateKey(AuthorizationSetBuilder()
                                       .Authorization(TAG_ALGORITHM, Algorithm::EC)
@@ -2067,7 +2138,9 @@
  * Verifies that keymint rejects HMAC key generation with multiple specified digest algorithms.
  */
 TEST_P(NewKeyGenerationTest, HmacMultipleDigests) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     ASSERT_EQ(ErrorCode::UNSUPPORTED_DIGEST,
               GenerateKey(AuthorizationSetBuilder()
@@ -2291,7 +2364,9 @@
  * presented.
  */
 TEST_P(SigningOperationsTest, NoUserConfirmation) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .RsaSigningKey(1024, 65537)
                                                  .Digest(Digest::NONE)
@@ -2381,7 +2456,9 @@
  * for a 1024-bit key.
  */
 TEST_P(SigningOperationsTest, RsaPssSha512TooSmallKey) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .RsaSigningKey(1024, 65537)
                                                  .Digest(Digest::SHA_2_512)
@@ -3200,7 +3277,9 @@
  * Verifies that importing and using an ECDSA P-521 key pair works correctly.
  */
 TEST_P(ImportKeyTest, Ecdsa521Success) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
     ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
                                                .Authorization(TAG_NO_AUTH_REQUIRED)
                                                .EcdsaSigningKey(EcCurve::P_521)
@@ -3909,7 +3988,9 @@
  * with a different digest than was used to encrypt.
  */
 TEST_P(EncryptionOperationsTest, RsaOaepDecryptWithWrongDigest) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -5823,7 +5904,9 @@
  * Verifies that the max uses per boot tag works correctly with AES keys.
  */
 TEST_P(MaxOperationsTest, TestLimitAes) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -5850,7 +5933,9 @@
  * Verifies that the max uses per boot tag works correctly with RSA keys.
  */
 TEST_P(MaxOperationsTest, TestLimitRsa) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -5881,7 +5966,9 @@
  * Verifies that the usage count limit tag = 1 works correctly with AES keys.
  */
 TEST_P(UsageCountLimitTest, TestSingleUseAes) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -5925,7 +6012,9 @@
  * Verifies that the usage count limit tag > 1 works correctly with AES keys.
  */
 TEST_P(UsageCountLimitTest, TestLimitedUseAes) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -5970,7 +6059,9 @@
  * Verifies that the usage count limit tag = 1 works correctly with RSA keys.
  */
 TEST_P(UsageCountLimitTest, TestSingleUseRsa) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -6014,7 +6105,9 @@
  * Verifies that the usage count limit tag > 1 works correctly with RSA keys.
  */
 TEST_P(UsageCountLimitTest, TestLimitUseRsa) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
                                                  .Authorization(TAG_NO_AUTH_REQUIRED)
@@ -6061,7 +6154,9 @@
  * in hardware.
  */
 TEST_P(UsageCountLimitTest, TestSingleUseKeyAndRollbackResistance) {
-    if (SecLevel() == SecurityLevel::STRONGBOX) return;
+    if (SecLevel() == SecurityLevel::STRONGBOX) {
+        GTEST_SKIP() << "Test not applicable to StrongBox device";
+    }
 
     auto error = GenerateKey(AuthorizationSetBuilder()
                                      .RsaSigningKey(2048, 65537)
@@ -6070,38 +6165,39 @@
                                      .Authorization(TAG_NO_AUTH_REQUIRED)
                                      .Authorization(TAG_ROLLBACK_RESISTANCE)
                                      .SetDefaultValidity());
-    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
-
-    if (error == ErrorCode::OK) {
-        // Rollback resistance is supported by KeyMint, verify it is enforced in hardware.
-        AuthorizationSet hardwareEnforced(SecLevelAuthorizations());
-        ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
-        ASSERT_EQ(ErrorCode::OK, DeleteKey());
-
-        // The KeyMint should also enforce single use key in hardware when it supports rollback
-        // resistance.
-        ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
-                                                     .Authorization(TAG_NO_AUTH_REQUIRED)
-                                                     .RsaSigningKey(1024, 65537)
-                                                     .NoDigestOrPadding()
-                                                     .Authorization(TAG_USAGE_COUNT_LIMIT, 1)
-                                                     .SetDefaultValidity()));
-
-        // Check the usage count limit tag appears in the hardware authorizations.
-        AuthorizationSet hardware_auths = HwEnforcedAuthorizations(key_characteristics_);
-        EXPECT_TRUE(hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U))
-                << "key usage count limit " << 1U << " missing";
-
-        string message = "1234567890123456";
-        auto params = AuthorizationSetBuilder().NoDigestOrPadding();
-
-        // First usage of RSA key should work.
-        SignMessage(message, params);
-
-        // Usage count limit tag is enforced by hardware. After using the key, the key blob
-        // must be invalidated from secure storage (such as RPMB partition).
-        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::SIGN, params));
+    if (error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE) {
+        GTEST_SKIP() << "Rollback resistance not supported";
     }
+
+    // Rollback resistance is supported by KeyMint, verify it is enforced in hardware.
+    ASSERT_EQ(ErrorCode::OK, error);
+    AuthorizationSet hardwareEnforced(SecLevelAuthorizations());
+    ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_EQ(ErrorCode::OK, DeleteKey());
+
+    // The KeyMint should also enforce single use key in hardware when it supports rollback
+    // resistance.
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                                 .Authorization(TAG_NO_AUTH_REQUIRED)
+                                                 .RsaSigningKey(1024, 65537)
+                                                 .NoDigestOrPadding()
+                                                 .Authorization(TAG_USAGE_COUNT_LIMIT, 1)
+                                                 .SetDefaultValidity()));
+
+    // Check the usage count limit tag appears in the hardware authorizations.
+    AuthorizationSet hardware_auths = HwEnforcedAuthorizations(key_characteristics_);
+    EXPECT_TRUE(hardware_auths.Contains(TAG_USAGE_COUNT_LIMIT, 1U))
+            << "key usage count limit " << 1U << " missing";
+
+    string message = "1234567890123456";
+    auto params = AuthorizationSetBuilder().NoDigestOrPadding();
+
+    // First usage of RSA key should work.
+    SignMessage(message, params);
+
+    // Usage count limit tag is enforced by hardware. After using the key, the key blob
+    // must be invalidated from secure storage (such as RPMB partition).
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB, Begin(KeyPurpose::SIGN, params));
 }
 
 INSTANTIATE_KEYMINT_AIDL_TEST(UsageCountLimitTest);
@@ -6178,24 +6274,25 @@
                                      .Authorization(TAG_NO_AUTH_REQUIRED)
                                      .Authorization(TAG_ROLLBACK_RESISTANCE)
                                      .SetDefaultValidity());
-    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+    if (error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE) {
+        GTEST_SKIP() << "Rollback resistance not supported";
+    }
 
     // Delete must work if rollback protection is implemented
-    if (error == ErrorCode::OK) {
-        AuthorizationSet hardwareEnforced(SecLevelAuthorizations());
-        ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_EQ(ErrorCode::OK, error);
+    AuthorizationSet hardwareEnforced(SecLevelAuthorizations());
+    ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
 
-        ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */));
+    ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */));
 
-        string message = "12345678901234567890123456789012";
-        AuthorizationSet begin_out_params;
-        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
-                  Begin(KeyPurpose::SIGN, key_blob_,
-                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
-                        &begin_out_params));
-        AbortIfNeeded();
-        key_blob_ = AidlBuf();
-    }
+    string message = "12345678901234567890123456789012";
+    AuthorizationSet begin_out_params;
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              Begin(KeyPurpose::SIGN, key_blob_,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+                    &begin_out_params));
+    AbortIfNeeded();
+    key_blob_ = AidlBuf();
 }
 
 /**
@@ -6212,21 +6309,22 @@
                                      .Authorization(TAG_NO_AUTH_REQUIRED)
                                      .Authorization(TAG_ROLLBACK_RESISTANCE)
                                      .SetDefaultValidity());
-    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+    if (error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE) {
+        GTEST_SKIP() << "Rollback resistance not supported";
+    }
 
     // Delete must work if rollback protection is implemented
-    if (error == ErrorCode::OK) {
-        AuthorizationSet enforced(SecLevelAuthorizations());
-        ASSERT_TRUE(enforced.Contains(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_EQ(ErrorCode::OK, error);
+    AuthorizationSet enforced(SecLevelAuthorizations());
+    ASSERT_TRUE(enforced.Contains(TAG_ROLLBACK_RESISTANCE));
 
-        // Delete the key we don't care about the result at this point.
-        DeleteKey();
+    // Delete the key we don't care about the result at this point.
+    DeleteKey();
 
-        // Now create an invalid key blob and delete it.
-        key_blob_ = AidlBuf("just some garbage data which is not a valid key blob");
+    // Now create an invalid key blob and delete it.
+    key_blob_ = AidlBuf("just some garbage data which is not a valid key blob");
 
-        ASSERT_EQ(ErrorCode::OK, DeleteKey());
-    }
+    ASSERT_EQ(ErrorCode::OK, DeleteKey());
 }
 
 /**
@@ -6241,7 +6339,10 @@
  * credentials stored in Keystore/Keymint.
  */
 TEST_P(KeyDeletionTest, DeleteAllKeys) {
-    if (!arm_deleteAllKeys) return;
+    if (!arm_deleteAllKeys) {
+        GTEST_SKIP() << "Option --arm_deleteAllKeys not set";
+        return;
+    }
     auto error = GenerateKey(AuthorizationSetBuilder()
                                      .RsaSigningKey(2048, 65537)
                                      .Digest(Digest::NONE)
@@ -6249,25 +6350,26 @@
                                      .Authorization(TAG_NO_AUTH_REQUIRED)
                                      .Authorization(TAG_ROLLBACK_RESISTANCE)
                                      .SetDefaultValidity());
-    ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
+    if (error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE) {
+        GTEST_SKIP() << "Rollback resistance not supported";
+    }
 
     // Delete must work if rollback protection is implemented
-    if (error == ErrorCode::OK) {
-        AuthorizationSet hardwareEnforced(SecLevelAuthorizations());
-        ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
+    ASSERT_EQ(ErrorCode::OK, error);
+    AuthorizationSet hardwareEnforced(SecLevelAuthorizations());
+    ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
 
-        ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
+    ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
 
-        string message = "12345678901234567890123456789012";
-        AuthorizationSet begin_out_params;
+    string message = "12345678901234567890123456789012";
+    AuthorizationSet begin_out_params;
 
-        EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
-                  Begin(KeyPurpose::SIGN, key_blob_,
-                        AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
-                        &begin_out_params));
-        AbortIfNeeded();
-        key_blob_ = AidlBuf();
-    }
+    EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
+              Begin(KeyPurpose::SIGN, key_blob_,
+                    AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
+                    &begin_out_params));
+    AbortIfNeeded();
+    key_blob_ = AidlBuf();
 }
 
 INSTANTIATE_KEYMINT_AIDL_TEST(KeyDeletionTest);
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 6561c92..6e82b8b 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -104,7 +104,7 @@
 
     uint32_t frequency = settings.dvbt().frequency;
     if (type == FrontendScanType::SCAN_BLIND) {
-        frequency += 100;
+        frequency += 100 * 1000;
     }
     msg.frequencies({frequency});
     mCallback->onScanMessage(FrontendScanMessageType::FREQUENCY, msg);
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index c4f610e..2157bdf 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -175,8 +175,8 @@
     // assign randomly selected values for testing.
     info = {
             .type = mFrontends[frontendId]->getFrontendType(),
-            .minFrequency = 139,
-            .maxFrequency = 1139,
+            .minFrequency = 139000000,
+            .maxFrequency = 1139000000,
             .minSymbolRate = 45,
             .maxSymbolRate = 1145,
             .acquireRange = 30,
diff --git a/tv/tuner/1.0/vts/functional/DvrTests.cpp b/tv/tuner/1.0/vts/functional/DvrTests.cpp
index 599abfb..83f9858 100644
--- a/tv/tuner/1.0/vts/functional/DvrTests.cpp
+++ b/tv/tuner/1.0/vts/functional/DvrTests.cpp
@@ -124,11 +124,9 @@
     while (mDataOutputBuffer.empty()) {
         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
             EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
-            stopRecordThread();
             return;
         }
     }
-    stopRecordThread();
     ALOGW("[vts] record pass and stop");
 }
 
@@ -193,9 +191,10 @@
 bool DvrCallback::readRecordFMQ() {
     android::Mutex::Autolock autoLock(mMsgLock);
     bool result = false;
+    int readSize = mRecordMQ->availableToRead();
     mDataOutputBuffer.clear();
-    mDataOutputBuffer.resize(mRecordMQ->availableToRead());
-    result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
+    mDataOutputBuffer.resize(readSize);
+    result = mRecordMQ->read(mDataOutputBuffer.data(), readSize);
     EXPECT_TRUE(result) << "can't read from Record MQ";
     mMsgCondition.signal();
     return result;
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
index 62ac6f7..ba66595 100644
--- a/tv/tuner/1.0/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
@@ -85,7 +85,7 @@
         // passed in means the real input config on the transponder connected to the DUT.
         // We want the blind the test to start from lower frequency than this to check the blind
         // scan implementation.
-        resetBlindScanStartingFrequency(config, targetFrequency - 100);
+        resetBlindScanStartingFrequency(config, targetFrequency - 100 * 1000);
     }
 
     Result result = frontend->scan(config.settings, type);
@@ -415,7 +415,6 @@
 
 void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
     ASSERT_TRUE(getFrontendIds());
-    ASSERT_TRUE(mFeIds.size() > 0);
     for (size_t i = 0; i < mFeIds.size(); i++) {
         ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
         if (mFrontendInfo.type != feType) {
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
index 2cea181..008879d 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -68,7 +68,7 @@
     // without overriding in the xml config.
     string defaultFeId = "FE_DEFAULT";
     FrontendDvbtSettings dvbtSettings{
-            .frequency = 578000,
+            .frequency = 578000000,
             .transmissionMode = FrontendDvbtTransmissionMode::AUTO,
             .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
             .isHighPriority = true,
diff --git a/tv/tuner/1.1/default/Frontend.cpp b/tv/tuner/1.1/default/Frontend.cpp
index e3fbdad..f5463a9 100644
--- a/tv/tuner/1.1/default/Frontend.cpp
+++ b/tv/tuner/1.1/default/Frontend.cpp
@@ -128,7 +128,7 @@
     }
 
     if (type == FrontendScanType::SCAN_BLIND) {
-        frequency += 100;
+        frequency += 100 * 1000;
     }
 
     msg.frequencies({frequency});
diff --git a/tv/tuner/1.1/default/Tuner.cpp b/tv/tuner/1.1/default/Tuner.cpp
index 1e940ba..6d94fbd 100644
--- a/tv/tuner/1.1/default/Tuner.cpp
+++ b/tv/tuner/1.1/default/Tuner.cpp
@@ -264,8 +264,8 @@
     // assign randomly selected values for testing.
     info = {
             .type = mFrontends[frontendId]->getFrontendType(),
-            .minFrequency = 139,
-            .maxFrequency = 1139,
+            .minFrequency = 139000000,
+            .maxFrequency = 1139000000,
             .minSymbolRate = 45,
             .maxSymbolRate = 1145,
             .acquireRange = 30,
diff --git a/tv/tuner/1.1/vts/functional/AndroidTest.xml b/tv/tuner/1.1/vts/functional/AndroidTest.xml
index 3e6878c..848cfc0 100644
--- a/tv/tuner/1.1/vts/functional/AndroidTest.xml
+++ b/tv/tuner/1.1/vts/functional/AndroidTest.xml
@@ -24,6 +24,7 @@
         <option name="cleanup" value="true" />
         <option name="push" value="VtsHalTvTunerV1_1TargetTest->/data/local/tmp/VtsHalTvTunerV1_1TargetTest" />
         <option name="push" value="test.es->/data/local/tmp/test.es" />
+        <option name="push" value="segment000000.ts->/data/local/tmp/segment000000.ts" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
diff --git a/tv/tuner/1.1/vts/functional/DvrTests.cpp b/tv/tuner/1.1/vts/functional/DvrTests.cpp
index 1e478f5..e40e7fd 100644
--- a/tv/tuner/1.1/vts/functional/DvrTests.cpp
+++ b/tv/tuner/1.1/vts/functional/DvrTests.cpp
@@ -123,11 +123,9 @@
     while (mDataOutputBuffer.empty()) {
         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
             EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
-            stopRecordThread();
             return;
         }
     }
-    stopRecordThread();
     ALOGW("[vts] record pass and stop");
 }
 
@@ -204,6 +202,7 @@
 void DvrCallback::stopRecordThread() {
     mKeepReadingRecordFMQ = false;
     mRecordThreadRunning = false;
+    android::Mutex::Autolock autoLock(mRecordThreadLock);
 }
 
 AssertionResult DvrTests::openDvrInDemux(DvrType type, uint32_t bufferSize) {
diff --git a/tv/tuner/1.1/vts/functional/FrontendTests.cpp b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
index 9c0933e..bc57821 100644
--- a/tv/tuner/1.1/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/1.1/vts/functional/FrontendTests.cpp
@@ -136,7 +136,7 @@
         // passed in means the real input config on the transponder connected to the DUT.
         // We want the blind the test to start from lower frequency than this to check the blind
         // scan implementation.
-        resetBlindScanStartingFrequency(config, targetFrequency - 100);
+        resetBlindScanStartingFrequency(config, targetFrequency - 100 * 1000);
     }
 
     Result result = frontend_1_1->scan_1_1(config.config1_0.settings, type, config.settingsExt1_1);
@@ -474,7 +474,6 @@
 
 void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
     ASSERT_TRUE(getFrontendIds());
-    ASSERT_TRUE(mFeIds.size() > 0);
     for (size_t i = 0; i < mFeIds.size(); i++) {
         ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
         if (mFrontendInfo.type != feType) {
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
index 2b5ad46..669fa11 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TestConfigurations.h
@@ -73,7 +73,7 @@
     // without overriding in the xml config.
     string defaultFeId = "FE_DEFAULT";
     FrontendDvbtSettings dvbtSettings{
-            .frequency = 578000,
+            .frequency = 578000000,
             .transmissionMode = FrontendDvbtTransmissionMode::AUTO,
             .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
             .isHighPriority = true,
diff --git a/tv/tuner/aidl/default/Frontend.cpp b/tv/tuner/aidl/default/Frontend.cpp
index 660d0bb..f9e697e 100644
--- a/tv/tuner/aidl/default/Frontend.cpp
+++ b/tv/tuner/aidl/default/Frontend.cpp
@@ -128,7 +128,7 @@
     }
 
     if (in_type == FrontendScanType::SCAN_BLIND) {
-        frequency += 100;
+        frequency += 100 * 1000;
     }
 
     {
diff --git a/tv/tuner/aidl/default/Tuner.cpp b/tv/tuner/aidl/default/Tuner.cpp
index 678be54..8468929 100644
--- a/tv/tuner/aidl/default/Tuner.cpp
+++ b/tv/tuner/aidl/default/Tuner.cpp
@@ -252,8 +252,8 @@
     // assign randomly selected values for testing.
     *_aidl_return = {
             .type = mFrontends[in_frontendId]->getFrontendType(),
-            .minFrequency = 139,
-            .maxFrequency = 1139,
+            .minFrequency = 139000000,
+            .maxFrequency = 1139000000,
             .minSymbolRate = 45,
             .maxSymbolRate = 1145,
             .acquireRange = 30,
diff --git a/tv/tuner/aidl/vts/functional/AndroidTest.xml b/tv/tuner/aidl/vts/functional/AndroidTest.xml
index f93ed78..a849e5a 100644
--- a/tv/tuner/aidl/vts/functional/AndroidTest.xml
+++ b/tv/tuner/aidl/vts/functional/AndroidTest.xml
@@ -24,6 +24,7 @@
         <option name="cleanup" value="true" />
         <option name="push" value="VtsHalTvTunerTargetTest->/data/local/tmp/VtsHalTvTunerTargetTest" />
         <option name="push" value="test.es->/data/local/tmp/test.es" />
+        <option name="push" value="segment000000.ts->/data/local/tmp/segment000000.ts" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
diff --git a/tv/tuner/aidl/vts/functional/FrontendTests.cpp b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
index 7dce4fb..77add8e 100644
--- a/tv/tuner/aidl/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/aidl/vts/functional/FrontendTests.cpp
@@ -126,7 +126,7 @@
         // passed in means the real input config on the transponder connected to the DUT.
         // We want the blind the test to start from lower frequency than this to check the blind
         // scan implementation.
-        resetBlindScanStartingFrequency(config, targetFrequency - 100);
+        resetBlindScanStartingFrequency(config, targetFrequency - 100 * 1000);
     }
 
     ndk::ScopedAStatus result = frontend->scan(config.settings, type);
@@ -446,7 +446,6 @@
 
 void FrontendTests::getFrontendIdByType(FrontendType feType, int32_t& feId) {
     ASSERT_TRUE(getFrontendIds());
-    ASSERT_TRUE(mFeIds.size() > 0);
     for (size_t i = 0; i < mFeIds.size(); i++) {
         ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
         if (mFrontendInfo.type != feType) {
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
index b4fb54f..006bf17 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
@@ -81,7 +81,7 @@
     // without overriding in the xml config.
     string defaultFeId = "FE_DEFAULT";
     FrontendDvbtSettings dvbtSettings{
-            .frequency = 578000,
+            .frequency = 578000000,
             .transmissionMode = FrontendDvbtTransmissionMode::AUTO,
             .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
             .isHighPriority = true,
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index b411011..08270d6 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -998,6 +998,7 @@
         if (!feConfig.hasConnectToCicamId()) {
             canConnectToCiCam = false;
             ciCamId = -1;
+            return;
         }
         canConnectToCiCam = true;
         ciCamId = static_cast<int32_t>(feConfig.getConnectToCicamId());
diff --git a/tv/tuner/config/TunerTestingConfigReaderV1_1.h b/tv/tuner/config/TunerTestingConfigReaderV1_1.h
index 13d5303..c87980d 100644
--- a/tv/tuner/config/TunerTestingConfigReaderV1_1.h
+++ b/tv/tuner/config/TunerTestingConfigReaderV1_1.h
@@ -145,6 +145,7 @@
         if (!feConfig.hasConnectToCicamId()) {
             canConnectToCiCam = false;
             ciCamId = -1;
+            return;
         }
         canConnectToCiCam = true;
         ciCamId = static_cast<uint32_t>(feConfig.getConnectToCicamId());
diff --git a/tv/tuner/config/sample_tuner_vts_config_1_0.xml b/tv/tuner/config/sample_tuner_vts_config_1_0.xml
index 347e984..e880bcd 100644
--- a/tv/tuner/config/sample_tuner_vts_config_1_0.xml
+++ b/tv/tuner/config/sample_tuner_vts_config_1_0.xml
@@ -53,14 +53,14 @@
         -->
         <frontends>
             <frontend id="FE_DEFAULT" type="DVBT" isSoftwareFrontend="true"
-                      connectToCicamId="0" frequency="578000" endFrequency="800000">
+                      connectToCicamId="0" frequency="578000000" endFrequency="800000000">
                 <dvbtFrontendSettings bandwidth="8" transmissionMode="1" isHighPriority="1"
                                       constellation="1" hierarchy="1" hpCoderate="1" lpCoderate="1"
                                       guardInterval="1" standard="1" isMiso="0" plpMode="1"
                                       plpId="0" plpGroupId="0"/>
             </frontend>
             <frontend id="FE_DVBS_0" type="DVBS" isSoftwareFrontend="true"
-                      connectToCicamId="0" frequency="578000" endFrequency="800000">
+                      connectToCicamId="0" frequency="578000000" endFrequency="800000000">
             </frontend>
         </frontends>
         <!-- Filter section:
diff --git a/tv/tuner/config/sample_tuner_vts_config_1_1.xml b/tv/tuner/config/sample_tuner_vts_config_1_1.xml
index 8c99207..55ce0ec 100644
--- a/tv/tuner/config/sample_tuner_vts_config_1_1.xml
+++ b/tv/tuner/config/sample_tuner_vts_config_1_1.xml
@@ -53,11 +53,11 @@
         -->
         <frontends>
             <frontend id="FE_DEFAULT" type="DVBT" isSoftwareFrontend="true"
-                      connectToCicamId="0" frequency="578000" endFrequency="800000">
+                      connectToCicamId="0" frequency="578000000" endFrequency="800000000">
                 <dvbtFrontendSettings bandwidth="8" transmissionMode="128" isHighPriority="1"/>
             </frontend>
             <frontend id="FE_DVBS_0" type="DVBS" isSoftwareFrontend="true"
-                      connectToCicamId="0" frequency="578000" endFrequency="800000">
+                      connectToCicamId="0" frequency="578000000" endFrequency="800000000">
             </frontend>
         </frontends>
         <!-- Filter section:
diff --git a/uwb/aidl/Android.bp b/uwb/aidl/Android.bp
index 5d21753..0d1ebc2 100755
--- a/uwb/aidl/Android.bp
+++ b/uwb/aidl/Android.bp
@@ -17,6 +17,7 @@
     backend: {
         java: {
             sdk_version: "module_current",
+            enabled: false,
         },
         ndk: {
             vndk: {
@@ -37,3 +38,29 @@
         },
     },
 }
+
+aidl_interface {
+    name: "android.hardware.uwb.fira_android",
+    vendor_available: true,
+    srcs: ["android/hardware/uwb/fira_android/*.aidl"],
+    stability: "vintf",
+    backend: {
+        java: {
+            sdk_version: "module_current",
+            enabled: true,
+            apex_available: [
+                "com.android.uwb",
+            ],
+        },
+        ndk: {
+            vndk: {
+                enabled: true,
+            },
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.uwb",
+            ],
+            min_sdk_version: "current",
+        },
+    },
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
new file mode 100644
index 0000000..b0d88e0
--- /dev/null
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGids.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.uwb.fira_android;
+@Backing(type="byte") @VintfStability
+enum UwbVendorGids {
+  ANDROID = 14,
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
new file mode 100644
index 0000000..37b7efb
--- /dev/null
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+//     the interface (from the latest frozen version), the build system will
+//     prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.uwb.fira_android;
+@Backing(type="int") @VintfStability
+enum UwbVendorSessionSetAppConfigCmdParams {
+  CCC_RANGING_PROTOCOL_VER = 163,
+  CCC_UWB_CONFIG_ID = 164,
+  CCC_PULSESHAPE_COMBO = 165,
+  CCC_URSK_TTL = 166,
+}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/README.md b/uwb/aidl/android/hardware/uwb/fira_android/README.md
new file mode 100644
index 0000000..e658d93
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/README.md
@@ -0,0 +1,15 @@
+The `android.hardware.uwb.fira_android` package is used to add any Android specific
+additions to the UCI specification defined by FIRA standards body. These
+additions should be added to the vendor specific portions carved out in the UCI
+specification.
+
+These include:
+ - Android specific GIDs/OIDs for commands/responses/notifications.
+ - Andriod specific params in an existing UCI specified command/response/notification.
+
+All other interactions sent/received over the HAL interface is expected to
+comply with the UCI specification that can be found [here](
+https://groups.firaconsortium.org/wg/Technical/document/folder/127).
+
+TODO([b/196004116](b/196004116)): Link to the published specification.
+
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl
new file mode 100644
index 0000000..c7bc6b0
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGids.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific vendor command GIDs (Group ID) should be defined here.
+ *
+ * For each vendor GID defined here, also create a corresponding AIDL file enumerating the
+ * OIDs (Opcode Identifier) allowed within that GID.
+ * For ex: VENDOR_GID_XXX = 1110b -> UwbVendorGidXXXOids.aidl
+ */
+@VintfStability
+@Backing(type="byte")
+enum UwbVendorGids {
+    /**
+     * Use values from the Proprietary Group range: 1110b – 1111b defined in Table 36 of
+     * UCI specification.
+     */
+
+    /** All Android specific commands/response/notification should use this GID */
+    ANDROID = 0xE,
+}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
new file mode 100644
index 0000000..850e2da
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorSessionSetAppConfigCmdParams.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific vendor app params set in UCI command:
+ * GID: 0001b (UWB Session config Group)
+ * OID: 000011b (SESSION_SET_APP_CONFIG_CMD)
+ *
+ * Note: Refer to Table 34 of the UCI specification for the other params
+ * expected in this command.
+ */
+@VintfStability
+@Backing(type="int")
+enum UwbVendorSessionSetAppConfigCmdParams {
+    /** CCC params for ranging start */
+
+    /** Added in vendor version 0. */
+    CCC_RANGING_PROTOCOL_VER = 0xA3,
+    CCC_UWB_CONFIG_ID = 0xA4,
+    CCC_PULSESHAPE_COMBO = 0xA5,
+    CCC_URSK_TTL = 0xA6,
+}
diff --git a/vibrator/1.0/vts/OWNERS b/vibrator/1.0/vts/OWNERS
new file mode 100644
index 0000000..75b9a4b
--- /dev/null
+++ b/vibrator/1.0/vts/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 345036
+michaelwr@google.com
+leungv@google.com
diff --git a/vibrator/1.1/vts/OWNERS b/vibrator/1.1/vts/OWNERS
new file mode 100644
index 0000000..44bfe56
--- /dev/null
+++ b/vibrator/1.1/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 345036
+include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.2/vts/OWNERS b/vibrator/1.2/vts/OWNERS
new file mode 100644
index 0000000..44bfe56
--- /dev/null
+++ b/vibrator/1.2/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 345036
+include ../../1.0/vts/OWNERS
diff --git a/vibrator/1.3/vts/OWNERS b/vibrator/1.3/vts/OWNERS
new file mode 100644
index 0000000..44bfe56
--- /dev/null
+++ b/vibrator/1.3/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 345036
+include ../../1.0/vts/OWNERS
diff --git a/vibrator/aidl/OWNERS b/vibrator/aidl/OWNERS
index e3d7e6b..ae10db6 100644
--- a/vibrator/aidl/OWNERS
+++ b/vibrator/aidl/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 345036
 include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
 chasewu@google.com
 leungv@google.com
diff --git a/wifi/1.0/vts/OWNERS b/wifi/1.0/vts/OWNERS
index cf81c79..287152d 100644
--- a/wifi/1.0/vts/OWNERS
+++ b/wifi/1.0/vts/OWNERS
@@ -1,2 +1,3 @@
+# Bug component: 33618
 arabawy@google.com
 etancohen@google.com
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index e4948b4..6c0ebf7 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -107,8 +107,10 @@
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
         "android.hardware.wifi@1.0",
+        "android.hardware.wifi.hostapd@1.0",
         "libwifi-system-iface",
     ],
+    disable_framework: true,
     test_suites: [
         "general-tests",
         "vts",
diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
index 96b4501..28b1616 100644
--- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -15,9 +15,9 @@
  */
 
 #include <android-base/logging.h>
-
 #include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiApIface.h>
+#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -26,6 +26,7 @@
 #include "wifi_hidl_test_utils.h"
 
 using ::android::sp;
+using ::android::hardware::wifi::hostapd::V1_0::IHostapd;
 using ::android::hardware::wifi::V1_0::IfaceType;
 using ::android::hardware::wifi::V1_0::IWifi;
 using ::android::hardware::wifi::V1_0::IWifiApIface;
@@ -38,6 +39,10 @@
 class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        if (android::hardware::getAllHalInstanceNames(IHostapd::descriptor)
+                .empty()) {
+            GTEST_SKIP() << "Device does not support AP";
+        }
         // Make sure test starts with a clean state
         stopWifi(GetInstanceName());
 
diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
index 2e6ad32..66e1a80 100644
--- a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp
@@ -15,9 +15,9 @@
  */
 
 #include <android-base/logging.h>
-
 #include <android/hardware/wifi/1.0/IWifi.h>
 #include <android/hardware/wifi/1.0/IWifiChip.h>
+#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -26,6 +26,7 @@
 #include "wifi_hidl_test_utils.h"
 
 using ::android::sp;
+using ::android::hardware::wifi::hostapd::V1_0::IHostapd;
 using ::android::hardware::wifi::V1_0::ChipModeId;
 using ::android::hardware::wifi::V1_0::IfaceType;
 using ::android::hardware::wifi::V1_0::IWifi;
@@ -41,6 +42,10 @@
 class WifiChipHidlApTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        if (android::hardware::getAllHalInstanceNames(IHostapd::descriptor)
+                .empty()) {
+            GTEST_SKIP() << "Device does not support AP";
+        }
         // Make sure test starts with a clean state
         stopWifi(GetInstanceName());
 
diff --git a/wifi/1.1/vts/OWNERS b/wifi/1.1/vts/OWNERS
index cf81c79..294fc82 100644
--- a/wifi/1.1/vts/OWNERS
+++ b/wifi/1.1/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.0/vts/OWNERS
diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp
index 8048642..a8f3470 100644
--- a/wifi/1.1/vts/functional/Android.bp
+++ b/wifi/1.1/vts/functional/Android.bp
@@ -39,6 +39,7 @@
         "android.hardware.wifi@1.5",
         "libwifi-system-iface",
     ],
+    disable_framework: true,
     test_suites: [
         "general-tests",
         "vts",
diff --git a/wifi/1.2/vts/OWNERS b/wifi/1.2/vts/OWNERS
index cf81c79..294fc82 100644
--- a/wifi/1.2/vts/OWNERS
+++ b/wifi/1.2/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.0/vts/OWNERS
diff --git a/wifi/1.3/vts/OWNERS b/wifi/1.3/vts/OWNERS
index cf81c79..294fc82 100644
--- a/wifi/1.3/vts/OWNERS
+++ b/wifi/1.3/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.0/vts/OWNERS
diff --git a/wifi/1.4/vts/OWNERS b/wifi/1.4/vts/OWNERS
index cf81c79..294fc82 100644
--- a/wifi/1.4/vts/OWNERS
+++ b/wifi/1.4/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.0/vts/OWNERS
diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp
index 14ebbe3..f86869b 100644
--- a/wifi/1.4/vts/functional/Android.bp
+++ b/wifi/1.4/vts/functional/Android.bp
@@ -14,7 +14,6 @@
 // limitations under the License.
 //
 
-// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest.
 package {
     // See: http://go/android-license-faq
     // A large-scale-change added 'default_applicable_licenses' to import
@@ -25,10 +24,9 @@
 }
 
 cc_test {
-    name: "VtsHalWifiApV1_4TargetTest",
+    name: "VtsHalWifiV1_4TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "wifi_ap_iface_hidl_test.cpp",
         "wifi_chip_hidl_test.cpp",
     ],
     static_libs: [
@@ -46,6 +44,30 @@
     ],
 }
 
+// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest.
+cc_test {
+    name: "VtsHalWifiApV1_4TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "wifi_ap_iface_hidl_test.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+        "android.hardware.wifi@1.4",
+        "android.hardware.wifi.hostapd@1.0",
+        "libwifi-system-iface",
+    ],
+    disable_framework: true,
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
+}
+
 // These tests are split out so that they can be conditioned on presence of the
 // "android.hardware.wifi.aware" feature.
 cc_test {
diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
index 5b0f173..756afa5 100644
--- a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
+++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp
@@ -16,6 +16,7 @@
 
 #include <android/hardware/wifi/1.4/IWifi.h>
 #include <android/hardware/wifi/1.4/IWifiApIface.h>
+#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
 #include <hidl/ServiceManagement.h>
@@ -25,6 +26,7 @@
 
 using ::android::sp;
 using ::android::hardware::hidl_array;
+using ::android::hardware::wifi::hostapd::V1_0::IHostapd;
 using ::android::hardware::wifi::V1_0::WifiStatus;
 using ::android::hardware::wifi::V1_0::WifiStatusCode;
 using ::android::hardware::wifi::V1_4::IWifi;
@@ -36,6 +38,10 @@
 class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
+        if (android::hardware::getAllHalInstanceNames(IHostapd::descriptor)
+                .empty()) {
+            GTEST_SKIP() << "Device does not support AP";
+        }
         // Make sure to start with a clean state
         stopWifi(GetInstanceName());
 
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index 82d794c..6bdff42 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -28,6 +28,8 @@
 #include "wifi_chip.h"
 #include "wifi_status_util.h"
 
+#define P2P_MGMT_DEVICE_PREFIX "p2p-dev-"
+
 namespace {
 using android::sp;
 using android::base::unique_fd;
@@ -126,8 +128,37 @@
 }
 
 std::string getPredefinedP2pIfaceName() {
+    std::array<char, PROPERTY_VALUE_MAX> primaryIfaceName;
+    char p2pParentIfname[100];
+    std::string p2pDevIfName = "";
     std::array<char, PROPERTY_VALUE_MAX> buffer;
     property_get("wifi.direct.interface", buffer.data(), "p2p0");
+    if (strncmp(buffer.data(), P2P_MGMT_DEVICE_PREFIX,
+                strlen(P2P_MGMT_DEVICE_PREFIX)) == 0) {
+        /* Get the p2p parent interface name from p2p device interface name set
+         * in property */
+        strncpy(p2pParentIfname, buffer.data() + strlen(P2P_MGMT_DEVICE_PREFIX),
+                strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX));
+        if (property_get(kActiveWlanIfaceNameProperty, primaryIfaceName.data(),
+                         nullptr) == 0) {
+            return buffer.data();
+        }
+        /* Check if the parent interface derived from p2p device interface name
+         * is active */
+        if (strncmp(p2pParentIfname, primaryIfaceName.data(),
+                    strlen(buffer.data()) - strlen(P2P_MGMT_DEVICE_PREFIX)) !=
+            0) {
+            /*
+             * Update the predefined p2p device interface parent interface name
+             * with current active wlan interface
+             */
+            p2pDevIfName += P2P_MGMT_DEVICE_PREFIX;
+            p2pDevIfName += primaryIfaceName.data();
+            LOG(INFO) << "update the p2p device interface name to "
+                      << p2pDevIfName.c_str();
+            return p2pDevIfName;
+        }
+    }
     return buffer.data();
 }
 
diff --git a/wifi/1.5/default/wifi_iface_util.cpp b/wifi/1.5/default/wifi_iface_util.cpp
index 7bf830b..0977026 100644
--- a/wifi/1.5/default/wifi_iface_util.cpp
+++ b/wifi/1.5/default/wifi_iface_util.cpp
@@ -56,14 +56,21 @@
 bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
                                   const std::array<uint8_t, 6>& mac) {
 #ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
-    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
+    legacy_hal::wifi_error legacy_status;
+    uint64_t legacy_feature_set;
+    std::tie(legacy_status, legacy_feature_set) =
+        legacy_hal_.lock()->getSupportedFeatureSet(iface_name);
+
+    if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+        !iface_tool_.lock()->SetUpState(iface_name.c_str(), false)) {
         LOG(ERROR) << "SetUpState(false) failed.";
         return false;
     }
 #endif
     bool success = iface_tool_.lock()->SetMacAddress(iface_name.c_str(), mac);
 #ifndef WIFI_AVOID_IFACE_RESET_MAC_CHANGE
-    if (!iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
+    if (!(legacy_feature_set & WIFI_FEATURE_DYNAMIC_SET_MAC) &&
+        !iface_tool_.lock()->SetUpState(iface_name.c_str(), true)) {
         LOG(ERROR) << "SetUpState(true) failed. Wait for driver ready.";
         // Wait for driver ready and try to set iface UP again
         if (legacy_hal_.lock()->waitForDriverReady() !=
diff --git a/wifi/1.5/vts/OWNERS b/wifi/1.5/vts/OWNERS
index cf81c79..294fc82 100644
--- a/wifi/1.5/vts/OWNERS
+++ b/wifi/1.5/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.0/vts/OWNERS
diff --git a/wifi/hostapd/1.0/vts/OWNERS b/wifi/hostapd/1.0/vts/OWNERS
index cf81c79..287152d 100644
--- a/wifi/hostapd/1.0/vts/OWNERS
+++ b/wifi/hostapd/1.0/vts/OWNERS
@@ -1,2 +1,3 @@
+# Bug component: 33618
 arabawy@google.com
 etancohen@google.com
diff --git a/wifi/hostapd/1.1/vts/OWNERS b/wifi/hostapd/1.1/vts/OWNERS
index cf81c79..294fc82 100644
--- a/wifi/hostapd/1.1/vts/OWNERS
+++ b/wifi/hostapd/1.1/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.0/vts/OWNERS
diff --git a/wifi/hostapd/1.2/vts/OWNERS b/wifi/hostapd/1.2/vts/OWNERS
index cf81c79..294fc82 100644
--- a/wifi/hostapd/1.2/vts/OWNERS
+++ b/wifi/hostapd/1.2/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.0/vts/OWNERS
diff --git a/wifi/hostapd/1.3/vts/OWNERS b/wifi/hostapd/1.3/vts/OWNERS
index cf81c79..294fc82 100644
--- a/wifi/hostapd/1.3/vts/OWNERS
+++ b/wifi/hostapd/1.3/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.0/vts/OWNERS
diff --git a/wifi/offload/1.0/vts/OWNERS b/wifi/offload/1.0/vts/OWNERS
new file mode 100644
index 0000000..287152d
--- /dev/null
+++ b/wifi/offload/1.0/vts/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 33618
+arabawy@google.com
+etancohen@google.com
diff --git a/wifi/supplicant/1.0/vts/OWNERS b/wifi/supplicant/1.0/vts/OWNERS
new file mode 100644
index 0000000..b16dc11
--- /dev/null
+++ b/wifi/supplicant/1.0/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 33618
+include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.1/vts/OWNERS b/wifi/supplicant/1.1/vts/OWNERS
new file mode 100644
index 0000000..b16dc11
--- /dev/null
+++ b/wifi/supplicant/1.1/vts/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 33618
+include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.2/vts/OWNERS b/wifi/supplicant/1.2/vts/OWNERS
index cf81c79..b16dc11 100644
--- a/wifi/supplicant/1.2/vts/OWNERS
+++ b/wifi/supplicant/1.2/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.3/vts/OWNERS
diff --git a/wifi/supplicant/1.3/vts/OWNERS b/wifi/supplicant/1.3/vts/OWNERS
index cf81c79..287152d 100644
--- a/wifi/supplicant/1.3/vts/OWNERS
+++ b/wifi/supplicant/1.3/vts/OWNERS
@@ -1,2 +1,3 @@
+# Bug component: 33618
 arabawy@google.com
 etancohen@google.com
diff --git a/wifi/supplicant/1.4/vts/OWNERS b/wifi/supplicant/1.4/vts/OWNERS
index cf81c79..b16dc11 100644
--- a/wifi/supplicant/1.4/vts/OWNERS
+++ b/wifi/supplicant/1.4/vts/OWNERS
@@ -1,2 +1,2 @@
-arabawy@google.com
-etancohen@google.com
+# Bug component: 33618
+include ../../1.3/vts/OWNERS