Add libaudiofoundation.
am: 797b5b45fc

Change-Id: I22ad0dd7e6afecc166fd32201396a1fb5f9afafa
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
index d689e62..8ee3c54 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
@@ -153,7 +153,7 @@
 std::unique_ptr<VehiclePropValue> createAvailabilityRequest();
 
 // Creates a VehiclePropValue containing a message of type
-// VmsMessageType.AVAILABILITY_REQUEST.
+// VmsMessageType.SUBSCRIPTIONS_REQUEST.
 std::unique_ptr<VehiclePropValue> createSubscriptionsRequest();
 
 // Creates a VehiclePropValue containing a message of type VmsMessageType.DATA.
@@ -202,21 +202,21 @@
 
 // Returns true if the new sequence number is greater than the last seen
 // sequence number.
-bool isSequenceNumberNewer(const VehiclePropValue& subscription_change,
+bool isSequenceNumberNewer(const VehiclePropValue& subscriptions_state,
                            const int last_seen_sequence_number);
 
 // Returns sequence number of the message.
-int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscription_change);
+int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscriptions_state);
 
-// Takes a subscription change message and returns the layers that have active
+// Takes a subscriptions state message and returns the layers that have active
 // subscriptions of the layers that are offered by your HAL client/publisher.
 //
-// A publisher can use this function when receiving a subscription change message
-// to determine which layers to publish data on.
+// A publisher can use this function when receiving a subscriptions response or subscriptions
+// change message to determine which layers to publish data on.
 // The caller of this function can optionally decide to not consume these layers
 // if the subscription change has the sequence number less than the last seen
 // sequence number.
-std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscription_change,
+std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscriptions_state,
                                           const VmsOffers& offers);
 
 // Takes an availability change message and returns true if the parsed message implies that
diff --git a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
index d346206..9eba905 100644
--- a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
@@ -194,32 +194,35 @@
     return -1;
 }
 
-bool isSequenceNumberNewer(const VehiclePropValue& subscription_change,
+bool isSequenceNumberNewer(const VehiclePropValue& subscriptions_state,
                            const int last_seen_sequence_number) {
-    return (isValidVmsMessage(subscription_change) &&
-            parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE &&
-            subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex &&
-            subscription_change.value.int32Values[kSubscriptionStateSequenceNumberIndex] >
+    return (isValidVmsMessage(subscriptions_state) &&
+            (parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_CHANGE ||
+             parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_RESPONSE) &&
+            subscriptions_state.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex &&
+            subscriptions_state.value.int32Values[kSubscriptionStateSequenceNumberIndex] >
                     last_seen_sequence_number);
 }
 
-int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscription_change) {
-    if (isValidVmsMessage(subscription_change) &&
-        parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE &&
-        subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
-        return subscription_change.value.int32Values[kSubscriptionStateSequenceNumberIndex];
+int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscriptions_state) {
+    if (isValidVmsMessage(subscriptions_state) &&
+        (parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_CHANGE ||
+         parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_RESPONSE) &&
+        subscriptions_state.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
+        return subscriptions_state.value.int32Values[kSubscriptionStateSequenceNumberIndex];
     }
     return -1;
 }
 
-std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscription_change,
+std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscriptions_state,
                                           const VmsOffers& offers) {
-    if (isValidVmsMessage(subscription_change) &&
-        parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE &&
-        subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
-        const int32_t num_of_layers = subscription_change.value.int32Values[toInt(
+    if (isValidVmsMessage(subscriptions_state) &&
+        (parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_CHANGE ||
+         parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_RESPONSE) &&
+        subscriptions_state.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
+        const int32_t num_of_layers = subscriptions_state.value.int32Values[toInt(
                 VmsSubscriptionsStateIntegerValuesIndex::NUMBER_OF_LAYERS)];
-        const int32_t num_of_associated_layers = subscription_change.value.int32Values[toInt(
+        const int32_t num_of_associated_layers = subscriptions_state.value.int32Values[toInt(
                 VmsSubscriptionsStateIntegerValuesIndex ::NUMBER_OF_ASSOCIATED_LAYERS)];
 
         std::unordered_set<VmsLayer, VmsLayer::VmsLayerHashFunction> offered_layers;
@@ -231,9 +234,9 @@
         int current_index = toInt(VmsSubscriptionsStateIntegerValuesIndex::SUBSCRIPTIONS_START);
         // Add all subscribed layers which are offered by the current publisher.
         for (int i = 0; i < num_of_layers; i++) {
-            VmsLayer layer = VmsLayer(subscription_change.value.int32Values[current_index],
-                                      subscription_change.value.int32Values[current_index + 1],
-                                      subscription_change.value.int32Values[current_index + 2]);
+            VmsLayer layer = VmsLayer(subscriptions_state.value.int32Values[current_index],
+                                      subscriptions_state.value.int32Values[current_index + 1],
+                                      subscriptions_state.value.int32Values[current_index + 2]);
             if (offered_layers.find(layer) != offered_layers.end()) {
                 subscribed_layers.push_back(layer);
             }
@@ -243,15 +246,15 @@
         // For this, we need to check if the associated layer has a publisher ID which is
         // same as that of the current publisher.
         for (int i = 0; i < num_of_associated_layers; i++) {
-            VmsLayer layer = VmsLayer(subscription_change.value.int32Values[current_index],
-                                      subscription_change.value.int32Values[current_index + 1],
-                                      subscription_change.value.int32Values[current_index + 2]);
+            VmsLayer layer = VmsLayer(subscriptions_state.value.int32Values[current_index],
+                                      subscriptions_state.value.int32Values[current_index + 1],
+                                      subscriptions_state.value.int32Values[current_index + 2]);
             current_index += kLayerSize;
             if (offered_layers.find(layer) != offered_layers.end()) {
-                int32_t num_of_publisher_ids = subscription_change.value.int32Values[current_index];
+                int32_t num_of_publisher_ids = subscriptions_state.value.int32Values[current_index];
                 current_index++;
                 for (int j = 0; j < num_of_publisher_ids; j++) {
-                    if (subscription_change.value.int32Values[current_index] ==
+                    if (subscriptions_state.value.int32Values[current_index] ==
                         offers.publisher_id) {
                         subscribed_layers.push_back(layer);
                     }
diff --git a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
index 7189212..8b547f1 100644
--- a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
@@ -214,57 +214,82 @@
     EXPECT_EQ(parsePublisherIdResponse(*message), -1);
 }
 
-TEST(VmsUtilsTest, validSequenceNumberForSubscriptionsState) {
+TEST(VmsUtilsTest, validSequenceNumberForSubscriptionsChange) {
     auto message = createBaseVmsMessage(2);
     message->value.int32Values =
             hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
     EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), 1234);
 }
 
+TEST(VmsUtilsTest, validSequenceNumberForSubscriptionsResponse) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_RESPONSE), 1234};
+    EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), 1234);
+}
+
 TEST(VmsUtilsTest, invalidSubscriptionsState) {
     auto message = createBaseVmsMessage(1);
     EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), -1);
 }
 
-TEST(VmsUtilsTest, newSequenceNumberForExistingSmallerNumber) {
+TEST(VmsUtilsTest, newSequenceNumberForExistingSmallerNumberForChange) {
     auto message = createBaseVmsMessage(2);
     message->value.int32Values =
             hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
     EXPECT_TRUE(isSequenceNumberNewer(*message, 1233));
 }
 
-TEST(VmsUtilsTest, newSequenceNumberForExistingGreaterNumber) {
+TEST(VmsUtilsTest, newSequenceNumberForExistingSmallerNumberForResponse) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_RESPONSE), 1234};
+    EXPECT_TRUE(isSequenceNumberNewer(*message, 1233));
+}
+
+TEST(VmsUtilsTest, newSequenceNumberForExistingGreaterNumberForChange) {
     auto message = createBaseVmsMessage(2);
     message->value.int32Values =
             hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
     EXPECT_FALSE(isSequenceNumberNewer(*message, 1235));
 }
 
-TEST(VmsUtilsTest, newSequenceNumberForSameNumber) {
+TEST(VmsUtilsTest, newSequenceNumberForExistingGreaterNumberForResponse) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_RESPONSE), 1234};
+    EXPECT_FALSE(isSequenceNumberNewer(*message, 1235));
+}
+
+TEST(VmsUtilsTest, newSequenceNumberForSameNumberForChange) {
     auto message = createBaseVmsMessage(2);
     message->value.int32Values =
             hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
     EXPECT_FALSE(isSequenceNumberNewer(*message, 1234));
 }
 
-TEST(VmsUtilsTest, subscribedLayers) {
+TEST(VmsUtilsTest, newSequenceNumberForSameNumberForResponse) {
+    auto message = createBaseVmsMessage(2);
+    message->value.int32Values =
+            hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_RESPONSE), 1234};
+    EXPECT_FALSE(isSequenceNumberNewer(*message, 1234));
+}
+
+void testSubscribedLayers(VmsMessageType type) {
     VmsOffers offers = {123,
                         {VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}),
                          VmsLayerOffering(VmsLayer(2, 0, 1))}};
     auto message = createBaseVmsMessage(2);
-    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+    message->value.int32Values = hidl_vec<int32_t>{toInt(type),
                                                    1234,  // sequence number
                                                    2,     // number of layers
                                                    1,     // number of associated layers
                                                    1,     // layer 1
-                                                   0,
-                                                   1,
+                                                   0,           1,
                                                    4,  // layer 2
-                                                   1,
-                                                   1,
+                                                   1,           1,
                                                    2,  // associated layer
-                                                   0,
-                                                   1,
+                                                   0,           1,
                                                    2,    // number of publisher IDs
                                                    111,  // publisher IDs
                                                    123};
@@ -275,10 +300,18 @@
     EXPECT_EQ(result.at(1), VmsLayer(2, 0, 1));
 }
 
-TEST(VmsUtilsTest, subscribedLayersWithDifferentSubtype) {
+TEST(VmsUtilsTest, subscribedLayersForChange) {
+    testSubscribedLayers(VmsMessageType::SUBSCRIPTIONS_CHANGE);
+}
+
+TEST(VmsUtilsTest, subscribedLayersForResponse) {
+    testSubscribedLayers(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
+}
+
+void testSubscribedLayersWithDifferentSubtype(VmsMessageType type) {
     VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
     auto message = createBaseVmsMessage(2);
-    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+    message->value.int32Values = hidl_vec<int32_t>{toInt(type),
                                                    1234,  // sequence number
                                                    1,     // number of layers
                                                    0,     // number of associated layers
@@ -289,36 +322,58 @@
     EXPECT_TRUE(getSubscribedLayers(*message, offers).empty());
 }
 
-TEST(VmsUtilsTest, subscribedLayersWithDifferentVersion) {
+TEST(VmsUtilsTest, subscribedLayersWithDifferentSubtypeForChange) {
+    testSubscribedLayersWithDifferentSubtype(VmsMessageType::SUBSCRIPTIONS_CHANGE);
+}
+
+TEST(VmsUtilsTest, subscribedLayersWithDifferentSubtypeForResponse) {
+    testSubscribedLayersWithDifferentSubtype(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
+}
+
+void subscribedLayersWithDifferentVersion(VmsMessageType type) {
     VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
     auto message = createBaseVmsMessage(2);
-    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
-                                                   1234,  // sequence number
-                                                   1,     // number of layers
-                                                   0,     // number of associated layers
-                                                   1,     // layer 1
-                                                   0,
-                                                   2};  // different version
+    message->value.int32Values = hidl_vec<int32_t>{toInt(type),
+                                                   1234,             // sequence number
+                                                   1,                // number of layers
+                                                   0,                // number of associated layers
+                                                   1,                // layer 1
+                                                   0,           2};  // different version
     EXPECT_TRUE(isValidVmsMessage(*message));
     EXPECT_TRUE(getSubscribedLayers(*message, offers).empty());
 }
 
-TEST(VmsUtilsTest, subscribedLayersWithDifferentPublisherId) {
+TEST(VmsUtilsTest, subscribedLayersWithDifferentVersionForChange) {
+    subscribedLayersWithDifferentVersion(VmsMessageType::SUBSCRIPTIONS_CHANGE);
+}
+
+TEST(VmsUtilsTest, subscribedLayersWithDifferentVersionForResponse) {
+    subscribedLayersWithDifferentVersion(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
+}
+
+void subscribedLayersWithDifferentPublisherId(VmsMessageType type) {
     VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
     auto message = createBaseVmsMessage(2);
-    message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+    message->value.int32Values = hidl_vec<int32_t>{toInt(type),
                                                    1234,  // sequence number
                                                    0,     // number of layers
                                                    1,     // number of associated layers
                                                    1,     // associated layer 1
-                                                   0,
-                                                   1,
+                                                   0,           1,
                                                    1,     // number of publisher IDs
                                                    234};  // publisher ID 1
     EXPECT_TRUE(isValidVmsMessage(*message));
     EXPECT_TRUE(getSubscribedLayers(*message, offers).empty());
 }
 
+TEST(VmsUtilsTest, subscribedLayersWithDifferentPublisherIdForChange) {
+    subscribedLayersWithDifferentPublisherId(VmsMessageType::SUBSCRIPTIONS_CHANGE);
+}
+
+TEST(VmsUtilsTest, subscribedLayersWithDifferentPublisherIdForResponse) {
+    subscribedLayersWithDifferentPublisherId(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
+}
+
 TEST(VmsUtilsTest, serviceNewlyStarted) {
     auto message = createBaseVmsMessage(2);
     message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_CHANGE), 0};
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index f0b5966..ed88274 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -367,10 +367,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.radio.config</name>
-        <!--
-        See compatibility_matrix.4.xml on versioning of radio config HAL.
-        -->
-        <version>1.1</version>
+        <version>1.3</version>
         <interface>
             <name>IRadioConfig</name>
             <instance>default</instance>
diff --git a/current.txt b/current.txt
index c1991c3..b6ef9dc 100644
--- a/current.txt
+++ b/current.txt
@@ -578,7 +578,7 @@
 9d8ee57c490ffeaa28f702eaea8d198cb510e4bbfb99e6cb5f63e73341057c7c android.hardware.neuralnetworks@1.1::types
 fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
-71c0f7127335e5b74d1615d5e7f129831b43ffbae5318ad0924d7d8d8910a859 android.hardware.neuralnetworks@1.2::types
+72de91c3feba4b19c159cd1c413cbea596b78240caa43e31194e20e6f5b05c49 android.hardware.neuralnetworks@1.2::types
 a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types
 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
 fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
@@ -597,8 +597,12 @@
 9e59fffceed0dd72a9799e04505db5f777bbbea1af0695ba4107ef6d967c6fda android.hardware.neuralnetworks@1.3::IDevice
 4a6c3b3556da951b4def21ba579a227c022980fe4465df6cdfbe20628fa75f5a android.hardware.neuralnetworks@1.3::IPreparedModel
 94e803236398bed1febb11cc21051bc42ec003700139b099d6c479e02a7ca3c3 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-c511b1427b1c3f76af90967bbddaaf250db983a8d3abb9ff189fb5a807cf3d4d android.hardware.neuralnetworks@1.3::types
+554baa3b317e077b850afcbaac99daeef56861b1786540e56275a4fcad1f43e3 android.hardware.neuralnetworks@1.3::types
 274fb1254a6d1a97824ec5c880eeefc0e410dc6d3a2a4c34052201169d2b7de0 android.hardware.radio@1.5::types
 c8e81d912827a5d49b2ddcdc4eb4556c5d231a899a1dca879309e04210daa4a0 android.hardware.radio@1.5::IRadio
 a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication
 260ce05806d753d728f844d405e832179ed7d9b65986ec18fef3d21cf7285587 android.hardware.radio@1.5::IRadioResponse
+55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
+b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
+742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
+7683fed9d253956071f18b152e6be657719536f98d9b534433d5e411bcde5061 android.hardware.radio.config@1.3::IRadioConfigResponse
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index 666653b..8ddc380 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -101,11 +101,20 @@
         std::unique_ptr<android::CryptoPlugin::SubSample[]> legacySubSamples =
                 std::make_unique<android::CryptoPlugin::SubSample[]>(subSamples.size());
 
+        size_t destSize = 0;
         for (size_t i = 0; i < subSamples.size(); i++) {
-            legacySubSamples[i].mNumBytesOfClearData
-                = subSamples[i].numBytesOfClearData;
-            legacySubSamples[i].mNumBytesOfEncryptedData
-                = subSamples[i].numBytesOfEncryptedData;
+            uint32_t numBytesOfClearData = subSamples[i].numBytesOfClearData;
+            legacySubSamples[i].mNumBytesOfClearData = numBytesOfClearData;
+            uint32_t numBytesOfEncryptedData = subSamples[i].numBytesOfEncryptedData;
+            legacySubSamples[i].mNumBytesOfEncryptedData = numBytesOfEncryptedData;
+            if (__builtin_add_overflow(destSize, numBytesOfClearData, &destSize)) {
+                _hidl_cb(Status::BAD_VALUE, 0, "subsample clear size overflow");
+                return Void();
+            }
+            if (__builtin_add_overflow(destSize, numBytesOfEncryptedData, &destSize)) {
+                _hidl_cb(Status::BAD_VALUE, 0, "subsample encrypted size overflow");
+                return Void();
+            }
         }
 
         AString detailMessage;
@@ -137,11 +146,24 @@
                 _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
                 return Void();
             }
+
+            if (destSize > destBuffer.size) {
+                _hidl_cb(Status::BAD_VALUE, 0, "subsample sum too large");
+                return Void();
+            }
+
             destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
         } else if (destination.type == BufferType::NATIVE_HANDLE) {
+            if (!secure) {
+                _hidl_cb(Status::BAD_VALUE, 0, "native handle destination must be secure");
+                return Void();
+            }
             native_handle_t *handle = const_cast<native_handle_t *>(
                     destination.secureMemory.getNativeHandle());
             destPtr = static_cast<void *>(handle);
+        } else {
+            _hidl_cb(Status::BAD_VALUE, 0, "invalid destination type");
+            return Void();
         }
         ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(),
                 legacyMode, legacyPattern, srcPtr, legacySubSamples.get(),
diff --git a/gatekeeper/1.0/vts/functional/Android.bp b/gatekeeper/1.0/vts/functional/Android.bp
index f55e5d2..a115285 100644
--- a/gatekeeper/1.0/vts/functional/Android.bp
+++ b/gatekeeper/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalGatekeeperV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.gatekeeper@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
index 715e9fc..afc737c 100644
--- a/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
+++ b/gatekeeper/1.0/vts/functional/VtsHalGatekeeperV1_0TargetTest.cpp
@@ -24,7 +24,10 @@
 #include <inttypes.h>
 #include <unistd.h>
 
+#include <gtest/gtest.h>
 #include <hardware/hw_auth_token.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <android/log.h>
 #include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
@@ -32,9 +35,6 @@
 
 #include <log/log.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::gatekeeper::V1_0::IGatekeeper;
@@ -78,22 +78,8 @@
   return auth_token;
 }
 
-// Test environment for Gatekeeper HIDL HAL.
-class GatekeeperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static GatekeeperHidlEnvironment* Instance() {
-    static GatekeeperHidlEnvironment* instance = new GatekeeperHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IGatekeeper>(); }
- private:
-  GatekeeperHidlEnvironment() {}
-};
-
 // The main test class for Gatekeeper HIDL HAL.
-class GatekeeperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class GatekeeperHidlTest : public ::testing::TestWithParam<std::string> {
  protected:
   void setUid(uint32_t uid) { uid_ = uid; }
 
@@ -204,8 +190,7 @@
   GatekeeperHidlTest() : uid_(0) {}
   virtual void SetUp() override {
     GatekeeperResponse rsp;
-    gatekeeper_ = ::testing::VtsHalHidlTargetTestBase::getService<IGatekeeper>(
-        GatekeeperHidlEnvironment::Instance()->getServiceName<IGatekeeper>());
+    gatekeeper_ = IGatekeeper::getService(GetParam());
     ASSERT_NE(nullptr, gatekeeper_.get());
     doDeleteAllUsers(rsp);
   }
@@ -219,7 +204,7 @@
 /**
  * Ensure we can enroll new password
  */
-TEST_F(GatekeeperHidlTest, EnrollSuccess) {
+TEST_P(GatekeeperHidlTest, EnrollSuccess) {
   hidl_vec<uint8_t> password;
   GatekeeperResponse rsp;
   ALOGI("Testing Enroll (expected success)");
@@ -231,7 +216,7 @@
 /**
  * Ensure we can not enroll empty password
  */
-TEST_F(GatekeeperHidlTest, EnrollNoPassword) {
+TEST_P(GatekeeperHidlTest, EnrollNoPassword) {
   hidl_vec<uint8_t> password;
   GatekeeperResponse rsp;
   ALOGI("Testing Enroll (expected failure)");
@@ -242,7 +227,7 @@
 /**
  * Ensure we can successfully verify previously enrolled password
  */
-TEST_F(GatekeeperHidlTest, VerifySuccess) {
+TEST_P(GatekeeperHidlTest, VerifySuccess) {
   GatekeeperResponse enrollRsp;
   GatekeeperResponse verifyRsp;
   hidl_vec<uint8_t> password;
@@ -258,7 +243,7 @@
  * Ensure we can securely update password (keep the same
  * secure user_id) if we prove we know old password
  */
-TEST_F(GatekeeperHidlTest, TrustedReenroll) {
+TEST_P(GatekeeperHidlTest, TrustedReenroll) {
   GatekeeperResponse enrollRsp;
   GatekeeperRequest reenrollReq;
   GatekeeperResponse reenrollRsp;
@@ -297,7 +282,7 @@
  * Ensure we can update password (and get new
  * secure user_id) if we don't know old password
  */
-TEST_F(GatekeeperHidlTest, UntrustedReenroll) {
+TEST_P(GatekeeperHidlTest, UntrustedReenroll) {
   GatekeeperResponse enrollRsp;
   GatekeeperResponse reenrollRsp;
   GatekeeperResponse verifyRsp;
@@ -327,7 +312,7 @@
 /**
  * Ensure we dont get successful verify with invalid data
  */
-TEST_F(GatekeeperHidlTest, VerifyNoData) {
+TEST_P(GatekeeperHidlTest, VerifyNoData) {
   hidl_vec<uint8_t> password;
   hidl_vec<uint8_t> passwordHandle;
   GatekeeperResponse verifyRsp;
@@ -341,7 +326,7 @@
 /**
  * Ensure we can not verify password after we enrolled it and then deleted user
  */
-TEST_F(GatekeeperHidlTest, DeleteUserTest) {
+TEST_P(GatekeeperHidlTest, DeleteUserTest) {
   hidl_vec<uint8_t> password;
   GatekeeperResponse enrollRsp;
   GatekeeperResponse verifyRsp;
@@ -368,7 +353,7 @@
 /**
  * Ensure we can not delete a user that does not exist
  */
-TEST_F(GatekeeperHidlTest, DeleteInvalidUserTest) {
+TEST_P(GatekeeperHidlTest, DeleteInvalidUserTest) {
   hidl_vec<uint8_t> password;
   GatekeeperResponse enrollRsp;
   GatekeeperResponse verifyRsp;
@@ -400,7 +385,7 @@
  * Ensure we can not verify passwords after we enrolled them and then deleted
  * all users
  */
-TEST_F(GatekeeperHidlTest, DeleteAllUsersTest) {
+TEST_P(GatekeeperHidlTest, DeleteAllUsersTest) {
   struct UserData {
     uint32_t userId;
     hidl_vec<uint8_t> password;
@@ -448,11 +433,7 @@
   ALOGI("Testing deleteAllUsers done: rsp=%" PRIi32, delAllRsp.code);
 }
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(GatekeeperHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  GatekeeperHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, GatekeeperHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IGatekeeper::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/health/2.0/default/healthd_common_adapter.cpp b/health/2.0/default/healthd_common_adapter.cpp
index 8fc689d..0b5d869 100644
--- a/health/2.0/default/healthd_common_adapter.cpp
+++ b/health/2.0/default/healthd_common_adapter.cpp
@@ -49,11 +49,14 @@
 static std::unique_ptr<HealthLoopAdapter> health_loop;
 
 int healthd_register_event(int fd, void (*handler)(uint32_t), EventWakeup wakeup) {
+    if (!health_loop) return -1;
+
     auto wrapped_handler = [handler](auto*, uint32_t epevents) { handler(epevents); };
     return health_loop->RegisterEvent(fd, wrapped_handler, wakeup);
 }
 
 void healthd_battery_update_internal(bool charger_online) {
+    if (!health_loop) return;
     health_loop->AdjustWakealarmPeriods(charger_online);
 }
 
diff --git a/media/omx/1.0/vts/functional/README.md b/media/omx/1.0/vts/functional/README.md
index acffc42..274b30d 100644
--- a/media/omx/1.0/vts/functional/README.md
+++ b/media/omx/1.0/vts/functional/README.md
@@ -18,17 +18,17 @@
 
 usage:
 
-VtsHalMediaOmxV1\_0TargetAudioDecTest -I default -C <comp name> -R audio_decoder.<comp class> -P /sdcard/media/
+VtsHalMediaOmxV1\_0TargetAudioDecTest -I default -C <comp name> -R audio_decoder.<comp class> -P /data/local/tmp/media/
 
-VtsHalMediaOmxV1\_0TargetAudioEncTest -I default -C <comp name> -R audio_encoder.<comp class> -P /sdcard/media/
+VtsHalMediaOmxV1\_0TargetAudioEncTest -I default -C <comp name> -R audio_encoder.<comp class> -P /data/local/tmp/media/
 
 #### video :
 This folder includes test fixtures associated with testing video encoder and decoder components such as simple encoding of a raw clip or decoding of an elementary stream, end of stream test, timestamp deviations test, flush test and so on. These tests are aimed towards testing the plugin that connects the component to the omx core.
 
 usage:
 
-VtsHalMediaOmxV1\_0TargetVideoDecTest -I default -C <comp name> -R video_decoder.<comp class> -P /sdcard/media/
+VtsHalMediaOmxV1\_0TargetVideoDecTest -I default -C <comp name> -R video_decoder.<comp class> -P /data/local/tmp/media/
 
-VtsHalMediaOmxV1\_0TargetVideoEncTest -I default -C <comp name> -R video_encoder.<comp class> -P /sdcard/media/
+VtsHalMediaOmxV1\_0TargetVideoEncTest -I default -C <comp name> -R video_encoder.<comp class> -P /data/local/tmp/media/
 
-While tesing audio/video encoder, decoder components, test fixtures require input files. These input are files are present in the folder 'res'. Before running the tests all the files in 'res' have to be placed in '/media/sdcard/' or a path of your choice and this path needs to be provided as an argument to the test application
\ No newline at end of file
+While tesing audio/video encoder, decoder components, test fixtures require input files. These input are files are present in the folder 'res'. Before running the tests all the files in 'res' have to be placed in '/data/local/tmp/media' or a path of your choice and this path needs to be provided as an argument to the test application
diff --git a/media/omx/1.0/vts/functional/common/Android.bp b/media/omx/1.0/vts/functional/common/Android.bp
index cdc52fb..5a79e55 100644
--- a/media/omx/1.0/vts/functional/common/Android.bp
+++ b/media/omx/1.0/vts/functional/common/Android.bp
@@ -29,6 +29,21 @@
         "android.hidl.memory@1.0",
         "android.hardware.media.omx@1.0",
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
+    ],
+    export_static_lib_headers: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
     ],
 }
 
@@ -40,7 +55,12 @@
     static_libs: [
         "VtsHalMediaOmxV1_0CommonUtil",
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.bufferqueue@1.0",
         "android.hardware.graphics.common@1.0",
         "android.hardware.media.omx@1.0",
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
index f299e36..8d4c022 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
@@ -22,8 +22,11 @@
 #include <android-base/logging.h>
 
 #include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <android/hardware/graphics/mapper/2.0/types.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/types.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
@@ -31,7 +34,9 @@
 #include <android/hidl/allocator/1.0/IAllocator.h>
 #include <android/hidl/memory/1.0/IMapper.h>
 #include <android/hidl/memory/1.0/IMemory.h>
-#include <cutils/atomic.h>
+
+#include <atomic>
+#include <variant>
 
 using ::android::hardware::graphics::common::V1_0::BufferUsage;
 using ::android::hardware::graphics::common::V1_0::PixelFormat;
@@ -195,67 +200,104 @@
                             BufferInfo* buffer, uint32_t nFrameWidth,
                             uint32_t nFrameHeight, int32_t* nStride,
                             int format) {
-    android::hardware::media::omx::V1_0::Status status;
-    sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator =
-        android::hardware::graphics::allocator::V2_0::IAllocator::getService();
-    ASSERT_NE(nullptr, allocator.get());
+    struct AllocatorV2 : public GrallocV2 {
+        sp<IAllocator> mAllocator;
+        sp<IMapper> mMapper;
+        AllocatorV2(sp<IAllocator>&& allocator, sp<IMapper>&& mapper)
+              : mAllocator{std::move(allocator)}, mMapper{std::move(mapper)} {}
+        AllocatorV2() = default;
+    };
+    struct AllocatorV3 : public GrallocV3 {
+        sp<IAllocator> mAllocator;
+        sp<IMapper> mMapper;
+        AllocatorV3(sp<IAllocator>&& allocator, sp<IMapper>&& mapper)
+              : mAllocator{std::move(allocator)}, mMapper{std::move(mapper)} {}
+        AllocatorV3() = default;
+    };
+    std::variant<AllocatorV2, AllocatorV3> grallocVar;
 
-    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
-        android::hardware::graphics::mapper::V2_0::IMapper::getService();
-    ASSERT_NE(mapper.get(), nullptr);
+    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper2{};
+    sp<android::hardware::graphics::mapper::V3_0::IMapper> mapper3{};
+    sp<android::hardware::graphics::allocator::V2_0::IAllocator> allocator2{};
+    sp<android::hardware::graphics::allocator::V3_0::IAllocator> allocator3 =
+        android::hardware::graphics::allocator::V3_0::IAllocator::getService();
+    if (allocator3) {
+        mapper3 =
+            android::hardware::graphics::mapper::V3_0::IMapper::getService();
+        ASSERT_NE(nullptr, mapper3.get());
+        grallocVar.emplace<AllocatorV3>(std::move(allocator3), std::move(mapper3));
+    } else {
+        allocator2 =
+            android::hardware::graphics::allocator::V2_0::IAllocator::getService();
+        ASSERT_NE(nullptr, allocator2.get());
+        mapper2 =
+            android::hardware::graphics::mapper::V2_0::IMapper::getService();
+        ASSERT_NE(nullptr, allocator2.get());
+        grallocVar.emplace<AllocatorV2>(std::move(allocator2), std::move(mapper2));
+    }
 
-    android::hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo
-        descriptorInfo;
-    uint32_t usage;
-
-    descriptorInfo.width = nFrameWidth;
-    descriptorInfo.height = nFrameHeight;
-    descriptorInfo.layerCount = 1;
-    descriptorInfo.format = static_cast<PixelFormat>(format);
-    descriptorInfo.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN);
-    omxNode->getGraphicBufferUsage(
+    android::hardware::media::omx::V1_0::Status status{};
+    uint64_t usage{};
+    ASSERT_TRUE(omxNode->getGraphicBufferUsage(
         portIndex,
         [&status, &usage](android::hardware::media::omx::V1_0::Status _s,
                           uint32_t _n1) {
             status = _s;
             usage = _n1;
-        });
-    if (status == android::hardware::media::omx::V1_0::Status::OK) {
-        descriptorInfo.usage |= usage;
-    }
+        }).isOk());
+    ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
 
-    ::android::hardware::hidl_vec<uint32_t> descriptor;
-    android::hardware::graphics::mapper::V2_0::Error error;
-    mapper->createDescriptor(
-        descriptorInfo, [&error, &descriptor](
-                            android::hardware::graphics::mapper::V2_0::Error _s,
-                            ::android::hardware::hidl_vec<uint32_t> _n1) {
-            error = _s;
-            descriptor = _n1;
-        });
-    ASSERT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE);
+    static std::atomic_int32_t bufferIdCounter{0};
 
-    static volatile int32_t nextId = 0;
-    uint64_t id = static_cast<uint64_t>(getpid()) << 32;
-    allocator->allocate(
-        descriptor, 1,
-        [&](android::hardware::graphics::mapper::V2_0::Error _s, uint32_t _n1,
-            const ::android::hardware::hidl_vec<
-                ::android::hardware::hidl_handle>& _n2) {
-            ASSERT_EQ(android::hardware::graphics::mapper::V2_0::Error::NONE,
-                      _s);
-            *nStride = _n1;
-            buffer->omxBuffer.nativeHandle = _n2[0];
-            buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth;
-            buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight;
-            buffer->omxBuffer.attr.anwBuffer.stride = _n1;
-            buffer->omxBuffer.attr.anwBuffer.format = descriptorInfo.format;
-            buffer->omxBuffer.attr.anwBuffer.usage = descriptorInfo.usage;
-            buffer->omxBuffer.attr.anwBuffer.layerCount =
-                descriptorInfo.layerCount;
-            buffer->omxBuffer.attr.anwBuffer.id =
-                id | static_cast<uint32_t>(android_atomic_inc(&nextId));
-        });
+    std::visit([buffer, nFrameWidth, nFrameHeight, format, usage, nStride](auto&& gralloc) {
+            using Gralloc = std::remove_reference_t<decltype(gralloc)>;
+            using Descriptor = typename Gralloc::Descriptor;
+            using DescriptorInfo = typename Gralloc::DescriptorInfo;
+            using Error = typename Gralloc::Error;
+            using Format = typename Gralloc::Format;
+            using Usage = typename Gralloc::Usage;
+
+            Error error{};
+            Descriptor descriptor{};
+
+            DescriptorInfo descriptorInfo{};
+            descriptorInfo.width = nFrameWidth;
+            descriptorInfo.height = nFrameHeight;
+            descriptorInfo.layerCount = 1;
+            descriptorInfo.format = static_cast<Format>(format);
+            descriptorInfo.usage = usage | Usage(BufferUsage::CPU_READ_OFTEN);
+
+            gralloc.mMapper->createDescriptor(descriptorInfo,
+                    [&error, &descriptor](
+                        Error _s,
+                        const Descriptor& _n1) {
+                    error = _s;
+                    descriptor = _n1;
+                });
+            ASSERT_EQ(error, Error::NONE);
+
+            gralloc.mAllocator->allocate(
+                descriptor, 1,
+                [&](Error _s, uint32_t _n1,
+                    const ::android::hardware::hidl_vec<
+                        ::android::hardware::hidl_handle>& _n2) {
+                    ASSERT_EQ(Error::NONE, _s);
+                    *nStride = _n1;
+                    buffer->omxBuffer.nativeHandle = _n2[0];
+                    buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth;
+                    buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight;
+                    buffer->omxBuffer.attr.anwBuffer.stride = _n1;
+                    buffer->omxBuffer.attr.anwBuffer.format =
+                        static_cast<PixelFormat>(descriptorInfo.format);
+                    buffer->omxBuffer.attr.anwBuffer.usage =
+                        static_cast<uint32_t>(descriptorInfo.usage);
+                    buffer->omxBuffer.attr.anwBuffer.layerCount =
+                        descriptorInfo.layerCount;
+                    buffer->omxBuffer.attr.anwBuffer.id =
+                        (static_cast<uint64_t>(getpid()) << 32) |
+                        bufferIdCounter.fetch_add(1, std::memory_order_relaxed);
+                });
+        }, grallocVar);
 }
 
 // allocate buffers needed on a component port
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
index 1575ba2..ac077a3 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
@@ -22,6 +22,16 @@
 #endif
 
 #include <getopt.h>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.0/types.h>
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.0/types.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/types.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <utils/Condition.h>
 #include <utils/List.h>
@@ -288,6 +298,36 @@
 /*
  * common functions declarations
  */
+struct GrallocV2 {
+    using Format = android::hardware::graphics::common::V1_0::PixelFormat;
+    using Usage = android::hardware::hidl_bitfield<
+            android::hardware::graphics::common::V1_0::BufferUsage>;
+
+    using IAllocator = android::hardware::graphics::allocator::V2_0::IAllocator;
+
+    using IMapper = android::hardware::graphics::mapper::V2_0::IMapper;
+    using Error = android::hardware::graphics::mapper::V2_0::Error;
+    using Descriptor = android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+    using YCbCrLayout = android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+    using DescriptorInfo = IMapper::BufferDescriptorInfo;
+    using Rect = IMapper::Rect;
+};
+
+struct GrallocV3 {
+    using Format = android::hardware::graphics::common::V1_2::PixelFormat;
+    using Usage = android::hardware::hidl_bitfield<
+            android::hardware::graphics::common::V1_2::BufferUsage>;
+
+    using IAllocator = android::hardware::graphics::allocator::V3_0::IAllocator;
+
+    using IMapper = android::hardware::graphics::mapper::V3_0::IMapper;
+    using Error = android::hardware::graphics::mapper::V3_0::Error;
+    using Descriptor = android::hardware::graphics::mapper::V3_0::BufferDescriptor;
+    using YCbCrLayout = android::hardware::graphics::mapper::V3_0::YCbCrLayout;
+    using DescriptorInfo = IMapper::BufferDescriptorInfo;
+    using Rect = IMapper::Rect;
+};
+
 Return<android::hardware::media::omx::V1_0::Status> setRole(
     sp<IOmxNode> omxNode, const char* role);
 
@@ -368,7 +408,7 @@
    public:
     virtual void registerTestServices() override { registerTestService<IOmx>(); }
 
-    ComponentTestEnvironment() : res("/sdcard/media/") {}
+    ComponentTestEnvironment() : res("/data/local/tmp/media/") {}
 
     void setComponent(const char* _component) { component = _component; }
 
diff --git a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
index a740a80..2280cee 100644
--- a/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
+++ b/media/omx/1.0/vts/functional/video/VtsHalMediaOmxV1_0TargetVideoEncTest.cpp
@@ -63,6 +63,7 @@
 #include <media_video_hidl_test_common.h>
 #include <system/window.h>
 #include <fstream>
+#include <variant>
 
 static ComponentTestEnvironment* gEnv = nullptr;
 
@@ -364,6 +365,61 @@
     return Void();
 };
 
+// Variant of mappers
+struct MapperV2 : public GrallocV2 {
+    sp<IMapper> mMapper;
+    MapperV2(sp<IMapper>&& mapper): mMapper{std::move(mapper)} {}
+    MapperV2() = default;
+    android::hardware::Return<void> lock(
+            void* buffer,
+            Usage usage,
+            const Rect& rect,
+            const android::hardware::hidl_handle& handle,
+            Error* error,
+            void** data) {
+        return mMapper->lock(buffer, usage, rect, handle,
+                             [error, data](Error e, void* d) {
+                                *error = e;
+                                *data = d;
+                             });
+    }
+};
+struct MapperV3 : public GrallocV3 {
+    sp<IMapper> mMapper;
+    MapperV3(sp<IMapper>&& mapper): mMapper{std::move(mapper)} {}
+    MapperV3() = default;
+    android::hardware::Return<void> lock(
+            void* buffer,
+            Usage usage,
+            const Rect& rect,
+            const android::hardware::hidl_handle& handle,
+            Error* error,
+            void** data) {
+        return mMapper->lock(buffer, usage, rect, handle,
+                             [error, data](Error e, void* d, int32_t, int32_t) {
+                                *error = e;
+                                *data = d;
+                             });
+    }
+};
+using MapperVar = std::variant<MapperV2, MapperV3>;
+// Initializes the MapperVar by trying services of different versions.
+bool initialize(MapperVar& mapperVar) {
+    sp<android::hardware::graphics::mapper::V3_0::IMapper> mapper3 =
+        android::hardware::graphics::mapper::V3_0::IMapper::getService();
+    if (mapper3) {
+        mapperVar.emplace<MapperV3>(std::move(mapper3));
+        return true;
+    }
+    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper2 =
+        android::hardware::graphics::mapper::V2_0::IMapper::getService();
+    if (mapper2) {
+        mapperVar.emplace<MapperV2>(std::move(mapper2));
+        return true;
+    }
+    return false;
+}
+
 // request VOP refresh
 void requestIDR(sp<IOmxNode> omxNode, OMX_U32 portIndex) {
     android::hardware::media::omx::V1_0::Status status;
@@ -574,150 +630,166 @@
 
 int colorFormatConversion(BufferInfo* buffer, void* buff, PixelFormat format,
                           std::ifstream& eleStream) {
-    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
-        android::hardware::graphics::mapper::V2_0::IMapper::getService();
-    EXPECT_NE(mapper.get(), nullptr);
-    if (mapper.get() == nullptr) return 1;
-
-    android::hardware::hidl_handle fence;
-    android::hardware::graphics::mapper::V2_0::IMapper::Rect rect;
-    android::hardware::graphics::mapper::V2_0::YCbCrLayout ycbcrLayout;
-    android::hardware::graphics::mapper::V2_0::Error error;
-    rect.left = 0;
-    rect.top = 0;
-    rect.width = buffer->omxBuffer.attr.anwBuffer.width;
-    rect.height = buffer->omxBuffer.attr.anwBuffer.height;
-
-    if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
-        format == PixelFormat::YCBCR_420_888) {
-        mapper->lockYCbCr(
-            buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, fence,
-            [&](android::hardware::graphics::mapper::V2_0::Error _e,
-                android::hardware::graphics::mapper::V2_0::YCbCrLayout _n1) {
-                error = _e;
-                ycbcrLayout = _n1;
-            });
-        EXPECT_EQ(error,
-                  android::hardware::graphics::mapper::V2_0::Error::NONE);
-        if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
-            return 1;
-
-        int size = ((rect.width * rect.height * 3) >> 1);
-        char* img = new char[size];
-        if (img == nullptr) return 1;
-        eleStream.read(img, size);
-        if (eleStream.gcount() != size) {
-            delete[] img;
-            return 1;
-        }
-
-        char* imgTmp = img;
-        char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
-        for (size_t y = rect.height; y > 0; --y) {
-            memcpy(ipBuffer, imgTmp, rect.width);
-            ipBuffer += ycbcrLayout.yStride;
-            imgTmp += rect.width;
-        }
-
-        if (format == PixelFormat::YV12)
-            EXPECT_EQ(ycbcrLayout.chromaStep, 1U);
-        else if (format == PixelFormat::YCRCB_420_SP)
-            EXPECT_EQ(ycbcrLayout.chromaStep, 2U);
-
-        ipBuffer = static_cast<char*>(ycbcrLayout.cb);
-        for (size_t y = rect.height >> 1; y > 0; --y) {
-            for (int32_t x = 0; x < (rect.width >> 1); ++x) {
-                ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
-            }
-            ipBuffer += ycbcrLayout.cStride;
-        }
-        ipBuffer = static_cast<char*>(ycbcrLayout.cr);
-        for (size_t y = rect.height >> 1; y > 0; --y) {
-            for (int32_t x = 0; x < (rect.width >> 1); ++x) {
-                ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
-            }
-            ipBuffer += ycbcrLayout.cStride;
-        }
-
-        delete[] img;
-
-        mapper->unlock(buff,
-                       [&](android::hardware::graphics::mapper::V2_0::Error _e,
-                           android::hardware::hidl_handle _n1) {
-                           error = _e;
-                           fence = _n1;
-                       });
-        EXPECT_EQ(error,
-                  android::hardware::graphics::mapper::V2_0::Error::NONE);
-        if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
-            return 1;
-    } else {
-        void* data;
-        mapper->lock(buff, buffer->omxBuffer.attr.anwBuffer.usage, rect, fence,
-                     [&](android::hardware::graphics::mapper::V2_0::Error _e,
-                         void* _n1) {
-                         error = _e;
-                         data = _n1;
-                     });
-        EXPECT_EQ(error,
-                  android::hardware::graphics::mapper::V2_0::Error::NONE);
-        if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
-            return 1;
-
-        if (format == PixelFormat::BGRA_8888) {
-            char* ipBuffer = static_cast<char*>(data);
-            for (size_t y = rect.height; y > 0; --y) {
-                eleStream.read(ipBuffer, rect.width * 4);
-                if (eleStream.gcount() != rect.width * 4) return 1;
-                ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
-            }
-        } else {
-            EXPECT_TRUE(false) << "un expected pixel format";
-            return 1;
-        }
-
-        mapper->unlock(buff,
-                       [&](android::hardware::graphics::mapper::V2_0::Error _e,
-                           android::hardware::hidl_handle _n1) {
-                           error = _e;
-                           fence = _n1;
-                       });
-        EXPECT_EQ(error,
-                  android::hardware::graphics::mapper::V2_0::Error::NONE);
-        if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
-            return 1;
+    MapperVar mapperVar;
+    if (!initialize(mapperVar)) {
+        EXPECT_TRUE(false) << "failed to obtain mapper service";
+        return 1;
     }
 
-    return 0;
+    return std::visit([buffer, buff, format, &eleStream](auto&& mapper) -> int {
+            using Gralloc = std::remove_reference_t<decltype(mapper)>;
+            using Error = typename Gralloc::Error;
+            using Rect = typename Gralloc::Rect;
+            using Usage = typename Gralloc::Usage;
+            using YCbCrLayout = typename Gralloc::YCbCrLayout;
+
+            android::hardware::hidl_handle fence;
+            Rect rect;
+            YCbCrLayout ycbcrLayout;
+            Error error;
+            rect.left = 0;
+            rect.top = 0;
+            rect.width = buffer->omxBuffer.attr.anwBuffer.width;
+            rect.height = buffer->omxBuffer.attr.anwBuffer.height;
+
+            if (format == PixelFormat::YV12 || format == PixelFormat::YCRCB_420_SP ||
+                format == PixelFormat::YCBCR_420_888) {
+                mapper.mMapper->lockYCbCr(
+                        buff,
+                        static_cast<Usage>(
+                            buffer->omxBuffer.attr.anwBuffer.usage),
+                        rect,
+                        fence,
+                        [&](Error _e,
+                            const YCbCrLayout& _n1) {
+                            error = _e;
+                            ycbcrLayout = _n1;
+                        });
+                EXPECT_EQ(error, Error::NONE);
+                if (error != Error::NONE)
+                    return 1;
+
+                int size = ((rect.width * rect.height * 3) >> 1);
+                char* img = new char[size];
+                if (img == nullptr) return 1;
+                eleStream.read(img, size);
+                if (eleStream.gcount() != size) {
+                    delete[] img;
+                    return 1;
+                }
+
+                char* imgTmp = img;
+                char* ipBuffer = static_cast<char*>(ycbcrLayout.y);
+                for (size_t y = rect.height; y > 0; --y) {
+                    memcpy(ipBuffer, imgTmp, rect.width);
+                    ipBuffer += ycbcrLayout.yStride;
+                    imgTmp += rect.width;
+                }
+
+                if (format == PixelFormat::YV12)
+                    EXPECT_EQ(ycbcrLayout.chromaStep, 1U);
+                else if (format == PixelFormat::YCRCB_420_SP)
+                    EXPECT_EQ(ycbcrLayout.chromaStep, 2U);
+
+                ipBuffer = static_cast<char*>(ycbcrLayout.cb);
+                for (size_t y = rect.height >> 1; y > 0; --y) {
+                    for (int32_t x = 0; x < (rect.width >> 1); ++x) {
+                        ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
+                    }
+                    ipBuffer += ycbcrLayout.cStride;
+                }
+                ipBuffer = static_cast<char*>(ycbcrLayout.cr);
+                for (size_t y = rect.height >> 1; y > 0; --y) {
+                    for (int32_t x = 0; x < (rect.width >> 1); ++x) {
+                        ipBuffer[ycbcrLayout.chromaStep * x] = *imgTmp++;
+                    }
+                    ipBuffer += ycbcrLayout.cStride;
+                }
+
+                delete[] img;
+
+                mapper.mMapper->unlock(buff,
+                               [&](Error _e,
+                                   const android::hardware::hidl_handle& _n1) {
+                                   error = _e;
+                                   fence = _n1;
+                               });
+                EXPECT_EQ(error, Error::NONE);
+                if (error != Error::NONE)
+                    return 1;
+            } else {
+                void* data;
+                mapper.lock(
+                        buff,
+                        buffer->omxBuffer.attr.anwBuffer.usage,
+                        rect,
+                        fence,
+                        &error,
+                        &data);
+                EXPECT_EQ(error, Error::NONE);
+                if (error != Error::NONE)
+                    return 1;
+
+                if (format == PixelFormat::BGRA_8888) {
+                    char* ipBuffer = static_cast<char*>(data);
+                    for (size_t y = rect.height; y > 0; --y) {
+                        eleStream.read(ipBuffer, rect.width * 4);
+                        if (eleStream.gcount() != rect.width * 4) return 1;
+                        ipBuffer += buffer->omxBuffer.attr.anwBuffer.stride * 4;
+                    }
+                } else {
+                    EXPECT_TRUE(false) << "un expected pixel format";
+                    return 1;
+                }
+
+                mapper.mMapper->unlock(
+                        buff,
+                        [&](Error _e, const android::hardware::hidl_handle& _n1) {
+                            error = _e;
+                            fence = _n1;
+                        });
+                EXPECT_EQ(error, Error::NONE);
+                if (error != Error::NONE)
+                    return 1;
+            }
+
+            return 0;
+        }, mapperVar);
 }
 
 int fillGraphicBuffer(BufferInfo* buffer, PixelFormat format,
                       std::ifstream& eleStream) {
-    sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
-        android::hardware::graphics::mapper::V2_0::IMapper::getService();
-    EXPECT_NE(mapper.get(), nullptr);
-    if (mapper.get() == nullptr) return 1;
-
-    void* buff = nullptr;
-    android::hardware::graphics::mapper::V2_0::Error error;
-    mapper->importBuffer(
-        buffer->omxBuffer.nativeHandle,
-        [&](android::hardware::graphics::mapper::V2_0::Error _e, void* _n1) {
-            error = _e;
-            buff = _n1;
-        });
-    EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE);
-    if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
+    MapperVar mapperVar;
+    if (!initialize(mapperVar)) {
+        EXPECT_TRUE(false) << "failed to obtain mapper service";
         return 1;
+    }
 
-    if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
+    return std::visit([buffer, format, &eleStream](auto&& mapper) -> int {
+            using Gralloc = std::remove_reference_t<decltype(mapper)>;
+            using Error = typename Gralloc::Error;
 
-    error = mapper->freeBuffer(buff);
-    EXPECT_EQ(error, android::hardware::graphics::mapper::V2_0::Error::NONE);
-    if (error != android::hardware::graphics::mapper::V2_0::Error::NONE)
-        return 1;
+            void* buff = nullptr;
+            Error error;
+            mapper.mMapper->importBuffer(
+                buffer->omxBuffer.nativeHandle,
+                [&](Error _e, void* _n1) {
+                    error = _e;
+                    buff = _n1;
+                });
+            EXPECT_EQ(error, Error::NONE);
+            if (error != Error::NONE)
+                return 1;
 
-    return 0;
+            if (colorFormatConversion(buffer, buff, format, eleStream)) return 1;
+
+            error = mapper.mMapper->freeBuffer(buff);
+            EXPECT_EQ(error, Error::NONE);
+            if (error != Error::NONE)
+                return 1;
+
+            return 0;
+        }, mapperVar);
 }
 
 int dispatchGraphicBuffer(sp<IOmxNode> omxNode,
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index 837ced5..ef71ea8 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -2448,15 +2448,17 @@
      *       then clipping is disabled.
      *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
      *       this scalar must be of the type {@link OperandType::FLOAT32},
-     *       otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16},
-     *       this scalar must be of type {@link OperandType::FLOAT16}.
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
      * * 50: The clipping threshold for the output from the
      *       projection layer, such that values are bound within
      *       [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
      *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
      *       this scalar must be of the type {@link OperandType::FLOAT32},
-     *       otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16},
-     *       this scalar must be of type {@link OperandType::FLOAT16}.
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
      * * 51: merge_outputs
      *       An {@link OperandType::BOOL} scalar specifying if the outputs
      *       from forward and backward cells should be merged.
@@ -4124,7 +4126,6 @@
      * * 0: A tensor of the same type and shape as input1 and input2.
      *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
      *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
-     *
      */
     SELECT = 84,
 
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index aacb385..c1bf494 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -58,8 +58,20 @@
 using V1_1::ExecutionPreference;
 using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
+namespace {
+
+enum class Executor { ASYNC, SYNC, BURST };
+
 enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
 
+struct TestConfig {
+    Executor executor;
+    MeasureTiming measureTiming;
+    OutputType outputType;
+};
+
+}  // namespace
+
 Model createModel(const TestModel& testModel) {
     // Model operands.
     hidl_vec<Operand> operands(testModel.operands.size());
@@ -194,31 +206,31 @@
     return android::nn::ExecutionBurstController::create(preparedModel,
                                                          std::chrono::microseconds{0});
 }
-enum class Executor { ASYNC, SYNC, BURST };
 
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
-                           Executor executor, MeasureTiming measure, OutputType outputType) {
+                           const TestConfig& testConfig) {
     // If output0 does not have size larger than one byte, we can not test with insufficient buffer.
-    if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) {
+    if (testConfig.outputType == OutputType::INSUFFICIENT &&
+        !isOutputSizeGreaterThanOne(testModel, 0)) {
         return;
     }
 
     Request request = createRequest(testModel);
-    if (outputType == OutputType::INSUFFICIENT) {
+    if (testConfig.outputType == OutputType::INSUFFICIENT) {
         makeOutputInsufficientSize(/*outputIndex=*/0, &request);
     }
 
     ErrorStatus executionStatus;
     hidl_vec<OutputShape> outputShapes;
     Timing timing;
-    switch (executor) {
+    switch (testConfig.executor) {
         case Executor::ASYNC: {
             SCOPED_TRACE("asynchronous");
 
             // launch execution
             sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-            Return<ErrorStatus> executionLaunchStatus =
-                    ExecutePreparedModel(preparedModel, request, measure, executionCallback);
+            Return<ErrorStatus> executionLaunchStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, executionCallback);
             ASSERT_TRUE(executionLaunchStatus.isOk());
             EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
 
@@ -234,8 +246,8 @@
             SCOPED_TRACE("synchronous");
 
             // execute
-            Return<ErrorStatus> executionReturnStatus =
-                    ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing);
+            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, &outputShapes, &timing);
             ASSERT_TRUE(executionReturnStatus.isOk());
             executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
 
@@ -258,14 +270,14 @@
             // execute burst
             int n;
             std::tie(n, outputShapes, timing, std::ignore) =
-                    controller->compute(request, measure, keys);
+                    controller->compute(request, testConfig.measureTiming, keys);
             executionStatus = nn::convertResultCodeToErrorStatus(n);
 
             break;
         }
     }
 
-    if (outputType != OutputType::FULLY_SPECIFIED &&
+    if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
         executionStatus == ErrorStatus::GENERAL_FAILURE) {
         LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
                      "execute model that it does not support.";
@@ -274,7 +286,7 @@
                   << std::endl;
         GTEST_SKIP();
     }
-    if (measure == MeasureTiming::NO) {
+    if (testConfig.measureTiming == MeasureTiming::NO) {
         EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
         EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
     } else {
@@ -283,7 +295,7 @@
         }
     }
 
-    switch (outputType) {
+    switch (testConfig.outputType) {
         case OutputType::FULLY_SPECIFIED:
             // If the model output operands are fully specified, outputShapes must be either
             // either empty, or have the same number of elements as the number of outputs.
@@ -321,44 +333,29 @@
 
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
                            bool testDynamicOutputShape) {
+    std::initializer_list<OutputType> outputTypesList;
+    std::initializer_list<MeasureTiming> measureTimingList;
+    std::initializer_list<Executor> executorList;
+
     if (testDynamicOutputShape) {
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
+        outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
+        measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+        executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
     } else {
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
+        outputTypesList = {OutputType::FULLY_SPECIFIED};
+        measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+        executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+    }
+
+    for (const OutputType outputType : outputTypesList) {
+        for (const MeasureTiming measureTiming : measureTimingList) {
+            for (const Executor executor : executorList) {
+                const TestConfig testConfig = {.executor = executor,
+                                               .measureTiming = measureTiming,
+                                               .outputType = outputType};
+                EvaluatePreparedModel(preparedModel, testModel, testConfig);
+            }
+        }
     }
 }
 
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index 7df14b1..f959e45 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -2375,15 +2375,17 @@
      *       then clipping is disabled.
      *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
      *       this scalar must be of the type {@link OperandType::FLOAT32},
-     *       otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16},
-     *       this scalar must be of type {@link OperandType::FLOAT16}.
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
      * * 50: The clipping threshold for the output from the
      *       projection layer, such that values are bound within
      *       [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
      *       If all the input tensors have type {@link OperandType::TENSOR_FLOAT32},
      *       this scalar must be of the type {@link OperandType::FLOAT32},
-     *       otherwise if all the input tensors have the type {@link OperandType::TENSOR_FLOAT16},
-     *       this scalar must be of type {@link OperandType::FLOAT16}.
+     *       otherwise if all the input tensors have the type
+     *       {@link OperandType::TENSOR_FLOAT16}, this scalar must be
+     *       of type {@link OperandType::FLOAT16}.
      * * 51: merge_outputs
      *       An {@link OperandType::BOOL} scalar specifying if the outputs
      *       from forward and backward cells should be merged.
@@ -4034,6 +4036,7 @@
      * * {@link OperandType::TENSOR_FLOAT32}
      * * {@link OperandType::TENSOR_INT32}
      * * {@link OperandType::TENSOR_QUANT8_ASYMM}
+     * * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
      *
      * Supported tensor rank: from 1
      *
@@ -4044,14 +4047,14 @@
      *      true) or input2 (if false).
      * * 1: An input tensor of the same shape as input0.
      * * 2: An input tensor of the same shape and type as input1.
-     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
+     *      For a {@link OperandType::TENSOR_QUANT8_ASYMM}
+     *      and {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} tensor,
      *      the scales and zeroPoint can be different from input1 scale and zeroPoint.
      *
      * Outputs:
      * * 0: A tensor of the same type and shape as input1 and input2.
      *      For a {@link OperandType::TENSOR_QUANT8_ASYMM} tensor,
      *      the scale and zeroPoint can be different from inputs' scale and zeroPoint.
-     *
      */
     SELECT = @1.2::OperationType:SELECT,
 
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index d8a7534..60992d5 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -456,8 +456,7 @@
     }
 
     // Execute and verify results.
-    EvaluatePreparedModel(preparedModel, testModel,
-                          /*testDynamicOutputShape=*/false);
+    EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
 }
 
 TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
@@ -519,8 +518,7 @@
     }
 
     // Execute and verify results.
-    EvaluatePreparedModel(preparedModel, testModel,
-                          /*testDynamicOutputShape=*/false);
+    EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
 }
 
 TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) {
@@ -541,8 +539,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -566,8 +563,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -590,8 +586,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -615,8 +610,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -727,8 +721,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -752,8 +745,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -776,8 +768,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -801,8 +792,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -914,8 +904,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -937,8 +926,7 @@
         saveModelToCache(model, modelCache, dataCache, &preparedModel);
         ASSERT_NE(preparedModel, nullptr);
         // Execute and verify results.
-        EvaluatePreparedModel(preparedModel, testModel,
-                              /*testDynamicOutputShape=*/false);
+        EvaluatePreparedModel(preparedModel, testModel, /*testKind=*/TestKind::GENERAL);
         // Check if prepareModelFromCache fails.
         preparedModel = nullptr;
         ErrorStatus status;
@@ -1082,8 +1070,7 @@
                 ASSERT_EQ(preparedModel, nullptr);
             } else {
                 ASSERT_NE(preparedModel, nullptr);
-                EvaluatePreparedModel(preparedModel, testModelAdd,
-                                      /*testDynamicOutputShape=*/false);
+                EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL);
             }
         }
     }
@@ -1144,8 +1131,7 @@
                 ASSERT_EQ(preparedModel, nullptr);
             } else {
                 ASSERT_NE(preparedModel, nullptr);
-                EvaluatePreparedModel(preparedModel, testModelAdd,
-                                      /*testDynamicOutputShape=*/false);
+                EvaluatePreparedModel(preparedModel, testModelAdd, /*testKind=*/TestKind::GENERAL);
             }
         }
     }
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index a1e04c5..3e947f5 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -69,8 +69,35 @@
 using V1_2::implementation::ExecutionCallback;
 using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
 
+namespace {
+
+enum class Executor { ASYNC, SYNC, BURST };
+
 enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
 
+struct TestConfig {
+    Executor executor;
+    MeasureTiming measureTiming;
+    OutputType outputType;
+    // `reportSkipping` indicates if a test should print an info message in case
+    // it is skipped. The field is set to true by default and is set to false in
+    // quantization coupling tests to suppress skipping a test
+    bool reportSkipping;
+    TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType)
+        : executor(executor),
+          measureTiming(measureTiming),
+          outputType(outputType),
+          reportSkipping(true) {}
+    TestConfig(Executor executor, MeasureTiming measureTiming, OutputType outputType,
+               bool reportSkipping)
+        : executor(executor),
+          measureTiming(measureTiming),
+          outputType(outputType),
+          reportSkipping(reportSkipping) {}
+};
+
+}  // namespace
+
 Model createModel(const TestModel& testModel) {
     // Model operands.
     hidl_vec<Operand> operands(testModel.operands.size());
@@ -205,31 +232,34 @@
     return android::nn::ExecutionBurstController::create(preparedModel,
                                                          std::chrono::microseconds{0});
 }
-enum class Executor { ASYNC, SYNC, BURST };
 
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
-                           Executor executor, MeasureTiming measure, OutputType outputType) {
+                           const TestConfig& testConfig, bool* skipped = nullptr) {
+    if (skipped != nullptr) {
+        *skipped = false;
+    }
     // If output0 does not have size larger than one byte, we can not test with insufficient buffer.
-    if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) {
+    if (testConfig.outputType == OutputType::INSUFFICIENT &&
+        !isOutputSizeGreaterThanOne(testModel, 0)) {
         return;
     }
 
     Request request = createRequest(testModel);
-    if (outputType == OutputType::INSUFFICIENT) {
+    if (testConfig.outputType == OutputType::INSUFFICIENT) {
         makeOutputInsufficientSize(/*outputIndex=*/0, &request);
     }
 
     ErrorStatus executionStatus;
     hidl_vec<OutputShape> outputShapes;
     Timing timing;
-    switch (executor) {
+    switch (testConfig.executor) {
         case Executor::ASYNC: {
             SCOPED_TRACE("asynchronous");
 
             // launch execution
             sp<ExecutionCallback> executionCallback = new ExecutionCallback();
-            Return<ErrorStatus> executionLaunchStatus =
-                    ExecutePreparedModel(preparedModel, request, measure, executionCallback);
+            Return<ErrorStatus> executionLaunchStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, executionCallback);
             ASSERT_TRUE(executionLaunchStatus.isOk());
             EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
 
@@ -245,8 +275,8 @@
             SCOPED_TRACE("synchronous");
 
             // execute
-            Return<ErrorStatus> executionReturnStatus =
-                    ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing);
+            Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
+                    preparedModel, request, testConfig.measureTiming, &outputShapes, &timing);
             ASSERT_TRUE(executionReturnStatus.isOk());
             executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
 
@@ -269,15 +299,21 @@
             // execute burst
             int n;
             std::tie(n, outputShapes, timing, std::ignore) =
-                    controller->compute(request, measure, keys);
+                    controller->compute(request, testConfig.measureTiming, keys);
             executionStatus = nn::convertResultCodeToErrorStatus(n);
 
             break;
         }
     }
 
-    if (outputType != OutputType::FULLY_SPECIFIED &&
+    if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
         executionStatus == ErrorStatus::GENERAL_FAILURE) {
+        if (skipped != nullptr) {
+            *skipped = true;
+        }
+        if (!testConfig.reportSkipping) {
+            return;
+        }
         LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
                      "execute model that it does not support.";
         std::cout << "[          ]   Early termination of test because vendor service cannot "
@@ -285,7 +321,7 @@
                   << std::endl;
         GTEST_SKIP();
     }
-    if (measure == MeasureTiming::NO) {
+    if (testConfig.measureTiming == MeasureTiming::NO) {
         EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
         EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
     } else {
@@ -294,7 +330,7 @@
         }
     }
 
-    switch (outputType) {
+    switch (testConfig.outputType) {
         case OutputType::FULLY_SPECIFIED:
             // If the model output operands are fully specified, outputShapes must be either
             // either empty, or have the same number of elements as the number of outputs.
@@ -331,59 +367,117 @@
 }
 
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
-                           bool testDynamicOutputShape) {
-    if (testDynamicOutputShape) {
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::UNSPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::INSUFFICIENT);
-    } else {
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
-        EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
-                              OutputType::FULLY_SPECIFIED);
+                           TestKind testKind) {
+    std::initializer_list<OutputType> outputTypesList;
+    std::initializer_list<MeasureTiming> measureTimingList;
+    std::initializer_list<Executor> executorList;
+
+    switch (testKind) {
+        case TestKind::GENERAL: {
+            outputTypesList = {OutputType::FULLY_SPECIFIED};
+            measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+        } break;
+        case TestKind::DYNAMIC_SHAPE: {
+            outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
+            measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
+            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+        } break;
+        case TestKind::QUANTIZATION_COUPLING: {
+            LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
+            return;
+        } break;
+    }
+
+    for (const OutputType outputType : outputTypesList) {
+        for (const MeasureTiming measureTiming : measureTimingList) {
+            for (const Executor executor : executorList) {
+                const TestConfig testConfig(executor, measureTiming, outputType);
+                EvaluatePreparedModel(preparedModel, testModel, testConfig);
+            }
+        }
     }
 }
 
-void Execute(const sp<IDevice>& device, const TestModel& testModel, bool testDynamicOutputShape) {
+void EvaluatePreparedCoupledModels(const sp<IPreparedModel>& preparedModel,
+                                   const TestModel& testModel,
+                                   const sp<IPreparedModel>& preparedCoupledModel,
+                                   const TestModel& coupledModel) {
+    std::initializer_list<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
+    std::initializer_list<MeasureTiming> measureTimingList = {MeasureTiming::NO,
+                                                              MeasureTiming::YES};
+    std::initializer_list<Executor> executorList = {Executor::ASYNC, Executor::SYNC,
+                                                    Executor::BURST};
+
+    for (const OutputType outputType : outputTypesList) {
+        for (const MeasureTiming measureTiming : measureTimingList) {
+            for (const Executor executor : executorList) {
+                const TestConfig testConfig(executor, measureTiming, outputType,
+                                            /*reportSkipping=*/false);
+                bool baseSkipped = false;
+                EvaluatePreparedModel(preparedModel, testModel, testConfig, &baseSkipped);
+                bool coupledSkipped = false;
+                EvaluatePreparedModel(preparedCoupledModel, coupledModel, testConfig,
+                                      &coupledSkipped);
+                ASSERT_EQ(baseSkipped, coupledSkipped);
+                if (baseSkipped) {
+                    LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                                 "execute model that it does not support.";
+                    std::cout << "[          ]   Early termination of test because vendor service "
+                                 "cannot "
+                                 "execute model that it does not support."
+                              << std::endl;
+                    GTEST_SKIP();
+                }
+            }
+        }
+    }
+}
+
+void Execute(const sp<IDevice>& device, const TestModel& testModel, TestKind testKind) {
     Model model = createModel(testModel);
-    if (testDynamicOutputShape) {
+    if (testKind == TestKind::DYNAMIC_SHAPE) {
         makeOutputDimensionsUnspecified(&model);
     }
 
     sp<IPreparedModel> preparedModel;
-    createPreparedModel(device, model, &preparedModel);
-    if (preparedModel == nullptr) return;
-
-    EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape);
+    switch (testKind) {
+        case TestKind::GENERAL: {
+            createPreparedModel(device, model, &preparedModel);
+            if (preparedModel == nullptr) return;
+            EvaluatePreparedModel(preparedModel, testModel, TestKind::GENERAL);
+        } break;
+        case TestKind::DYNAMIC_SHAPE: {
+            createPreparedModel(device, model, &preparedModel);
+            if (preparedModel == nullptr) return;
+            EvaluatePreparedModel(preparedModel, testModel, TestKind::DYNAMIC_SHAPE);
+        } break;
+        case TestKind::QUANTIZATION_COUPLING: {
+            ASSERT_TRUE(testModel.hasQuant8AsymmOperands());
+            createPreparedModel(device, model, &preparedModel, /*reportSkipping*/ false);
+            TestModel signedQuantizedModel = convertQuant8AsymmOperandsToSigned(testModel);
+            sp<IPreparedModel> preparedCoupledModel;
+            createPreparedModel(device, createModel(signedQuantizedModel), &preparedCoupledModel,
+                                /*reportSkipping*/ false);
+            // If we couldn't prepare a model with unsigned quantization, we must
+            // fail to prepare a model with signed quantization as well.
+            if (preparedModel == nullptr) {
+                ASSERT_EQ(preparedCoupledModel, nullptr);
+                // If we failed to prepare both of the models, we can safely skip
+                // the test.
+                LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+                             "prepare model that it does not support.";
+                std::cout
+                        << "[          ]   Early termination of test because vendor service cannot "
+                           "prepare model that it does not support."
+                        << std::endl;
+                GTEST_SKIP();
+            }
+            ASSERT_NE(preparedCoupledModel, nullptr);
+            EvaluatePreparedCoupledModels(preparedModel, testModel, preparedCoupledModel,
+                                          signedQuantizedModel);
+        } break;
+    }
 }
 
 void GeneratedTestBase::SetUp() {
@@ -406,12 +500,19 @@
 // Tag for the dynamic output shape tests
 class DynamicOutputShapeTest : public GeneratedTest {};
 
+// Tag for the dynamic output shape tests
+class DISABLED_QuantizationCouplingTest : public GeneratedTest {};
+
 TEST_P(GeneratedTest, Test) {
-    Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/false);
+    Execute(kDevice, kTestModel, /*testKind=*/TestKind::GENERAL);
 }
 
 TEST_P(DynamicOutputShapeTest, Test) {
-    Execute(kDevice, kTestModel, /*testDynamicOutputShape=*/true);
+    Execute(kDevice, kTestModel, /*testKind=*/TestKind::DYNAMIC_SHAPE);
+}
+
+TEST_P(DISABLED_QuantizationCouplingTest, Test) {
+    Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING);
 }
 
 INSTANTIATE_GENERATED_TEST(GeneratedTest,
@@ -420,4 +521,8 @@
 INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest,
                            [](const TestModel& testModel) { return !testModel.expectFailure; });
 
+INSTANTIATE_GENERATED_TEST(DISABLED_QuantizationCouplingTest, [](const TestModel& testModel) {
+    return testModel.hasQuant8AsymmOperands() && testModel.operations.size() == 1;
+});
+
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
index 45cff5b..ad6323f 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
@@ -57,8 +57,19 @@
 
 void PrepareModel(const sp<IDevice>& device, const Model& model, sp<IPreparedModel>* preparedModel);
 
+enum class TestKind {
+    // Runs a test model and compares the results to a golden data
+    GENERAL,
+    // Same as GENERAL but sets dimensions for the output tensors to zeros
+    DYNAMIC_SHAPE,
+    // Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result
+    // (OK/SKIPPED/FAILED) as the model with all such tensors converted to
+    // TENSOR_QUANT8_ASYMM_SIGNED.
+    QUANTIZATION_COUPLING
+};
+
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel,
-                           const test_helper::TestModel& testModel, bool testDynamicOutputShape);
+                           const test_helper::TestModel& testModel, TestKind testKind);
 
 }  // namespace android::hardware::neuralnetworks::V1_3::vts::functional
 
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index 625913d..92d8fa7 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -37,7 +37,7 @@
 
 // internal helper function
 void createPreparedModel(const sp<IDevice>& device, const Model& model,
-                         sp<IPreparedModel>* preparedModel) {
+                         sp<IPreparedModel>* preparedModel, bool reportSkipping) {
     ASSERT_NE(nullptr, preparedModel);
     *preparedModel = nullptr;
 
@@ -74,6 +74,9 @@
     // can continue.
     if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
         ASSERT_EQ(nullptr, preparedModel->get());
+        if (!reportSkipping) {
+            return;
+        }
         LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot prepare "
                      "model that it does not support.";
         std::cout << "[          ]   Early termination of test because vendor service cannot "
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
index 8cb42d4..4e51052 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
@@ -47,7 +47,7 @@
 // Create an IPreparedModel object. If the model cannot be prepared,
 // "preparedModel" will be nullptr instead.
 void createPreparedModel(const sp<IDevice>& device, const Model& model,
-                         sp<IPreparedModel>* preparedModel);
+                         sp<IPreparedModel>* preparedModel, bool reportSkipping = true);
 
 // Utility function to get PreparedModel from callback and downcast to V1_2.
 sp<IPreparedModel> getPreparedModel_1_3(const sp<implementation::PreparedModelCallback>& callback);
diff --git a/radio/config/1.3/Android.bp b/radio/config/1.3/Android.bp
new file mode 100644
index 0000000..88de666
--- /dev/null
+++ b/radio/config/1.3/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.radio.config@1.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IRadioConfig.hal",
+        "IRadioConfigIndication.hal",
+        "IRadioConfigResponse.hal",
+    ],
+    interfaces: [
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/radio/config/1.3/IRadioConfig.hal b/radio/config/1.3/IRadioConfig.hal
new file mode 100644
index 0000000..a0ce6e0
--- /dev/null
+++ b/radio/config/1.3/IRadioConfig.hal
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 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.radio.config@1.3;
+
+import @1.1::IRadioConfig;
+
+/**
+ * This interface is used by telephony and telecom to talk to cellular radio for the purpose of
+ * radio configuration, and it is not associated with any specific modem or slot.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ */
+interface IRadioConfig extends @1.1::IRadioConfig {
+
+};
diff --git a/radio/config/1.3/IRadioConfigIndication.hal b/radio/config/1.3/IRadioConfigIndication.hal
new file mode 100644
index 0000000..9ef496c
--- /dev/null
+++ b/radio/config/1.3/IRadioConfigIndication.hal
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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.radio.config@1.3;
+
+import @1.2::IRadioConfigIndication;
+
+/**
+ * Interface declaring unsolicited radio config indications.
+ */
+interface IRadioConfigIndication extends @1.2::IRadioConfigIndication {
+
+};
diff --git a/radio/config/1.3/IRadioConfigResponse.hal b/radio/config/1.3/IRadioConfigResponse.hal
new file mode 100644
index 0000000..9c4c971
--- /dev/null
+++ b/radio/config/1.3/IRadioConfigResponse.hal
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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.radio.config@1.3;
+
+import @1.2::IRadioConfigResponse;
+
+/**
+ * Interface declaring response functions to solicited radio config requests.
+ */
+interface IRadioConfigResponse extends @1.2::IRadioConfigResponse {
+
+};
diff --git a/radio/config/1.3/default/Android.bp b/radio/config/1.3/default/Android.bp
new file mode 100644
index 0000000..163c5c5
--- /dev/null
+++ b/radio/config/1.3/default/Android.bp
@@ -0,0 +1,28 @@
+cc_binary {
+    name: "android.hardware.radio.config@1.3-service",
+    init_rc: ["android.hardware.radio.config@1.3-service.rc"],
+    relative_install_path: "hw",
+    vintf_fragments: ["radio-config-default.xml"],
+    vendor: true,
+    srcs: [
+        "RadioConfig.cpp",
+        "RadioConfigIndication.cpp",
+        "RadioConfigResponse.cpp",
+        "service.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio.config@1.3",
+        "android.hardware.radio@1.0",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.3",
+        "android.hardware.radio@1.4",
+        "android.hardware.radio@1.5",
+    ],
+}
diff --git a/radio/config/1.3/default/RadioConfig.cpp b/radio/config/1.3/default/RadioConfig.cpp
new file mode 100644
index 0000000..c28119c
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfig.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "RadioConfig.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config;
+
+// Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
+Return<void> RadioConfig::setResponseFunctions(
+        const sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
+        const sp<V1_0::IRadioConfigIndication>& radioConfigIndication) {
+    mRadioConfigResponse = radioConfigResponse;
+    mRadioConfigIndication = radioConfigIndication;
+
+    mRadioConfigResponseV1_3 =
+            V1_3::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_3 =
+            V1_3::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_3 == nullptr || mRadioConfigIndicationV1_3 == nullptr) {
+        mRadioConfigResponseV1_3 = nullptr;
+        mRadioConfigIndicationV1_3 = nullptr;
+    }
+
+    mRadioConfigResponseV1_2 =
+            V1_2::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_2 =
+            V1_2::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_2 == nullptr || mRadioConfigIndicationV1_2 == nullptr) {
+        mRadioConfigResponseV1_2 = nullptr;
+        mRadioConfigIndicationV1_2 = nullptr;
+    }
+
+    mRadioConfigResponseV1_1 =
+            V1_1::IRadioConfigResponse::castFrom(mRadioConfigResponse).withDefault(nullptr);
+    mRadioConfigIndicationV1_1 =
+            V1_1::IRadioConfigIndication::castFrom(mRadioConfigIndication).withDefault(nullptr);
+    if (mRadioConfigResponseV1_1 == nullptr || mRadioConfigIndicationV1_1 == nullptr) {
+        mRadioConfigResponseV1_1 = nullptr;
+        mRadioConfigIndicationV1_1 = nullptr;
+    }
+
+    return Void();
+}
+
+Return<void> RadioConfig::getSimSlotsStatus(int32_t /* serial */) {
+    hidl_vec<V1_0::SimSlotStatus> slotStatus;
+    RadioResponseInfo info;
+    mRadioConfigResponse->getSimSlotsStatusResponse(info, slotStatus);
+    return Void();
+}
+
+Return<void> RadioConfig::setSimSlotsMapping(int32_t /* serial */,
+                                             const hidl_vec<uint32_t>& /* slotMap */) {
+    RadioResponseInfo info;
+    mRadioConfigResponse->setSimSlotsMappingResponse(info);
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow.
+Return<void> RadioConfig::getPhoneCapability(int32_t /* serial */) {
+    V1_1::PhoneCapability phoneCapability;
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->getPhoneCapabilityResponse(info, phoneCapability);
+    return Void();
+}
+
+Return<void> RadioConfig::setPreferredDataModem(int32_t /* serial */, uint8_t /* modemId */) {
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->setPreferredDataModemResponse(info);
+    return Void();
+}
+
+Return<void> RadioConfig::setModemsConfig(int32_t /* serial */,
+                                          const V1_1::ModemsConfig& /* modemsConfig */) {
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->setModemsConfigResponse(info);
+    return Void();
+}
+
+Return<void> RadioConfig::getModemsConfig(int32_t /* serial */) {
+    V1_1::ModemsConfig modemsConfig;
+    RadioResponseInfo info;
+    mRadioConfigResponseV1_1->getModemsConfigResponse(info, modemsConfig);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfig.h b/radio/config/1.3/default/RadioConfig.h
new file mode 100644
index 0000000..00585e6
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfig.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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_RADIO_CONFIG_V1_3_RADIOCONFIG_H
+#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H
+
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::config;
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct RadioConfig : public V1_3::IRadioConfig {
+    sp<V1_0::IRadioConfigResponse> mRadioConfigResponse;
+    sp<V1_0::IRadioConfigIndication> mRadioConfigIndication;
+    sp<V1_1::IRadioConfigResponse> mRadioConfigResponseV1_1;
+    sp<V1_1::IRadioConfigIndication> mRadioConfigIndicationV1_1;
+    sp<V1_2::IRadioConfigResponse> mRadioConfigResponseV1_2;
+    sp<V1_2::IRadioConfigIndication> mRadioConfigIndicationV1_2;
+    sp<V1_3::IRadioConfigResponse> mRadioConfigResponseV1_3;
+    sp<V1_3::IRadioConfigIndication> mRadioConfigIndicationV1_3;
+
+    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfig follow.
+    Return<void> setResponseFunctions(
+            const sp<V1_0::IRadioConfigResponse>& radioConfigResponse,
+            const sp<V1_0::IRadioConfigIndication>& radioConfigIndication);
+    Return<void> getSimSlotsStatus(int32_t serial);
+    Return<void> setSimSlotsMapping(int32_t serial, const hidl_vec<uint32_t>& slotMap);
+
+    // Methods from ::android::hardware::radio::config::V1_1::IRadioConfig follow.
+    Return<void> getPhoneCapability(int32_t serial);
+    Return<void> setPreferredDataModem(int32_t serial, uint8_t modemId);
+    Return<void> setModemsConfig(int32_t serial, const V1_1::ModemsConfig& modemsConfig);
+    Return<void> getModemsConfig(int32_t serial);
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIG_H
diff --git a/radio/config/1.3/default/RadioConfigIndication.cpp b/radio/config/1.3/default/RadioConfigIndication.cpp
new file mode 100644
index 0000000..eb77a48
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigIndication.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "RadioConfigIndication.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config::V1_0;
+using namespace ::android::hardware::radio::config::V1_2;
+
+// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
+Return<void> RadioConfigIndication::simSlotsStatusChanged(
+        RadioIndicationType /* type */, const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow.
+Return<void> RadioConfigIndication::simSlotsStatusChanged_1_2(
+        RadioIndicationType /* type */, const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfigIndication.h b/radio/config/1.3/default/RadioConfigIndication.h
new file mode 100644
index 0000000..3697492
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigIndication.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
+#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
+
+#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config;
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct RadioConfigIndication : public IRadioConfigIndication {
+    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigIndication follow.
+    Return<void> simSlotsStatusChanged(RadioIndicationType type,
+                                       const hidl_vec<V1_0::SimSlotStatus>& slotStatus) override;
+
+    // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigIndication follow.
+    Return<void> simSlotsStatusChanged_1_2(
+            RadioIndicationType type, const hidl_vec<V1_2::SimSlotStatus>& slotStatus) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGINDICATION_H
diff --git a/radio/config/1.3/default/RadioConfigResponse.cpp b/radio/config/1.3/default/RadioConfigResponse.cpp
new file mode 100644
index 0000000..48e81da
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigResponse.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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 "RadioConfigResponse.h"
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using namespace ::android::hardware::radio::V1_0;
+using namespace ::android::hardware::radio::config::V1_0;
+using namespace ::android::hardware::radio::config::V1_1;
+using namespace ::android::hardware::radio::config::V1_2;
+
+// Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
+        const RadioResponseInfo& /* info */,
+        const hidl_vec<V1_0::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
+    // TODO implement
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
+        const RadioResponseInfo& /* info */, const V1_1::PhoneCapability& /* phoneCapability */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setPreferredDataModemResponse(
+        const RadioResponseInfo& /* info */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) {
+    // TODO implement
+    return Void();
+}
+
+Return<void> RadioConfigResponse::getModemsConfigResponse(
+        const RadioResponseInfo& /* info */, const V1_1::ModemsConfig& /* modemsConfig */) {
+    // TODO implement
+    return Void();
+}
+
+// Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
+        const RadioResponseInfo& /* info */,
+        const hidl_vec<V1_2::SimSlotStatus>& /* slotStatus */) {
+    // TODO implement
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
diff --git a/radio/config/1.3/default/RadioConfigResponse.h b/radio/config/1.3/default/RadioConfigResponse.h
new file mode 100644
index 0000000..0f0033f
--- /dev/null
+++ b/radio/config/1.3/default/RadioConfigResponse.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
+#define ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
+
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace radio {
+namespace config {
+namespace V1_3 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct RadioConfigResponse : public IRadioConfigResponse {
+    // Methods from ::android::hardware::radio::config::V1_0::IRadioConfigResponse follow.
+    Return<void> getSimSlotsStatusResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus)
+            override;
+    Return<void> setSimSlotsMappingResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+
+    // Methods from ::android::hardware::radio::config::V1_1::IRadioConfigResponse follow.
+    Return<void> getPhoneCapabilityResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::radio::config::V1_1::PhoneCapability& phoneCapability)
+            override;
+    Return<void> setPreferredDataModemResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+    Return<void> setModemsConfigResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info) override;
+    Return<void> getModemsConfigResponse(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const ::android::hardware::radio::config::V1_1::ModemsConfig& modemsConfig) override;
+
+    // Methods from ::android::hardware::radio::config::V1_2::IRadioConfigResponse follow.
+    Return<void> getSimSlotsStatusResponse_1_2(
+            const ::android::hardware::radio::V1_0::RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::config::V1_2::SimSlotStatus>& slotStatus)
+            override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+};
+
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace config
+}  // namespace radio
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_RADIO_CONFIG_V1_3_RADIOCONFIGRESPONSE_H
diff --git a/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc
new file mode 100644
index 0000000..6df9b52
--- /dev/null
+++ b/radio/config/1.3/default/android.hardware.radio.config@1.3-service.rc
@@ -0,0 +1,7 @@
+service vendor.radio-config-hal-1-3 /vendor/bin/hw/android.hardware.radio.config@1.3-service
+    interface android.hardware.radio.config@1.0::IRadioConfig default
+    interface android.hardware.radio.config@1.1::IRadioConfig default
+    interface android.hardware.radio.config@1.3::IRadioConfig default
+    class hal
+    user system
+    group system
diff --git a/radio/config/1.3/default/radio-config-default.xml b/radio/config/1.3/default/radio-config-default.xml
new file mode 100644
index 0000000..72f363e
--- /dev/null
+++ b/radio/config/1.3/default/radio-config-default.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, 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.
+*/
+-->
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.radio.config</name>
+        <transport>hwbinder</transport>
+        <version>1.3</version>
+        <interface>
+            <name>IRadioConfig</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/radio/config/1.3/default/service.cpp b/radio/config/1.3/default/service.cpp
new file mode 100644
index 0000000..b1e6736
--- /dev/null
+++ b/radio/config/1.3/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.radio.config@1.3-service"
+
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "RadioConfig.h"
+
+using android::OK;
+using android::sp;
+using android::status_t;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::radio::config::V1_3::IRadioConfig;
+using android::hardware::radio::config::V1_3::implementation::RadioConfig;
+
+int main() {
+    configureRpcThreadpool(1, true);
+    sp<IRadioConfig> radioConfig = new RadioConfig;
+    const status_t status = radioConfig->registerAsService();
+    ALOGW_IF(status != OK, "Could not register IRadioConfig 1.3");
+    ALOGD("Default service is ready.");
+
+    joinRpcThreadpool();
+    return 1;
+}
diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal
new file mode 100644
index 0000000..866002a
--- /dev/null
+++ b/radio/config/1.3/types.hal
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2019 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.radio.config@1.3;
diff --git a/radio/config/1.3/vts/functional/Android.bp b/radio/config/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..6b28faf
--- /dev/null
+++ b/radio/config/1.3/vts/functional/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_test {
+    name: "VtsHalRadioConfigV1_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "radio_config_hidl_hal_api.cpp",
+        "radio_config_hidl_hal_test.cpp",
+        "radio_config_response.cpp",
+        "VtsHalRadioConfigV1_3TargetTest.cpp",
+    ],
+    static_libs: [
+        "RadioVtsTestUtilBase",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+        "android.hardware.radio.config@1.2",
+        "android.hardware.radio.config@1.3",
+    ],
+    header_libs: ["radio.util.header@1.0"],
+    test_suites: ["general-tests", "vts-core"],
+}
diff --git a/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
new file mode 100644
index 0000000..3bacacf
--- /dev/null
+++ b/radio/config/1.3/vts/functional/VtsHalRadioConfigV1_3TargetTest.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 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 <radio_config_hidl_hal_utils.h>
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, RadioConfigHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                ::android::hardware::radio::config::V1_3::IRadioConfig::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
new file mode 100644
index 0000000..07e9ede
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_api.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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 <radio_config_hidl_hal_utils.h>
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
new file mode 100644
index 0000000..dbb4bf4
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_test.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 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 <radio_config_hidl_hal_utils.h>
+
+void RadioConfigHidlTest::SetUp() {
+    radioConfig = ::android::hardware::radio::config::V1_3::IRadioConfig::getService(GetParam());
+    ASSERT_NE(nullptr, radioConfig.get());
+
+    radioConfigRsp = new (std::nothrow) RadioConfigResponse(*this);
+    ASSERT_NE(nullptr, radioConfigRsp.get());
+
+    count_ = 0;
+
+    radioConfig->setResponseFunctions(radioConfigRsp, nullptr);
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioConfigHidlTest::notify(int receivedSerial) {
+    std::unique_lock<std::mutex> lock(mtx_);
+    if (serial == receivedSerial) {
+        count_++;
+        cv_.notify_one();
+    }
+}
+
+/*
+ * Wait till the response message is notified or till TIMEOUT_PERIOD.
+ */
+std::cv_status RadioConfigHidlTest::wait() {
+    std::unique_lock<std::mutex> lock(mtx_);
+
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count_ == 0) {
+        status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
+        }
+    }
+    count_--;
+    return status;
+}
diff --git a/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
new file mode 100644
index 0000000..9b78c04
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_hidl_hal_utils.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2019 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 <android-base/logging.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include <android/hardware/radio/config/1.3/IRadioConfig.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigIndication.h>
+#include <android/hardware/radio/config/1.3/IRadioConfigResponse.h>
+#include <android/hardware/radio/config/1.3/types.h>
+
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
+
+#include "vts_test_util.h"
+
+using namespace ::android::hardware::radio::config::V1_1;
+using namespace ::android::hardware::radio::config::V1_2;
+using namespace ::android::hardware::radio::config::V1_3;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
+using ::android::hardware::radio::V1_0::RadioResponseType;
+
+#define TIMEOUT_PERIOD 75
+
+class RadioConfigHidlTest;
+
+/* Callback class for radio config response */
+class RadioConfigResponse : public ::android::hardware::radio::config::V1_3::IRadioConfigResponse {
+  protected:
+    RadioConfigHidlTest& parent;
+
+  public:
+    RadioResponseInfo rspInfo;
+    PhoneCapability phoneCap;
+
+    RadioConfigResponse(RadioConfigHidlTest& parent);
+    virtual ~RadioConfigResponse() = default;
+
+    /* 1.0 Api */
+    Return<void> getSimSlotsStatusResponse(
+            const RadioResponseInfo& info,
+            const hidl_vec<::android::hardware::radio::config::V1_0::SimSlotStatus>& slotStatus);
+
+    Return<void> setSimSlotsMappingResponse(const RadioResponseInfo& info);
+
+    /* 1.1 Api */
+    Return<void> getPhoneCapabilityResponse(const RadioResponseInfo& info,
+                                            const PhoneCapability& phoneCapability);
+
+    Return<void> setPreferredDataModemResponse(const RadioResponseInfo& info);
+
+    Return<void> getModemsConfigResponse(const RadioResponseInfo& info,
+                                         const ModemsConfig& mConfig);
+
+    Return<void> setModemsConfigResponse(const RadioResponseInfo& info);
+
+    /* 1.2 Api */
+    Return<void> getSimSlotsStatusResponse_1_2(const RadioResponseInfo& info,
+                                               const hidl_vec<SimSlotStatus>& slotStatus);
+};
+
+/* Callback class for radio config indication */
+class RadioConfigIndication
+    : public ::android::hardware::radio::config::V1_3::IRadioConfigIndication {
+  protected:
+    RadioConfigHidlTest& parent;
+
+  public:
+    RadioConfigIndication(RadioConfigHidlTest& parent);
+    virtual ~RadioConfigIndication() = default;
+
+    /* 1.2 Api */
+    Return<void> simSlotsStatusChanged_1_2(
+            ::android::hardware::radio::V1_0::RadioIndicationType type,
+            const hidl_vec<SimSlotStatus>& slotStatus);
+};
+
+// The main test class for Radio config HIDL.
+class RadioConfigHidlTest : public ::testing::TestWithParam<std::string> {
+  protected:
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_;
+
+  public:
+    virtual void SetUp() override;
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    void notify(int receivedSerial);
+
+    /* Test code calls this function to wait for response */
+    std::cv_status wait();
+
+    void updateSimCardStatus();
+
+    /* Serial number for radio request */
+    int serial;
+
+    /* radio config service handle */
+    sp<::android::hardware::radio::config::V1_3::IRadioConfig> radioConfig;
+
+    /* radio config response handle */
+    sp<RadioConfigResponse> radioConfigRsp;
+};
diff --git a/radio/config/1.3/vts/functional/radio_config_response.cpp b/radio/config/1.3/vts/functional/radio_config_response.cpp
new file mode 100644
index 0000000..1ca960e
--- /dev/null
+++ b/radio/config/1.3/vts/functional/radio_config_response.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 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 <radio_config_hidl_hal_utils.h>
+
+using ::android::hardware::radio::V1_0::RadioResponseInfo;
+
+// SimSlotStatus slotStatus;
+
+RadioConfigResponse::RadioConfigResponse(RadioConfigHidlTest& parent) : parent(parent) {}
+
+/* 1.0 Apis */
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse(
+        const RadioResponseInfo& /* info */,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::config::V1_0::SimSlotStatus>& /* slotStatus */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setSimSlotsMappingResponse(const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioConfigResponse::getPhoneCapabilityResponse(
+        const RadioResponseInfo& info, const PhoneCapability& phoneCapability) {
+    rspInfo = info;
+    phoneCap = phoneCapability;
+    parent.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setPreferredDataModemResponse(
+        const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::getModemsConfigResponse(const RadioResponseInfo& /* info */,
+                                                          const ModemsConfig& /* mConfig */) {
+    return Void();
+}
+
+Return<void> RadioConfigResponse::setModemsConfigResponse(const RadioResponseInfo& /* info */) {
+    return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioConfigResponse::getSimSlotsStatusResponse_1_2(
+        const RadioResponseInfo& /* info */,
+        const ::android::hardware::hidl_vec<SimSlotStatus>& /* slotStatus */) {
+    return Void();
+}
\ No newline at end of file