Merge "Remove Secure Storage AIDL tamper and A/B update" into main
diff --git a/Android.bp b/Android.bp
index baf3291..223a1a9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,6 +51,7 @@
     // Lists all dependencies that can *not* be expected on the device.
     static_libs: [
         "VtsHalHidlTestUtils",
+        "libhidlbase",
         "libhidl-gen-utils",
     ],
 
@@ -63,7 +64,6 @@
         "libbase",
         // All the following are dependencies of any HAL definition library.
         "libcutils",
-        "libhidlbase",
         "liblog",
         "libutils",
     ],
@@ -72,6 +72,14 @@
         "-g",
     ],
 
+    target: {
+        android: {
+            shared_libs: [
+                "libvndksupport",
+            ],
+        },
+    },
+
     require_root: true,
 }
 
diff --git a/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
index c92e852..4170b4c 100644
--- a/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
+++ b/audio/aidl/vts/VtsHalAudioTargetTestTemplate.xml
@@ -33,6 +33,6 @@
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="{MODULE}" />
-        <option name="native-test-timeout" value="10m" />
+        <option name="native-test-timeout" value="30m" />
     </test>
 </configuration>
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index 82a194e..e31aae6 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -353,8 +353,14 @@
         mInput.resize(kBufferSize);
         generateSineWaveInput(mInput);
     }
-    void SetUp() override { SetUpReverb(); }
-    void TearDown() override { TearDownReverb(); }
+    void SetUp() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        SetUpReverb();
+    }
+    void TearDown() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        TearDownReverb();
+    }
 
     void assertEnergyIncreasingWithParameter(bool bypass) {
         createEnvParam(EnvironmentalReverb::bypass, bypass);
@@ -418,12 +424,16 @@
         std::tie(mTag, mValue) = std::get<TAG_VALUE_PAIR>(GetParam());
     }
     void SetUp() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
         SetUpReverb();
         createEnvParam(EnvironmentalReverb::roomLevelMb, kMinRoomLevel);
         ASSERT_NO_FATAL_FAILURE(
                 setAndVerifyParam(EX_NONE, mEnvParam, EnvironmentalReverb::roomLevelMb));
     }
-    void TearDown() override { TearDownReverb(); }
+    void TearDown() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        TearDownReverb();
+    }
 
     EnvironmentalReverb::Tag mTag;
     int mValue;
@@ -469,8 +479,14 @@
         mInput.resize(kBufferSize);
         generateSineWaveInput(mInput);
     }
-    void SetUp() override { SetUpReverb(); }
-    void TearDown() override { TearDownReverb(); }
+    void SetUp() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        SetUpReverb();
+    }
+    void TearDown() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        TearDownReverb();
+    }
 
     float getMean(std::vector<float>& buffer) {
         return std::accumulate(buffer.begin(), buffer.end(), 0.0) / buffer.size();
@@ -543,8 +559,14 @@
             generateSineWaveInput(mInput);
         }
     }
-    void SetUp() override { SetUpReverb(); }
-    void TearDown() override { TearDownReverb(); }
+    void SetUp() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        SetUpReverb();
+    }
+    void TearDown() override {
+        SKIP_TEST_IF_DATA_UNSUPPORTED(mDescriptor.common.flags);
+        TearDownReverb();
+    }
 
     EnvironmentalReverb::Tag mTag;
     int mParamValues;
diff --git a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
index 477de31..dc78ed6 100644
--- a/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
+++ b/automotive/evs/aidl/vts/VtsHalEvsTargetTest.cpp
@@ -317,12 +317,20 @@
             // Verify methods for extended info
             const auto id = 0xFFFFFFFF;  // meaningless id
             std::vector<uint8_t> values;
+            bool isSupported = false;
             auto status = pCam->setExtendedInfo(id, values);
             if (isLogicalCam) {
                 EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
                                                       static_cast<int>(EvsResult::NOT_SUPPORTED));
             } else {
-                EXPECT_TRUE(status.isOk());
+                if (status.isOk()) {
+                    // 0xFFFFFFFF is valid for EVS HAL implementation under
+                    // test.
+                    isSupported = true;
+                } else {
+                    EXPECT_TRUE(status.getServiceSpecificError() ==
+                                static_cast<int>(EvsResult::INVALID_ARG));
+                }
             }
 
             status = pCam->getExtendedInfo(id, &values);
@@ -330,7 +338,12 @@
                 EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
                                                       static_cast<int>(EvsResult::NOT_SUPPORTED));
             } else {
-                EXPECT_TRUE(status.isOk());
+                if (isSupported) {
+                    EXPECT_TRUE(status.isOk());
+                } else {
+                    EXPECT_TRUE(!status.isOk() && status.getServiceSpecificError() ==
+                                                    static_cast<int>(EvsResult::INVALID_ARG));
+                }
             }
 
             // Explicitly close the camera so resources are released right away
diff --git a/automotive/vehicle/TEST_MAPPING b/automotive/vehicle/TEST_MAPPING
index 77629a9..d848774 100644
--- a/automotive/vehicle/TEST_MAPPING
+++ b/automotive/vehicle/TEST_MAPPING
@@ -45,6 +45,9 @@
       "name": "FakeVehicleHardwareTest"
     },
     {
+      "name": "GRPCVehicleHardwareUnitTest"
+    },
+    {
       "name": "CarServiceUnitTest",
       "options" : [
         {
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
index f44573a..73bb521 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.cpp
@@ -20,6 +20,7 @@
 
 #include <android-base/logging.h>
 #include <grpc++/grpc++.h>
+#include <utils/SystemClock.h>
 
 #include <cstdlib>
 #include <mutex>
@@ -28,11 +29,16 @@
 
 namespace android::hardware::automotive::vehicle::virtualization {
 
-static std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
-    // TODO(chenhaosjtuacm): get secured credentials here
+namespace {
+
+constexpr size_t MAX_RETRY_COUNT = 5;
+
+std::shared_ptr<::grpc::ChannelCredentials> getChannelCredentials() {
     return ::grpc::InsecureChannelCredentials();
 }
 
+}  // namespace
+
 GRPCVehicleHardware::GRPCVehicleHardware(std::string service_addr)
     : mServiceAddr(std::move(service_addr)),
       mGrpcChannel(::grpc::CreateChannel(mServiceAddr, getChannelCredentials())),
@@ -40,11 +46,13 @@
       mValuePollingThread([this] { ValuePollingLoop(); }) {}
 
 // Only used for unit testing.
-GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub)
-    : mServiceAddr(""),
-      mGrpcChannel(nullptr),
-      mGrpcStub(std::move(stub)),
-      mValuePollingThread([] {}) {}
+GRPCVehicleHardware::GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub,
+                                         bool startValuePollingLoop)
+    : mServiceAddr(""), mGrpcChannel(nullptr), mGrpcStub(std::move(stub)) {
+    if (startValuePollingLoop) {
+        mValuePollingThread = std::thread([this] { ValuePollingLoop(); });
+    }
+}
 
 GRPCVehicleHardware::~GRPCVehicleHardware() {
     {
@@ -52,7 +60,9 @@
         mShuttingDownFlag.store(true);
     }
     mShutdownCV.notify_all();
-    mValuePollingThread.join();
+    if (mValuePollingThread.joinable()) {
+        mValuePollingThread.join();
+    }
 }
 
 std::vector<aidlvhal::VehiclePropConfig> GRPCVehicleHardware::getAllPropertyConfigs() const {
@@ -109,36 +119,117 @@
 aidlvhal::StatusCode GRPCVehicleHardware::getValues(
         std::shared_ptr<const GetValuesCallback> callback,
         const std::vector<aidlvhal::GetValueRequest>& requests) const {
-    ::grpc::ClientContext context;
+    std::vector<aidlvhal::GetValueResult> results;
+    auto status = getValuesWithRetry(requests, &results, /*retryCount=*/0);
+    if (status != aidlvhal::StatusCode::OK) {
+        return status;
+    }
+    if (!results.empty()) {
+        (*callback)(std::move(results));
+    }
+    return status;
+}
+
+aidlvhal::StatusCode GRPCVehicleHardware::getValuesWithRetry(
+        const std::vector<aidlvhal::GetValueRequest>& requests,
+        std::vector<aidlvhal::GetValueResult>* results, size_t retryCount) const {
+    if (retryCount == MAX_RETRY_COUNT) {
+        LOG(ERROR) << __func__ << ": GRPC GetValues Failed, failed to get the latest value after "
+                   << retryCount << " retries";
+        return aidlvhal::StatusCode::TRY_AGAIN;
+    }
+
     proto::VehiclePropValueRequests protoRequests;
-    proto::GetValueResults protoResults;
+    std::unordered_map<int64_t, const aidlvhal::GetValueRequest*> requestById;
     for (const auto& request : requests) {
         auto& protoRequest = *protoRequests.add_requests();
         protoRequest.set_request_id(request.requestId);
         proto_msg_converter::aidlToProto(request.prop, protoRequest.mutable_value());
+        requestById[request.requestId] = &request;
     }
+
     // TODO(chenhaosjtuacm): Make it Async.
+    ::grpc::ClientContext context;
+    proto::GetValueResults protoResults;
     auto grpc_status = mGrpcStub->GetValues(&context, protoRequests, &protoResults);
     if (!grpc_status.ok()) {
         LOG(ERROR) << __func__ << ": GRPC GetValues Failed: " << grpc_status.error_message();
         return aidlvhal::StatusCode::INTERNAL_ERROR;
     }
-    std::vector<aidlvhal::GetValueResult> results;
+
+    std::vector<aidlvhal::GetValueRequest> retryRequests;
     for (const auto& protoResult : protoResults.results()) {
-        auto& result = results.emplace_back();
-        result.requestId = protoResult.request_id();
-        result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
-        if (protoResult.has_value()) {
-            aidlvhal::VehiclePropValue value;
-            proto_msg_converter::protoToAidl(protoResult.value(), &value);
-            result.prop = std::move(value);
+        int64_t requestId = protoResult.request_id();
+        auto it = requestById.find(requestId);
+        if (it == requestById.end()) {
+            LOG(ERROR) << __func__
+                       << "Invalid getValue request with unknown request ID: " << requestId
+                       << ", ignore";
+            continue;
         }
+
+        if (!protoResult.has_value()) {
+            auto& result = results->emplace_back();
+            result.requestId = requestId;
+            result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
+            continue;
+        }
+
+        aidlvhal::VehiclePropValue value;
+        proto_msg_converter::protoToAidl(protoResult.value(), &value);
+
+        // VHAL proxy server uses a different timestamp then AAOS timestamp, so we have to reset
+        // the timestamp.
+        // TODO(b/350822044): Remove this once we use timestamp from proxy server.
+        if (!setAndroidTimestamp(&value)) {
+            // This is a rare case when we receive a property update event reflecting a new value
+            // for the property before we receive the get value result. This means that the result
+            // is already outdated, hence we should retry getting the latest value again.
+            LOG(WARNING) << __func__ << "getValue result for propId: " << value.prop
+                         << " areaId: " << value.areaId << " is oudated, retry";
+            retryRequests.push_back(*(it->second));
+            continue;
+        }
+
+        auto& result = results->emplace_back();
+        result.requestId = requestId;
+        result.status = static_cast<aidlvhal::StatusCode>(protoResult.status());
+        result.prop = std::move(value);
     }
-    (*callback)(std::move(results));
+
+    if (retryRequests.size() != 0) {
+        return getValuesWithRetry(retryRequests, results, retryCount++);
+    }
 
     return aidlvhal::StatusCode::OK;
 }
 
+bool GRPCVehicleHardware::setAndroidTimestamp(aidlvhal::VehiclePropValue* propValue) const {
+    PropIdAreaId propIdAreaId = {
+            .propId = propValue->prop,
+            .areaId = propValue->areaId,
+    };
+    int64_t now = elapsedRealtimeNano();
+    int64_t externalTimestamp = propValue->timestamp;
+
+    {
+        std::lock_guard lck(mLatestUpdateTimestampsMutex);
+        auto it = mLatestUpdateTimestamps.find(propIdAreaId);
+        if (it == mLatestUpdateTimestamps.end() || externalTimestamp > (it->second).first) {
+            mLatestUpdateTimestamps[propIdAreaId].first = externalTimestamp;
+            mLatestUpdateTimestamps[propIdAreaId].second = now;
+            propValue->timestamp = now;
+            return true;
+        }
+        if (externalTimestamp == (it->second).first) {
+            propValue->timestamp = (it->second).second;
+            return true;
+        }
+    }
+    // externalTimestamp < (it->second).first, the value is outdated.
+    return false;
+}
+
 void GRPCVehicleHardware::registerOnPropertyChangeEvent(
         std::unique_ptr<const PropertyChangeCallback> callback) {
     std::lock_guard lck(mCallbackMutex);
@@ -248,46 +339,61 @@
 
 void GRPCVehicleHardware::ValuePollingLoop() {
     while (!mShuttingDownFlag.load()) {
-        ::grpc::ClientContext context;
-
-        bool rpc_stopped{false};
-        std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() {
-            std::unique_lock<std::mutex> lck(mShutdownMutex);
-            mShutdownCV.wait(lck, [this, &rpc_stopped]() {
-                return rpc_stopped || mShuttingDownFlag.load();
-            });
-            context.TryCancel();
-        });
-
-        auto value_stream =
-                mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
-        LOG(INFO) << __func__ << ": GRPC Value Streaming Started";
-        proto::VehiclePropValues protoValues;
-        while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) {
-            std::vector<aidlvhal::VehiclePropValue> values;
-            for (const auto protoValue : protoValues.values()) {
-                values.push_back(aidlvhal::VehiclePropValue());
-                proto_msg_converter::protoToAidl(protoValue, &values.back());
-            }
-            std::shared_lock lck(mCallbackMutex);
-            if (mOnPropChange) {
-                (*mOnPropChange)(values);
-            }
-        }
-
-        {
-            std::lock_guard lck(mShutdownMutex);
-            rpc_stopped = true;
-        }
-        mShutdownCV.notify_all();
-        shuttingdown_watcher.join();
-
-        auto grpc_status = value_stream->Finish();
-        // never reach here until connection lost
-        LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
-
+        pollValue();
         // try to reconnect
     }
 }
 
+void GRPCVehicleHardware::pollValue() {
+    ::grpc::ClientContext context;
+
+    bool rpc_stopped{false};
+    std::thread shuttingdown_watcher([this, &rpc_stopped, &context]() {
+        std::unique_lock<std::mutex> lck(mShutdownMutex);
+        mShutdownCV.wait(
+                lck, [this, &rpc_stopped]() { return rpc_stopped || mShuttingDownFlag.load(); });
+        context.TryCancel();
+    });
+
+    auto value_stream = mGrpcStub->StartPropertyValuesStream(&context, ::google::protobuf::Empty());
+    LOG(INFO) << __func__ << ": GRPC Value Streaming Started";
+    proto::VehiclePropValues protoValues;
+    while (!mShuttingDownFlag.load() && value_stream->Read(&protoValues)) {
+        std::vector<aidlvhal::VehiclePropValue> values;
+        for (const auto protoValue : protoValues.values()) {
+            aidlvhal::VehiclePropValue aidlValue = {};
+            proto_msg_converter::protoToAidl(protoValue, &aidlValue);
+
+            // VHAL proxy server uses a different timestamp then AAOS timestamp, so we have to
+            // reset the timestamp.
+            // TODO(b/350822044): Remove this once we use timestamp from proxy server.
+            if (!setAndroidTimestamp(&aidlValue)) {
+                LOG(WARNING) << __func__ << ": property event for propId: " << aidlValue.prop
+                             << " areaId: " << aidlValue.areaId << " is outdated, ignore";
+                continue;
+            }
+
+            values.push_back(std::move(aidlValue));
+        }
+        if (values.empty()) {
+            continue;
+        }
+        std::shared_lock lck(mCallbackMutex);
+        if (mOnPropChange) {
+            (*mOnPropChange)(values);
+        }
+    }
+
+    {
+        std::lock_guard lck(mShutdownMutex);
+        rpc_stopped = true;
+    }
+    mShutdownCV.notify_all();
+    shuttingdown_watcher.join();
+
+    auto grpc_status = value_stream->Finish();
+    // never reach here until connection lost
+    LOG(ERROR) << __func__ << ": GRPC Value Streaming Failed: " << grpc_status.error_message();
+}
+
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
index 9750f62..1edf658 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleHardware.h
@@ -20,6 +20,7 @@
 #include <VehicleHalTypes.h>
 #include <VehicleUtils.h>
 #include <android-base/result.h>
+#include <android-base/thread_annotations.h>
 
 #include "VehicleServer.grpc.pb.h"
 #include "VehicleServer.pb.h"
@@ -33,6 +34,7 @@
 #include <shared_mutex>
 #include <string>
 #include <thread>
+#include <unordered_map>
 #include <vector>
 
 namespace android::hardware::automotive::vehicle::virtualization {
@@ -43,9 +45,6 @@
   public:
     explicit GRPCVehicleHardware(std::string service_addr);
 
-    // Only used for unit testing.
-    explicit GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub);
-
     ~GRPCVehicleHardware();
 
     // Get all the property configs.
@@ -94,7 +93,7 @@
     std::unique_ptr<const PropertyChangeCallback> mOnPropChange;
 
   private:
-    void ValuePollingLoop();
+    friend class GRPCVehicleHardwareUnitTest;
 
     std::string mServiceAddr;
     std::shared_ptr<::grpc::Channel> mGrpcChannel;
@@ -106,6 +105,31 @@
     std::mutex mShutdownMutex;
     std::condition_variable mShutdownCV;
     std::atomic<bool> mShuttingDownFlag{false};
+
+    mutable std::mutex mLatestUpdateTimestampsMutex;
+
+    // A map from [propId, areaId] to the latest timestamp this property is updated.
+    // The key is a tuple, the first element is the external timestamp (timestamp set by VHAL
+    // server), the second element is the Android timestamp (elapsedRealtimeNano).
+    mutable std::unordered_map<PropIdAreaId, std::pair<int64_t, int64_t>,
+                               PropIdAreaIdHash> mLatestUpdateTimestamps
+            GUARDED_BY(mLatestUpdateTimestampsMutex);
+
+    // Only used for unit testing.
+    GRPCVehicleHardware(std::unique_ptr<proto::VehicleServer::StubInterface> stub,
+                        bool startValuePollingLoop);
+
+    void ValuePollingLoop();
+    void pollValue();
+
+    aidlvhal::StatusCode getValuesWithRetry(const std::vector<aidlvhal::GetValueRequest>& requests,
+                                            std::vector<aidlvhal::GetValueResult>* results,
+                                            size_t retryCount) const;
+
+    // Check the external timestamp of propValue against the latest updated external timestamp, if
+    // this is an outdated value, return false. Otherwise, update the external timestamp to the
+    // Android timestamp and return true.
+    bool setAndroidTimestamp(aidlvhal::VehiclePropValue* propValue) const;
 };
 
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
index eb98af0..d7cbe1b 100644
--- a/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/GRPCVehicleProxyServer.cpp
@@ -69,10 +69,13 @@
                                                  const proto::VehiclePropValueRequests* requests,
                                                  proto::SetValueResults* results) {
     std::vector<aidlvhal::SetValueRequest> aidlRequests;
+    std::unordered_set<int64_t> requestIds;
     for (const auto& protoRequest : requests->requests()) {
         auto& aidlRequest = aidlRequests.emplace_back();
-        aidlRequest.requestId = protoRequest.request_id();
+        int64_t requestId = protoRequest.request_id();
+        aidlRequest.requestId = requestId;
         proto_msg_converter::protoToAidl(protoRequest.value(), &aidlRequest.value);
+        requestIds.insert(requestId);
     }
     auto waitMtx = std::make_shared<std::mutex>();
     auto waitCV = std::make_shared<std::condition_variable>();
@@ -80,19 +83,27 @@
     auto tmpResults = std::make_shared<proto::SetValueResults>();
     auto aidlStatus = mHardware->setValues(
             std::make_shared<const IVehicleHardware::SetValuesCallback>(
-                    [waitMtx, waitCV, complete,
-                     tmpResults](std::vector<aidlvhal::SetValueResult> setValueResults) {
-                        for (const auto& aidlResult : setValueResults) {
-                            auto& protoResult = *tmpResults->add_results();
-                            protoResult.set_request_id(aidlResult.requestId);
-                            protoResult.set_status(
-                                    static_cast<proto::StatusCode>(aidlResult.status));
-                        }
+                    [waitMtx, waitCV, complete, tmpResults,
+                     &requestIds](std::vector<aidlvhal::SetValueResult> setValueResults) {
+                        bool receivedAllResults = false;
                         {
                             std::lock_guard lck(*waitMtx);
-                            *complete = true;
+                            for (const auto& aidlResult : setValueResults) {
+                                auto& protoResult = *tmpResults->add_results();
+                                int64_t requestIdForResult = aidlResult.requestId;
+                                protoResult.set_request_id(requestIdForResult);
+                                protoResult.set_status(
+                                        static_cast<proto::StatusCode>(aidlResult.status));
+                                requestIds.erase(requestIdForResult);
+                            }
+                            if (requestIds.empty()) {
+                                receivedAllResults = true;
+                                *complete = true;
+                            }
                         }
-                        waitCV->notify_all();
+                        if (receivedAllResults) {
+                            waitCV->notify_all();
+                        }
                     }),
             aidlRequests);
     if (aidlStatus != aidlvhal::StatusCode::OK) {
@@ -114,10 +125,13 @@
                                                  const proto::VehiclePropValueRequests* requests,
                                                  proto::GetValueResults* results) {
     std::vector<aidlvhal::GetValueRequest> aidlRequests;
+    std::unordered_set<int64_t> requestIds;
     for (const auto& protoRequest : requests->requests()) {
         auto& aidlRequest = aidlRequests.emplace_back();
-        aidlRequest.requestId = protoRequest.request_id();
+        int64_t requestId = protoRequest.request_id();
+        aidlRequest.requestId = requestId;
         proto_msg_converter::protoToAidl(protoRequest.value(), &aidlRequest.prop);
+        requestIds.insert(requestId);
     }
     auto waitMtx = std::make_shared<std::mutex>();
     auto waitCV = std::make_shared<std::condition_variable>();
@@ -125,23 +139,31 @@
     auto tmpResults = std::make_shared<proto::GetValueResults>();
     auto aidlStatus = mHardware->getValues(
             std::make_shared<const IVehicleHardware::GetValuesCallback>(
-                    [waitMtx, waitCV, complete,
-                     tmpResults](std::vector<aidlvhal::GetValueResult> getValueResults) {
-                        for (const auto& aidlResult : getValueResults) {
-                            auto& protoResult = *tmpResults->add_results();
-                            protoResult.set_request_id(aidlResult.requestId);
-                            protoResult.set_status(
-                                    static_cast<proto::StatusCode>(aidlResult.status));
-                            if (aidlResult.prop) {
-                                auto* valuePtr = protoResult.mutable_value();
-                                proto_msg_converter::aidlToProto(*aidlResult.prop, valuePtr);
-                            }
-                        }
+                    [waitMtx, waitCV, complete, tmpResults,
+                     &requestIds](std::vector<aidlvhal::GetValueResult> getValueResults) {
+                        bool receivedAllResults = false;
                         {
                             std::lock_guard lck(*waitMtx);
-                            *complete = true;
+                            for (const auto& aidlResult : getValueResults) {
+                                auto& protoResult = *tmpResults->add_results();
+                                int64_t requestIdForResult = aidlResult.requestId;
+                                protoResult.set_request_id(requestIdForResult);
+                                protoResult.set_status(
+                                        static_cast<proto::StatusCode>(aidlResult.status));
+                                if (aidlResult.prop) {
+                                    auto* valuePtr = protoResult.mutable_value();
+                                    proto_msg_converter::aidlToProto(*aidlResult.prop, valuePtr);
+                                }
+                                requestIds.erase(requestIdForResult);
+                            }
+                            if (requestIds.empty()) {
+                                receivedAllResults = true;
+                                *complete = true;
+                            }
                         }
-                        waitCV->notify_all();
+                        if (receivedAllResults) {
+                            waitCV->notify_all();
+                        }
                     }),
             aidlRequests);
     if (aidlStatus != aidlvhal::StatusCode::OK) {
diff --git a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
index 3bd7e0e..20af231 100644
--- a/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
+++ b/automotive/vehicle/aidl/impl/grpc/test/GRPCVehicleHardwareUnitTest.cpp
@@ -19,8 +19,10 @@
 
 #include <gmock/gmock.h>
 #include <grpc++/grpc++.h>
+#include <grpcpp/test/mock_stream.h>
 #include <gtest/gtest.h>
 
+#include <utils/SystemClock.h>
 #include <chrono>
 #include <memory>
 #include <string>
@@ -31,98 +33,48 @@
 
 using ::testing::_;
 using ::testing::DoAll;
+using ::testing::ElementsAre;
 using ::testing::NiceMock;
 using ::testing::Return;
 using ::testing::SaveArg;
 using ::testing::SetArgPointee;
+using ::testing::SizeIs;
+
+using ::grpc::testing::MockClientReader;
 
 using proto::MockVehicleServerStub;
 
-const std::string kFakeServerAddr = "0.0.0.0:54321";
-
-class FakeVehicleServer : public proto::VehicleServer::Service {
-  public:
-    ::grpc::Status StartPropertyValuesStream(
-            ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-            ::grpc::ServerWriter<proto::VehiclePropValues>* stream) override {
-        stream->Write(proto::VehiclePropValues());
-        // A fake disconnection.
-        return ::grpc::Status(::grpc::StatusCode::ABORTED, "Connection lost.");
-    }
-
-    // Functions that we do not care.
-    ::grpc::Status GetAllPropertyConfig(
-            ::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
-            ::grpc::ServerWriter<proto::VehiclePropConfig>* stream) override {
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status SetValues(::grpc::ServerContext* context,
-                             const proto::VehiclePropValueRequests* requests,
-                             proto::SetValueResults* results) override {
-        return ::grpc::Status::OK;
-    }
-
-    ::grpc::Status GetValues(::grpc::ServerContext* context,
-                             const proto::VehiclePropValueRequests* requests,
-                             proto::GetValueResults* results) override {
-        return ::grpc::Status::OK;
-    }
-};
-
-TEST(GRPCVehicleHardwareUnitTest, Reconnect) {
-    auto receivedUpdate = std::make_shared<std::atomic<int>>(0);
-    auto vehicleHardware = std::make_unique<GRPCVehicleHardware>(kFakeServerAddr);
-    vehicleHardware->registerOnPropertyChangeEvent(
-            std::make_unique<const IVehicleHardware::PropertyChangeCallback>(
-                    [receivedUpdate](const auto&) { receivedUpdate->fetch_add(1); }));
-
-    constexpr size_t kServerRestartTimes = 5;
-    for (size_t serverStart = 0; serverStart < kServerRestartTimes; ++serverStart) {
-        EXPECT_EQ(receivedUpdate->load(), 0);
-        auto fakeServer = std::make_unique<FakeVehicleServer>();
-        ::grpc::ServerBuilder builder;
-        builder.RegisterService(fakeServer.get());
-        builder.AddListeningPort(kFakeServerAddr, ::grpc::InsecureServerCredentials());
-        auto grpcServer = builder.BuildAndStart();
-
-        // Wait until the vehicle hardware received the second update (after one fake
-        // disconnection).
-        constexpr auto kMaxWaitTime = std::chrono::seconds(5);
-        auto startTime = std::chrono::steady_clock::now();
-        while (receivedUpdate->load() <= 1 &&
-               std::chrono::steady_clock::now() - startTime < kMaxWaitTime)
-            ;
-
-        grpcServer->Shutdown();
-        grpcServer->Wait();
-        EXPECT_GT(receivedUpdate->load(), 1);
-
-        // Reset for the next round.
-        receivedUpdate->store(0);
-    }
-}
-
-class GRPCVehicleHardwareMockServerUnitTest : public ::testing::Test {
+class GRPCVehicleHardwareUnitTest : public ::testing::Test {
   protected:
     NiceMock<MockVehicleServerStub>* mGrpcStub;
     std::unique_ptr<GRPCVehicleHardware> mHardware;
 
     void SetUp() override {
         auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
-        ;
         mGrpcStub = stub.get();
-        mHardware = std::make_unique<GRPCVehicleHardware>(std::move(stub));
+        // Cannot use make_unique here since the constructor is a private method.
+        mHardware = std::unique_ptr<GRPCVehicleHardware>(
+                new GRPCVehicleHardware(std::move(stub), /*startValuePollingLoop=*/false));
     }
 
     void TearDown() override { mHardware.reset(); }
+
+    // Access GRPCVehicleHardware private method.
+    void pollValue() { mHardware->pollValue(); }
+
+    void startValuePollingLoop(std::unique_ptr<proto::VehicleServer::StubInterface> stub) {
+        mHardware = std::unique_ptr<GRPCVehicleHardware>(
+                new GRPCVehicleHardware(std::move(stub), /*startValuePollingLoop=*/true));
+    }
+
+    void generatePropertyUpdateEvent(int32_t propId, int64_t timestamp);
 };
 
 MATCHER_P(RepeatedInt32Eq, expected_values, "") {
     return std::vector<int32_t>(arg.begin(), arg.end()) == expected_values;
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, Subscribe) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribe) {
     proto::VehicleHalCallStatus protoStatus;
     protoStatus.set_status_code(proto::StatusCode::OK);
     proto::SubscribeRequest actualRequest;
@@ -147,7 +99,7 @@
     EXPECT_EQ(protoOptions.enable_variable_update_rate(), true);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeLegacyServer) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribeLegacyServer) {
     EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
             .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
 
@@ -157,7 +109,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::OK);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeGrpcFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribeGrpcFailure) {
     EXPECT_CALL(*mGrpcStub, Subscribe(_, _, _))
             .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
 
@@ -167,7 +119,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, SubscribeProtoFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestSubscribeProtoFailure) {
     proto::VehicleHalCallStatus protoStatus;
     protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
 
@@ -181,7 +133,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, Unsubscribe) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribe) {
     proto::VehicleHalCallStatus protoStatus;
     protoStatus.set_status_code(proto::StatusCode::OK);
     proto::UnsubscribeRequest actualRequest;
@@ -199,7 +151,7 @@
     EXPECT_EQ(actualRequest.area_id(), areaId);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeLegacyServer) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribeLegacyServer) {
     EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
             .WillOnce(Return(::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "")));
 
@@ -208,7 +160,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::OK);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeGrpcFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribeGrpcFailure) {
     EXPECT_CALL(*mGrpcStub, Unsubscribe(_, _, _))
             .WillOnce(Return(::grpc::Status(::grpc::StatusCode::INTERNAL, "GRPC Error")));
 
@@ -217,7 +169,7 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::INTERNAL_ERROR);
 }
 
-TEST_F(GRPCVehicleHardwareMockServerUnitTest, UnsubscribeProtoFailure) {
+TEST_F(GRPCVehicleHardwareUnitTest, TestUnsubscribeProtoFailure) {
     proto::VehicleHalCallStatus protoStatus;
     protoStatus.set_status_code(proto::StatusCode::NOT_AVAILABLE_SPEED_LOW);
 
@@ -230,4 +182,264 @@
     EXPECT_EQ(status, aidlvhal::StatusCode::NOT_AVAILABLE_SPEED_LOW);
 }
 
+TEST_F(GRPCVehicleHardwareUnitTest, TestPollValue) {
+    int64_t testTimestamp = 12345;
+    int32_t testPropId = 54321;
+    int64_t startTimestamp = elapsedRealtimeNano();
+
+    // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+    // there.
+    auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+    EXPECT_CALL(*mGrpcStub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+    EXPECT_CALL(*clientReader, Read(_))
+            .WillOnce([testTimestamp, testPropId](proto::VehiclePropValues* values) {
+                values->Clear();
+                auto value = values->add_values();
+                value->set_timestamp(testTimestamp);
+                value->set_prop(testPropId);
+                return true;
+            })
+            .WillOnce(Return(false));
+    EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+    std::vector<aidlvhal::VehiclePropValue> propertyEvents;
+
+    mHardware->registerOnPropertyChangeEvent(
+            std::make_unique<GRPCVehicleHardware::PropertyChangeCallback>(
+                    [&propertyEvents](const std::vector<aidlvhal::VehiclePropValue>& events) {
+                        for (const auto& event : events) {
+                            propertyEvents.push_back(event);
+                        }
+                    }));
+
+    pollValue();
+
+    ASSERT_THAT(propertyEvents, SizeIs(1));
+    EXPECT_EQ(propertyEvents[0].prop, testPropId);
+    EXPECT_GT(propertyEvents[0].timestamp, startTimestamp)
+            << "Timestamp must be updated to Android timestamp";
+    EXPECT_LT(propertyEvents[0].timestamp, elapsedRealtimeNano())
+            << "Timestamp must be updated to Android timestamp";
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestPollValueIgnoreOutdatedValue) {
+    int64_t testTimestamp1 = 12345;
+    int32_t value1 = 1324;
+    int64_t testTimestamp2 = 12340;
+    int32_t value2 = 1423;
+    int32_t testPropId = 54321;
+    int64_t startTimestamp = elapsedRealtimeNano();
+
+    // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+    // there.
+    auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+    EXPECT_CALL(*mGrpcStub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+    EXPECT_CALL(*clientReader, Read(_))
+            .WillOnce([testTimestamp1, value1, testPropId](proto::VehiclePropValues* values) {
+                values->Clear();
+                auto value = values->add_values();
+                value->set_timestamp(testTimestamp1);
+                value->set_prop(testPropId);
+                value->add_int32_values(value1);
+                return true;
+            })
+            .WillOnce([testTimestamp2, value2, testPropId](proto::VehiclePropValues* values) {
+                values->Clear();
+                // This event is outdated, must be ignored.
+                auto value = values->add_values();
+                value->set_timestamp(testTimestamp2);
+                value->set_prop(testPropId);
+                value->add_int32_values(value2);
+                return true;
+            })
+            .WillOnce(Return(false));
+    EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+    std::vector<aidlvhal::VehiclePropValue> propertyEvents;
+
+    mHardware->registerOnPropertyChangeEvent(
+            std::make_unique<GRPCVehicleHardware::PropertyChangeCallback>(
+                    [&propertyEvents](const std::vector<aidlvhal::VehiclePropValue>& events) {
+                        for (const auto& event : events) {
+                            propertyEvents.push_back(event);
+                        }
+                    }));
+
+    pollValue();
+
+    ASSERT_THAT(propertyEvents, SizeIs(1)) << "Outdated event must be ignored";
+    EXPECT_EQ(propertyEvents[0].prop, testPropId);
+    EXPECT_GT(propertyEvents[0].timestamp, startTimestamp);
+    EXPECT_LT(propertyEvents[0].timestamp, elapsedRealtimeNano());
+    EXPECT_THAT(propertyEvents[0].value.int32Values, ElementsAre(value1));
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestValuePollingLoop) {
+    int64_t testTimestamp = 12345;
+    int32_t testPropId = 54321;
+    auto stub = std::make_unique<NiceMock<MockVehicleServerStub>>();
+
+    // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+    // there.
+    auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+    EXPECT_CALL(*stub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+    EXPECT_CALL(*clientReader, Read(_))
+            .WillRepeatedly([testTimestamp, testPropId](proto::VehiclePropValues* values) {
+                // Sleep for 10ms and always return the same property event.
+                std::this_thread::sleep_for(std::chrono::milliseconds(10));
+                values->Clear();
+                auto value = values->add_values();
+                value->set_timestamp(testTimestamp);
+                value->set_prop(testPropId);
+                return true;
+            });
+    EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+    startValuePollingLoop(std::move(stub));
+
+    std::this_thread::sleep_for(std::chrono::milliseconds(100));
+
+    // This must stop the loop and wait for the thread to finish.
+    mHardware.reset();
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestGetValues) {
+    int64_t testRequestId = 1234;
+    int32_t testPropId = 4321;
+    int32_t testValue = 123456;
+    proto::VehiclePropValueRequests gotRequests;
+    EXPECT_CALL(*mGrpcStub, GetValues(_, _, _))
+            .WillOnce([&gotRequests, testRequestId, testPropId, testValue](
+                              ::grpc::ClientContext* context,
+                              const proto::VehiclePropValueRequests& request,
+                              proto::GetValueResults* response) {
+                gotRequests = request;
+                response->Clear();
+                auto* resultPtr = response->add_results();
+                resultPtr->set_request_id(testRequestId);
+                resultPtr->set_status(proto::StatusCode::OK);
+                auto* valuePtr = resultPtr->mutable_value();
+                valuePtr->set_prop(testPropId);
+                valuePtr->add_int32_values(testValue);
+                return ::grpc::Status::OK;
+            });
+
+    std::vector<aidlvhal::GetValueRequest> requests;
+    requests.push_back(aidlvhal::GetValueRequest{.requestId = testRequestId,
+                                                 .prop = {
+                                                         .prop = testPropId,
+                                                 }});
+
+    std::vector<aidlvhal::GetValueResult> gotResults;
+
+    auto status = mHardware->getValues(
+            std::make_shared<GRPCVehicleHardware::GetValuesCallback>(
+                    [&gotResults](std::vector<aidlvhal::GetValueResult> results) {
+                        for (const auto& result : results) {
+                            gotResults.push_back(result);
+                        }
+                    }),
+            requests);
+
+    ASSERT_EQ(status, aidlvhal::StatusCode::OK);
+    ASSERT_THAT(gotRequests.requests(), SizeIs(1));
+    EXPECT_THAT(gotRequests.requests(0).request_id(), testRequestId);
+    EXPECT_THAT(gotRequests.requests(0).value().prop(), testPropId);
+
+    ASSERT_THAT(gotResults, SizeIs(1));
+    EXPECT_EQ(gotResults[0].requestId, testRequestId);
+    EXPECT_EQ(gotResults[0].status, aidlvhal::StatusCode::OK);
+    EXPECT_EQ(gotResults[0].prop->prop, testPropId);
+    EXPECT_THAT(gotResults[0].prop->value.int32Values, ElementsAre(testValue));
+}
+
+void GRPCVehicleHardwareUnitTest::generatePropertyUpdateEvent(int32_t propId, int64_t timestamp) {
+    // This will be converted to a unique_ptr in StartPropertyValuesStream. The ownership is passed
+    // there.
+    auto clientReader = new MockClientReader<proto::VehiclePropValues>();
+    EXPECT_CALL(*mGrpcStub, StartPropertyValuesStreamRaw(_, _)).WillOnce(Return(clientReader));
+    EXPECT_CALL(*clientReader, Read(_))
+            .WillOnce([timestamp, propId](proto::VehiclePropValues* values) {
+                values->Clear();
+                auto value = values->add_values();
+                value->set_timestamp(timestamp);
+                value->set_prop(propId);
+                return true;
+            })
+            .WillOnce(Return(false));
+    EXPECT_CALL(*clientReader, Finish()).WillOnce(Return(::grpc::Status::OK));
+
+    pollValue();
+}
+
+TEST_F(GRPCVehicleHardwareUnitTest, TestGetValuesOutdatedRetry) {
+    int64_t startTimestamp = elapsedRealtimeNano();
+    int64_t testRequestId = 1234;
+    int32_t testPropId = 4321;
+    int32_t testValue1 = 123456;
+    int32_t testValue2 = 654321;
+    int32_t testTimestamp1 = 1000;
+    int32_t testTimestamp2 = 2000;
+
+    // A property update event for testTimestamp2 happens before getValues returns.
+    generatePropertyUpdateEvent(testPropId, testTimestamp2);
+
+    // GetValues first returns an outdated result, then an up-to-date result.
+    EXPECT_CALL(*mGrpcStub, GetValues(_, _, _))
+            .WillOnce([testRequestId, testPropId, testValue1, testTimestamp1](
+                              ::grpc::ClientContext* context,
+                              const proto::VehiclePropValueRequests& request,
+                              proto::GetValueResults* response) {
+                response->Clear();
+                auto* resultPtr = response->add_results();
+                resultPtr->set_request_id(testRequestId);
+                resultPtr->set_status(proto::StatusCode::OK);
+                auto* valuePtr = resultPtr->mutable_value();
+                valuePtr->set_prop(testPropId);
+                valuePtr->set_timestamp(testTimestamp1);
+                valuePtr->add_int32_values(testValue1);
+                return ::grpc::Status::OK;
+            })
+            .WillOnce([testRequestId, testPropId, testValue2, testTimestamp2](
+                              ::grpc::ClientContext* context,
+                              const proto::VehiclePropValueRequests& request,
+                              proto::GetValueResults* response) {
+                response->Clear();
+                auto* resultPtr = response->add_results();
+                resultPtr->set_request_id(testRequestId);
+                resultPtr->set_status(proto::StatusCode::OK);
+                auto* valuePtr = resultPtr->mutable_value();
+                valuePtr->set_prop(testPropId);
+                valuePtr->set_timestamp(testTimestamp2);
+                valuePtr->add_int32_values(testValue2);
+                return ::grpc::Status::OK;
+            });
+
+    std::vector<aidlvhal::GetValueRequest> requests;
+    requests.push_back(aidlvhal::GetValueRequest{.requestId = testRequestId,
+                                                 .prop = {
+                                                         .prop = testPropId,
+                                                 }});
+
+    std::vector<aidlvhal::GetValueResult> gotResults;
+
+    auto status = mHardware->getValues(
+            std::make_shared<GRPCVehicleHardware::GetValuesCallback>(
+                    [&gotResults](std::vector<aidlvhal::GetValueResult> results) {
+                        for (const auto& result : results) {
+                            gotResults.push_back(result);
+                        }
+                    }),
+            requests);
+
+    ASSERT_EQ(status, aidlvhal::StatusCode::OK);
+    ASSERT_THAT(gotResults, SizeIs(1));
+    EXPECT_EQ(gotResults[0].requestId, testRequestId);
+    EXPECT_EQ(gotResults[0].status, aidlvhal::StatusCode::OK);
+    EXPECT_EQ(gotResults[0].prop->prop, testPropId);
+    EXPECT_THAT(gotResults[0].prop->value.int32Values, ElementsAre(testValue2));
+    EXPECT_GT(gotResults[0].prop->timestamp, startTimestamp);
+    EXPECT_LT(gotResults[0].prop->timestamp, elapsedRealtimeNano());
+}
+
 }  // namespace android::hardware::automotive::vehicle::virtualization
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 4ea6dfe..80b069a 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -603,6 +603,7 @@
                      << "skip testing";
     }
 
+    // Subscribe to PERF_VEHICLE_SPEED using the max sample rate.
     auto client = mVhalClient->getSubscriptionClient(mCallback);
     ASSERT_NE(client, nullptr) << "Failed to get subscription client";
     SubscribeOptionsBuilder builder(propId);
@@ -616,18 +617,17 @@
                                              ", error: %s",
                                              propId, result.error().message().c_str());
 
-    ASSERT_TRUE(mCallback->waitForExpectedEvents(propId, 1, std::chrono::seconds(2)))
-            << "Must get at least 1 events within 2 seconds after subscription for rate: "
-            << maxSampleRate;
-
     // Sleep for 1 seconds to wait for more possible events to arrive.
     std::this_thread::sleep_for(std::chrono::seconds(1));
 
     client->unsubscribe({propId});
 
     auto events = mCallback->getEvents(propId);
-    if (events.size() == 1) {
-        // We only received one event, the value is not changing so nothing to check here.
+    if (events.size() <= 1) {
+        // We received 0 or 1 event, the value is not changing so nothing to check here.
+        // If all VHAL clients are subscribing to PERF_VEHICLE_SPEED with VUR on, then we
+        // will receive 0 event. If there are other VHAL clients subscribing to PERF_VEHICLE_SPEED
+        // with VUR off, then we will receive 1 event which is the initial value.
         return;
     }
 
diff --git a/broadcastradio/aidl/vts/Android.bp b/broadcastradio/aidl/vts/Android.bp
index 87e48a9..197ebb5 100644
--- a/broadcastradio/aidl/vts/Android.bp
+++ b/broadcastradio/aidl/vts/Android.bp
@@ -44,4 +44,5 @@
         "general-tests",
         "vts",
     ],
+    disable_framework: true,
 }
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
index 9b36406..87c9e02 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
+++ b/cas/1.2/default/android.hardware.cas@1.2-service-lazy.xml
@@ -1,5 +1,5 @@
 <manifest version="1.0" type="device">
-    <hal format="hidl">
+    <hal format="hidl" max-level="7">
         <name>android.hardware.cas</name>
         <transport>hwbinder</transport>
         <version>1.2</version>
diff --git a/cas/1.2/default/android.hardware.cas@1.2-service.xml b/cas/1.2/default/android.hardware.cas@1.2-service.xml
index 9b36406..87c9e02 100644
--- a/cas/1.2/default/android.hardware.cas@1.2-service.xml
+++ b/cas/1.2/default/android.hardware.cas@1.2-service.xml
@@ -1,5 +1,5 @@
 <manifest version="1.0" type="device">
-    <hal format="hidl">
+    <hal format="hidl" max-level="7">
         <name>android.hardware.cas</name>
         <transport>hwbinder</transport>
         <version>1.2</version>
diff --git a/common/aidl/Android.bp b/common/aidl/Android.bp
index 1f5742d..904a3d9 100644
--- a/common/aidl/Android.bp
+++ b/common/aidl/Android.bp
@@ -20,16 +20,18 @@
     backend: {
         java: {
             sdk_version: "module_current",
+            apex_available: [
+                "//apex_available:anyapex",
+                "//apex_available:platform",
+            ],
         },
         cpp: {
             enabled: false,
         },
         ndk: {
             apex_available: [
+                "//apex_available:anyapex",
                 "//apex_available:platform",
-                "com.android.btservices",
-                "com.android.media.swcodec",
-                "com.android.neuralnetworks",
             ],
             min_sdk_version: "29",
         },
diff --git a/common/support/Android.bp b/common/support/Android.bp
index 56700fa..aba5d6b 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -24,9 +24,8 @@
         "libcutils",
     ],
     apex_available: [
+        "//apex_available:anyapex",
         "//apex_available:platform",
-        "com.android.neuralnetworks",
-        "com.android.media.swcodec",
     ],
     min_sdk_version: "29",
 }
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 4f5c3d9..c28da4c 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -24,15 +24,18 @@
         java: {
             enabled: true,
             platform_apis: true,
+            apex_available: [
+                "//apex_available:anyapex",
+                "//apex_available:platform",
+            ],
         },
         cpp: {
             enabled: false,
         },
         ndk: {
             apex_available: [
+                "//apex_available:anyapex",
                 "//apex_available:platform",
-                "com.android.media.swcodec",
-                "com.android.neuralnetworks",
             ],
             min_sdk_version: "29",
         },
diff --git a/keymaster/3.0/default/Android.bp b/keymaster/3.0/default/Android.bp
new file mode 100644
index 0000000..4018cc0
--- /dev/null
+++ b/keymaster/3.0/default/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2024 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 {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: [
+        "hardware_interfaces_license",
+    ],
+}
+
+cc_library_shared {
+    name: "android.hardware.keymaster@3.0-impl",
+    proprietary: true,
+    relative_install_path: "hw",
+    srcs: ["KeymasterDevice.cpp"],
+    shared_libs: [
+        "android.hardware.keymaster@3.0",
+        "libcrypto",
+        "libhardware",
+        "libhidlbase",
+        "libkeymaster_portable",
+        "libkeymaster3device",
+        "liblog",
+        "libpuresoftkeymasterdevice",
+        "libsoftkeymasterdevice",
+        "libutils",
+    ],
+}
+
+cc_binary {
+    name: "android.hardware.keymaster@3.0-service",
+    relative_install_path: "hw",
+    proprietary: true,
+    init_rc: ["android.hardware.keymaster@3.0-service.rc"],
+    srcs: ["service.cpp"],
+    shared_libs: [
+        "android.hardware.keymaster@3.0",
+        "libbase",
+        "libcutils",
+        "libdl",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/keymaster/3.0/default/Android.mk b/keymaster/3.0/default/Android.mk
deleted file mode 100644
index 053ad67..0000000
--- a/keymaster/3.0/default/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.keymaster@3.0-impl
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_SRC_FILES := \
-    KeymasterDevice.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog \
-    libsoftkeymasterdevice \
-    libcrypto \
-    libkeymaster_portable \
-    libpuresoftkeymasterdevice \
-    libkeymaster3device \
-    libhidlbase \
-    libutils \
-    libhardware \
-    android.hardware.keymaster@3.0
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_PROPRIETARY_MODULE := true
-LOCAL_MODULE := android.hardware.keymaster@3.0-service
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../../../NOTICE
-LOCAL_INIT_RC := android.hardware.keymaster@3.0-service.rc
-LOCAL_SRC_FILES := \
-    service.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog \
-    libcutils \
-    libdl \
-    libbase \
-    libutils \
-    libhardware \
-    libhidlbase \
-    android.hardware.keymaster@3.0
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/bufferpool/aidl/default/Accessor.cpp b/media/bufferpool/aidl/default/Accessor.cpp
index 423fd84..81e8eac 100644
--- a/media/bufferpool/aidl/default/Accessor.cpp
+++ b/media/bufferpool/aidl/default/Accessor.cpp
@@ -444,7 +444,7 @@
         std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> &accessors,
         std::mutex &mutex,
         std::condition_variable &cv) {
-    std::list<const std::weak_ptr<Accessor>> evictList;
+    std::list<std::weak_ptr<Accessor>> evictList;
     while (true) {
         int expired = 0;
         int evicted = 0;
diff --git a/neuralnetworks/1.2/utils/test/DeviceTest.cpp b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
index 0d8c141..0e855c4 100644
--- a/neuralnetworks/1.2/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/1.2/utils/test/DeviceTest.cpp
@@ -54,6 +54,10 @@
         .execTime = std::numeric_limits<float>::max(),
         .powerUsage = std::numeric_limits<float>::max()};
 
+// FIXME: This function causes Clang to hang indefinitely when building with
+// -O1. Turn off optimization as a temporary workaround.
+// http://b/296850773
+#pragma clang optimize off
 template <typename... Args>
 auto makeCallbackReturn(Args&&... args) {
     return [argPack = std::make_tuple(std::forward<Args>(args)...)](const auto& cb) {
@@ -61,6 +65,7 @@
         return Void();
     };
 }
+#pragma clang optimize on
 
 sp<MockDevice> createMockDevice() {
     const auto mockDevice = MockDevice::create();
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index b214401..ec2a29c 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -2494,24 +2494,27 @@
                                  {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
                                   RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
 
-    // Assert the value has changed
-    serial = GetRandomSerialNumber();
-    ndk::ScopedAStatus res = radio_network->isCellularIdentifierTransparencyEnabled(serial);
+    if (radioRsp_network->rspInfo.error == RadioError::NONE) {
+        // Assert the value has changed
+        serial = GetRandomSerialNumber();
+        ndk::ScopedAStatus res = radio_network->isCellularIdentifierTransparencyEnabled(serial);
 
-    ASSERT_OK(res);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
-    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
-                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
-    EXPECT_EQ(valueToSet, radioRsp_network->isCellularIdentifierTransparencyEnabled);
+        ASSERT_OK(res);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
+        EXPECT_EQ(valueToSet, radioRsp_network->isCellularIdentifierTransparencyEnabled);
 
-    // Reset original state
-    radio_network->setCellularIdentifierTransparencyEnabled(serial, originalTransparencySetting);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+        // Reset original state
+        radio_network->setCellularIdentifierTransparencyEnabled(serial,
+                                                                originalTransparencySetting);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    }
 }
 
 /*
@@ -2547,24 +2550,26 @@
                                  {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
                                   RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
 
-    // Assert the value has changed
-    serial = GetRandomSerialNumber();
-    ndk::ScopedAStatus res = radio_network->isSecurityAlgorithmsUpdatedEnabled(serial);
+    if (radioRsp_network->rspInfo.error == RadioError::NONE) {
+        // Assert the value has changed
+        serial = GetRandomSerialNumber();
+        ndk::ScopedAStatus res = radio_network->isSecurityAlgorithmsUpdatedEnabled(serial);
 
-    ASSERT_OK(res);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
-    ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
-                                 {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
-                                  RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
-    EXPECT_EQ(valueToSet, radioRsp_network->isSecurityAlgorithmsUpdatedEnabled);
+        ASSERT_OK(res);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+                                     {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
+                                      RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
+        EXPECT_EQ(valueToSet, radioRsp_network->isSecurityAlgorithmsUpdatedEnabled);
 
-    // Reset original state
-    radio_network->setSecurityAlgorithmsUpdatedEnabled(serial, originalSecuritySetting);
-    EXPECT_EQ(std::cv_status::no_timeout, wait());
-    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
-    EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+        // Reset original state
+        radio_network->setSecurityAlgorithmsUpdatedEnabled(serial, originalSecuritySetting);
+        EXPECT_EQ(std::cv_status::no_timeout, wait());
+        EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+        EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+    }
 }
 
 /**
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 5106561..464883e 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -39,7 +39,9 @@
 class AttestKeyTest : public KeyMintAidlTestBase {
   public:
     void SetUp() override {
-        skipAttestKeyTestIfNeeded();
+        if (shouldSkipAttestKeyTest()) {
+            GTEST_SKIP() << "Test using ATTEST_KEY is not applicable on waivered device";
+        }
         KeyMintAidlTestBase::SetUp();
     }
 };
@@ -251,7 +253,11 @@
                                             .SetDefaultValidity(),
                                     {} /* attestation signing key */, &attest_key.keyBlob,
                                     &attest_key_characteristics, &attest_key_cert_chain);
-    if (isRkpOnly() && result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) {
+    std::optional<bool> rkpOnly = isRkpOnly();
+    if (!rkpOnly.has_value()) {
+        GTEST_SKIP() << "Test not applicable because RKP-only status cannot be determined";
+    }
+    if (rkpOnly.value() && result == ErrorCode::ATTESTATION_KEYS_NOT_PROVISIONED) {
         GTEST_SKIP() << "RKP-only devices do not have a factory key";
     }
     ASSERT_EQ(ErrorCode::OK, result);
@@ -355,7 +361,8 @@
                         .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der)
                         .SetDefaultValidity();
         // In RKP-only systems, the first key cannot be attested due to lack of batch key
-        if (!isRkpOnly() || i > 0) {
+        bool confirmedNotRkpOnly = !isRkpOnly().value_or(true);
+        if (confirmedNotRkpOnly || i > 0) {
             auth_set_builder.AttestationChallenge("foo");
         }
         auto result = GenerateAttestKey(auth_set_builder, attest_key_opt, &key_blob_list[i],
@@ -363,7 +370,7 @@
         ASSERT_EQ(ErrorCode::OK, result);
         deleters.push_back(KeyBlobDeleter(keymint_, key_blob_list[i]));
 
-        if (!isRkpOnly() || i > 0) {
+        if (confirmedNotRkpOnly || i > 0) {
             AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
             AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
             ASSERT_GT(cert_chain_list[i].size(), 0);
@@ -386,7 +393,7 @@
         }
 
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_list[i]));
-        EXPECT_GT(cert_chain_list[i].size(), i + (isRkpOnly() ? 0 : 1));
+        EXPECT_GT(cert_chain_list[i].size(), i + (confirmedNotRkpOnly ? 1 : 0));
         verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
     }
 }
@@ -432,7 +439,8 @@
                         .Authorization(TAG_NO_AUTH_REQUIRED)
                         .SetDefaultValidity();
         // In RKP-only systems, the first key cannot be attested due to lack of batch key
-        if (!isRkpOnly() || i > 0) {
+        bool confirmedNotRkpOnly = !isRkpOnly().value_or(true);
+        if (confirmedNotRkpOnly || i > 0) {
             auth_set_builder.AttestationChallenge("foo");
         }
         auto result = GenerateAttestKey(auth_set_builder, attest_key_opt, &key_blob_list[i],
@@ -440,7 +448,7 @@
         ASSERT_EQ(ErrorCode::OK, result);
         deleters.push_back(KeyBlobDeleter(keymint_, key_blob_list[i]));
 
-        if (!isRkpOnly() || i > 0) {
+        if (confirmedNotRkpOnly || i > 0) {
             AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
             AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
             ASSERT_GT(cert_chain_list[i].size(), 0);
@@ -459,7 +467,7 @@
         }
 
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_list[i]));
-        EXPECT_GT(cert_chain_list[i].size(), i + (isRkpOnly() ? 0 : 1));
+        EXPECT_GT(cert_chain_list[i].size(), i + (confirmedNotRkpOnly ? 1 : 0));
         verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
     }
 }
@@ -530,7 +538,8 @@
                         .Authorization(TAG_NO_AUTH_REQUIRED)
                         .SetDefaultValidity();
         // In RKP-only systems, the first key cannot be attested due to lack of batch key
-        if (!isRkpOnly() || i > 0) {
+        bool confirmedNotRkpOnly = !isRkpOnly().value_or(true);
+        if (confirmedNotRkpOnly || i > 0) {
             auth_set_builder.AttestationChallenge("foo");
         }
         if ((i & 0x1) == 1) {
@@ -543,7 +552,7 @@
         ASSERT_EQ(ErrorCode::OK, result);
         deleters.push_back(KeyBlobDeleter(keymint_, key_blob_list[i]));
 
-        if (!isRkpOnly() || i > 0) {
+        if (confirmedNotRkpOnly || i > 0) {
             AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
             AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
             ASSERT_GT(cert_chain_list[i].size(), 0);
@@ -566,7 +575,7 @@
         }
 
         EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_list[i]));
-        EXPECT_GT(cert_chain_list[i].size(), i + (isRkpOnly() ? 0 : 1));
+        EXPECT_GT(cert_chain_list[i].size(), i + (confirmedNotRkpOnly ? 1 : 0));
         verify_subject_and_serial(cert_chain_list[i][0], serial_int, subject, false);
     }
 }
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index cef8120..2ba75a3 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -250,7 +250,13 @@
     return AidlVersion() >= 3 && property_get_int32("ro.vendor.api_level", 0) > __ANDROID_API_T__;
 }
 
-bool KeyMintAidlTestBase::isRkpOnly() {
+std::optional<bool> KeyMintAidlTestBase::isRkpOnly() {
+    // GSI replaces the values for remote_prov_prop properties (since they’re system_internal_prop
+    // properties), so on GSI the properties are not reliable indicators of whether StrongBox/TEE is
+    // RKP-only or not.
+    if (is_gsi_image()) {
+        return std::nullopt;
+    }
     if (SecLevel() == SecurityLevel::STRONGBOX) {
         return property_get_bool("remote_provisioning.strongbox.rkp_only", false);
     }
@@ -318,8 +324,11 @@
     vector<Certificate> attest_cert_chain;
     // If an attestation is requested, but the system is RKP-only, we need to supply an explicit
     // attestation key. Else the result is a key without an attestation.
-    if (isRkpOnly() && key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) {
-        skipAttestKeyTestIfNeeded();
+    // If the RKP-only value is undeterminable (i.e., when running on GSI), generate and use the
+    // attest key anyways. In the case that using an attest key is not supported
+    // (shouldSkipAttestKeyTest), assume the device has factory keys (so not RKP-only).
+    if (isRkpOnly().value_or(true) && key_desc.Contains(TAG_ATTESTATION_CHALLENGE) &&
+        !shouldSkipAttestKeyTest()) {
         AuthorizationSet attest_key_desc =
                 AuthorizationSetBuilder().EcdsaKey(EcCurve::P_256).AttestKey().SetDefaultValidity();
         attest_key.emplace();
@@ -1677,14 +1686,6 @@
             is_attest_key_feature_disabled());
 }
 
-// Skip a test that involves use of the ATTEST_KEY feature in specific configurations
-// where ATTEST_KEY is not supported (for either StrongBox or TEE).
-void KeyMintAidlTestBase::skipAttestKeyTestIfNeeded() const {
-    if (shouldSkipAttestKeyTest()) {
-        GTEST_SKIP() << "Test using ATTEST_KEY is not applicable on waivered device";
-    }
-}
-
 void verify_serial(X509* cert, const uint64_t expected_serial) {
     BIGNUM_Ptr ser(BN_new());
     EXPECT_TRUE(ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), ser.get()));
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 1bf2d9d..0368bba 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -104,7 +104,7 @@
     uint32_t boot_patch_level();
     bool isDeviceIdAttestationRequired();
     bool isSecondImeiIdAttestationRequired();
-    bool isRkpOnly();
+    std::optional<bool> isRkpOnly();
 
     bool Curve25519Supported();
 
@@ -356,7 +356,6 @@
     bool is_strongbox_enabled(void) const;
     bool is_chipset_allowed_km4_strongbox(void) const;
     bool shouldSkipAttestKeyTest(void) const;
-    void skipAttestKeyTestIfNeeded() const;
 
     void assert_mgf_digests_present_or_not_in_key_characteristics(
             const vector<KeyCharacteristics>& key_characteristics,
diff --git a/security/keymint/support/fuzzer/Android.bp b/security/keymint/support/fuzzer/Android.bp
index 1b1a580..a3ceb91 100644
--- a/security/keymint/support/fuzzer/Android.bp
+++ b/security/keymint/support/fuzzer/Android.bp
@@ -46,6 +46,35 @@
         "hardware/interfaces/security/keymint/support/include",
         "frameworks/native/libs/binder/ndk/include_platform",
     ],
+    fuzz_config: {
+        cc: [
+            "android-hardware-security@google.com",
+        ],
+        componentid: 1084733,
+        hotlists: [
+            "4593311",
+            "4271696",
+        ],
+        description: "The fuzzer targets the APIs of libkeymint_support",
+        vector: "local_no_privileges_required",
+        service_privilege: "privileged",
+        users: "multi_user",
+        fuzzed_code_usage: "shipped",
+    },
+}
+
+cc_defaults {
+    name: "keymint_remote_fuzzer_defaults",
+    static_libs: [
+        "libkeymint_remote_prov_support",
+        "android.hardware.security.rkp-V3-ndk",
+    ],
+    shared_libs: [
+        "libcppbor",
+        "libcppcose_rkp",
+        "libjsoncpp",
+        "libkeymaster_portable",
+    ],
 }
 
 cc_fuzz {
@@ -67,3 +96,25 @@
         "keymint_fuzzer_defaults",
     ],
 }
+
+cc_fuzz {
+    name: "keymint_remote_prov_fuzzer",
+    srcs: [
+        "keymint_remote_prov_fuzzer.cpp",
+    ],
+    defaults: [
+        "keymint_fuzzer_defaults",
+        "keymint_remote_fuzzer_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "keymint_rkpsupport_fuzzer",
+    srcs: [
+        "keymint_rkpsupport_fuzzer.cpp",
+    ],
+    defaults: [
+        "keymint_fuzzer_defaults",
+        "keymint_remote_fuzzer_defaults",
+    ],
+}
diff --git a/security/keymint/support/fuzzer/README.md b/security/keymint/support/fuzzer/README.md
index d41af08..4cf6927 100644
--- a/security/keymint/support/fuzzer/README.md
+++ b/security/keymint/support/fuzzer/README.md
@@ -12,6 +12,8 @@
 ## Table of contents
 + [keymint_attestation_fuzzer](#KeyMintAttestation)
 + [keymint_authSet_fuzzer](#KeyMintAuthSet)
++ [keymint_remote_prov_fuzzer](#KeyMintRemoteProv)
++ [keymint_rkpsupport_fuzzer](#KeyMintRemoteKeyProvSupport)
 
 # <a name="KeyMintAttestation"></a> Fuzzer for KeyMintAttestation
 KeyMintAttestation supports the following parameters:
@@ -77,3 +79,53 @@
 $ adb sync data
 $ adb shell /data/fuzz/arm64/keymint_authSet_fuzzer/keymint_authSet_fuzzer
 ```
+
+# <a name="KeyMintRemoteProv"></a> Fuzzer for KeyMintRemoteProv
+KeyMintRemoteProv supports the following parameters:
+1. ChallengeSize(parameter name: "challengeSize")
+2. Challenge(parameter name: "challenge")
+3. NumKeys(parameter name: "numKeys")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`challengeSize`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`challenge`| `std::vector<uint8_t>` |Value obtained from FuzzedDataProvider|
+|`numKeys`| `uint8_t` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_remote_prov_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_remote_prov_fuzzer/keymint_remote_prov_fuzzer
+```
+
+# <a name="KeyMintRemoteKeyProvSupport"></a> Fuzzer for KeyMintRemoteKeyProvSupport
+KeyMintRemoteKeyProvSupport supports the following parameters:
+1. SupportedEekCurve(parameter name: "supportedEekCurve")
+2. Length(parameter name: "length")
+3. SerialNumberProp(parameter name: "serialNoProp")
+4. InstanceName(parameter name: "instanceName")
+5. Value(parameter name: "value")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |--------------| -------------------- |
+|`supportedEekCurve`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`length`| `uint8_t` |Value obtained from FuzzedDataProvider|
+|`serialNoProp`| `string` |Value obtained from FuzzedDataProvider|
+|`instanceName`| `string` |Value obtained from FuzzedDataProvider|
+|`value`| `uint8_t` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) keymint_rkpsupport_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/keymint_rkpsupport_fuzzer/keymint_rkpsupport_fuzzer
+```
diff --git a/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp
new file mode 100644
index 0000000..6bd986c
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_remote_prov_fuzzer.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2024 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/binder_manager.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <remote_prov/remote_prov_utils.h>
+#include <utils/Log.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+using namespace cppcose;
+using namespace aidl::android::hardware::security::keymint;
+using namespace aidl::android::hardware::security::keymint::remote_prov;
+
+constexpr size_t kMinSize = 0;
+constexpr size_t kSupportedNumKeys = 4;
+constexpr size_t kChallengeSize = 64;
+constexpr size_t kMaxBytes = 128;
+const std::string kServiceName =
+        "android.hardware.security.keymint.IRemotelyProvisionedComponent/default";
+
+std::shared_ptr<IRemotelyProvisionedComponent> gRPC = nullptr;
+
+class KeyMintRemoteProv {
+  public:
+    KeyMintRemoteProv(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+  private:
+    std::vector<uint8_t> ExtractPayloadValue(const MacedPublicKey& macedPubKey);
+    FuzzedDataProvider mFdp;
+};
+
+std::vector<uint8_t> KeyMintRemoteProv::ExtractPayloadValue(const MacedPublicKey& macedPubKey) {
+    std::vector<uint8_t> payloadValue;
+
+    auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+    if (coseMac0) {
+        // The payload is a bstr holding an encoded COSE_Key
+        auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+        if (payload != nullptr) {
+            payloadValue = payload->value();
+        }
+    }
+    return payloadValue;
+}
+
+void KeyMintRemoteProv::process() {
+    std::vector<MacedPublicKey> keysToSign = std::vector<MacedPublicKey>(
+            mFdp.ConsumeIntegralInRange<uint8_t>(kMinSize, kSupportedNumKeys));
+    cppbor::Array cborKeysToSign;
+    for (auto& key : keysToSign) {
+        // TODO: b/350649166 - Randomize keysToSign
+        std::vector<uint8_t> privateKeyBlob;
+        gRPC->generateEcdsaP256KeyPair(false /* testMode */, &key, &privateKeyBlob);
+
+        std::vector<uint8_t> payloadValue = ExtractPayloadValue(key);
+        cborKeysToSign.add(cppbor::EncodedItem(payloadValue));
+    }
+
+    uint8_t challengeSize = mFdp.ConsumeIntegralInRange<uint8_t>(kMinSize, kChallengeSize);
+    std::vector<uint8_t> challenge = mFdp.ConsumeBytes<uint8_t>(challengeSize);
+
+    std::vector<uint8_t> csr;
+    gRPC->generateCertificateRequestV2(keysToSign, challenge, &csr);
+
+    while (mFdp.remaining_bytes()) {
+        auto invokeProvAPI = mFdp.PickValueInArray<const std::function<void()>>({
+                [&]() { verifyFactoryCsr(cborKeysToSign, csr, gRPC.get(), challenge); },
+                [&]() { verifyProductionCsr(cborKeysToSign, csr, gRPC.get(), challenge); },
+                [&]() { isCsrWithProperDiceChain(csr); },
+        });
+        invokeProvAPI();
+    }
+}
+
+extern "C" int LLVMFuzzerInitialize(int /* *argc */, char /* ***argv */) {
+    ::ndk::SpAIBinder binder(AServiceManager_waitForService(kServiceName.c_str()));
+    gRPC = IRemotelyProvisionedComponent::fromBinder(binder);
+    LOG_ALWAYS_FATAL_IF(!gRPC, "Failed to get IRemotelyProvisionedComponent instance.");
+    return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    KeyMintRemoteProv kmRemoteProv(data, size);
+    kmRemoteProv.process();
+    return 0;
+}
+
+}  // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/security/keymint/support/fuzzer/keymint_rkpsupport_fuzzer.cpp b/security/keymint/support/fuzzer/keymint_rkpsupport_fuzzer.cpp
new file mode 100644
index 0000000..778d48f
--- /dev/null
+++ b/security/keymint/support/fuzzer/keymint_rkpsupport_fuzzer.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 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 <fuzzer/FuzzedDataProvider.h>
+#include <remote_prov/remote_prov_utils.h>
+
+namespace android::hardware::security::keymint_support::fuzzer {
+
+using namespace aidl::android::hardware::security::keymint::remote_prov;
+
+constexpr size_t kMaxBytes = 128;
+
+class KeyMintRemoteKeyProvSupport {
+  public:
+    KeyMintRemoteKeyProvSupport(const uint8_t* data, size_t size) : mFdp(data, size) {}
+    void process();
+
+  private:
+    FuzzedDataProvider mFdp;
+};
+
+void KeyMintRemoteKeyProvSupport::process() {
+    while (mFdp.remaining_bytes()) {
+        auto invokeProvAPI = mFdp.PickValueInArray<const std::function<void()>>({
+                [&]() {
+                    std::vector<uint8_t> eekId;
+                    if (mFdp.ConsumeBool()) {
+                        eekId = mFdp.ConsumeBytes<uint8_t>(kMaxBytes);
+                    }
+                    generateEekChain(mFdp.ConsumeIntegral<uint8_t>() /* supportedEekCurve */,
+                                     mFdp.ConsumeIntegral<uint8_t>() /* length */, eekId);
+                },
+                [&]() { getProdEekChain(mFdp.ConsumeIntegral<uint8_t>() /* supportedEekCurve */); },
+                [&]() {
+                    std::string serialNoProp = mFdp.ConsumeRandomLengthString(kMaxBytes);
+                    std::string instanceName = mFdp.ConsumeRandomLengthString(kMaxBytes);
+                    cppbor::Array array;
+                    array.add(mFdp.ConsumeIntegral<uint8_t>() /* value */);
+                    jsonEncodeCsrWithBuild(instanceName, array, serialNoProp);
+                },
+        });
+        invokeProvAPI();
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    KeyMintRemoteKeyProvSupport keymintRKPSupport(data, size);
+    keymintRKPSupport.process();
+    return 0;
+}
+
+}  // namespace android::hardware::security::keymint_support::fuzzer
diff --git a/tests/extension/vibrator/aidl/default/CustomVibrator.cpp b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
index 7a7c58b..9c306b5 100644
--- a/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
+++ b/tests/extension/vibrator/aidl/default/CustomVibrator.cpp
@@ -60,7 +60,7 @@
 ndk::SpAIBinder CustomVibrator::createBinder() {
     auto binder = BnCustomVibrator::createBinder();
     // e.g. AIBinder_setInheritRt(binder.get(), true);
-    // e.g. AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, 20);
+    // e.g. AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, -2);
     // e.g. AIBinder_setRequestingSid(binder.get(), true);
     return binder;
 }
diff --git a/tests/msgq/1.0/ITestMsgQ.hal b/tests/msgq/1.0/ITestMsgQ.hal
index 0cf9c7c..62bef0a 100644
--- a/tests/msgq/1.0/ITestMsgQ.hal
+++ b/tests/msgq/1.0/ITestMsgQ.hal
@@ -18,8 +18,8 @@
 
 interface ITestMsgQ {
     enum EventFlagBits : uint32_t {
-        FMQ_NOT_EMPTY = 1 << 0,
-        FMQ_NOT_FULL  = 1 << 1,
+        FMQ_NOT_FULL = 1 << 0,
+        FMQ_NOT_EMPTY  = 1 << 1,
     };
 
     /**
diff --git a/tests/msgq/TEST_MAPPING b/tests/msgq/TEST_MAPPING
new file mode 100644
index 0000000..51c6c97
--- /dev/null
+++ b/tests/msgq/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "fmq_unit_tests"
+    },
+    {
+      "name": "fmq_test"
+    }
+  ],
+  "hwasan-presubmit": [
+    {
+      "name": "fmq_unit_tests"
+    },
+    {
+      "name": "fmq_test"
+    }
+  ]
+}