Merge "Delete HIDL 3.8" into tm-dev
diff --git a/audio/policy/1.0/xml/api/current.txt b/audio/policy/1.0/xml/api/current.txt
index 1478381..0b77d45 100644
--- a/audio/policy/1.0/xml/api/current.txt
+++ b/audio/policy/1.0/xml/api/current.txt
@@ -232,12 +232,12 @@
 
   public class ValueType {
     ctor public ValueType();
-    method public int getAndroid_type();
+    method public String getAndroid_type();
     method public String getLiteral();
-    method public int getNumerical();
-    method public void setAndroid_type(int);
+    method public long getNumerical();
+    method public void setAndroid_type(String);
     method public void setLiteral(String);
-    method public void setNumerical(int);
+    method public void setNumerical(long);
   }
 
   public class ValuesType {
diff --git a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
index 852ea77..3ce12e7 100644
--- a/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
+++ b/audio/policy/1.0/xml/audio_policy_engine_configuration.xsd
@@ -189,10 +189,20 @@
     </xs:complexType>
     <xs:complexType name="valueType">
         <xs:attribute name="literal" type="xs:string" use="required"/>
-        <xs:attribute name="numerical" type="xs:int" use="required"/>
-        <xs:attribute name="android_type" type="xs:int" use="optional"/>
+        <xs:attribute name="numerical" type="xs:long" use="required"/>
+        <xs:attribute name="android_type" type="longDecimalOrHexType" use="optional"/>
     </xs:complexType>
 
+    <xs:simpleType name="longDecimalOrHexType">
+      <xs:union memberTypes="xs:long longHexType" />
+    </xs:simpleType>
+
+    <xs:simpleType name="longHexType">
+      <xs:restriction base="xs:string">
+        <xs:pattern value="0x[0-9A-Fa-f]{1,16}"/>
+      </xs:restriction>
+    </xs:simpleType>
+
     <xs:complexType name="attributesRefType">
         <xs:sequence>
             <xs:element name="Attributes" type="AttributesType" minOccurs="1" maxOccurs="1"/>
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash
index 7bb15e8..f478504 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/.hash
@@ -1 +1 @@
-38469e5a0359c95015bea304c463b686cf4ee9ca
+8610b651e162c614a97542d6f4ed039c969823e5
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
index 7e48eba..d7b874a 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/1/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
@@ -36,5 +36,5 @@
 enum VehicleApPowerStateConfigFlag {
   ENABLE_DEEP_SLEEP_FLAG = 1,
   CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 2,
-  ENABLE_HIBERNATION_FLAG = 3,
+  ENABLE_HIBERNATION_FLAG = 4,
 }
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
index 7e48eba..d7b874a 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
@@ -36,5 +36,5 @@
 enum VehicleApPowerStateConfigFlag {
   ENABLE_DEEP_SLEEP_FLAG = 1,
   CONFIG_SUPPORT_TIMER_POWER_ON_FLAG = 2,
-  ENABLE_HIBERNATION_FLAG = 3,
+  ENABLE_HIBERNATION_FLAG = 4,
 }
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
index 4d8e2f5..8b0190ce 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleApPowerStateConfigFlag.aidl
@@ -37,5 +37,5 @@
      * (via VehicleApPowerStateShutdownParam#CAN_HIBERNATE or
      *  VehicleApPowerStateShutdownParam#HIBERNATE_IMMEDIATELY flags)
      */
-    ENABLE_HIBERNATION_FLAG = 0x3,
+    ENABLE_HIBERNATION_FLAG = 0x4,
 }
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 462698c..fe03732 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -39,7 +39,7 @@
 using ::aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
 using ::aidl::android::hardware::camera::metadata::SensorPixelMode;
 using ::aidl::android::hardware::camera::provider::CameraIdAndStreamCombination;
-using ::aidl::android::hardware::camera::provider::ICameraProviderCallbackDefault;
+using ::aidl::android::hardware::camera::provider::BnCameraProviderCallback;
 
 using ::ndk::ScopedAStatus;
 
@@ -86,7 +86,7 @@
 
 // Test if ICameraProvider::setCallback returns Status::OK
 TEST_P(CameraAidlTest, setCallback) {
-    struct ProviderCb : public ICameraProviderCallbackDefault {
+    struct ProviderCb : public BnCameraProviderCallback {
         ScopedAStatus cameraDeviceStatusChange(const std::string& cameraDeviceName,
                                                CameraDeviceStatus newStatus) override {
             ALOGI("camera device status callback name %s, status %d", cameraDeviceName.c_str(),
@@ -109,11 +109,11 @@
         }
     };
 
-    std::shared_ptr<ProviderCb> cb = ProviderCb::make<ProviderCb>();
+    std::shared_ptr<ProviderCb> cb = ndk::SharedRefBase::make<ProviderCb>();
     ScopedAStatus ret = mProvider->setCallback(cb);
     ASSERT_TRUE(ret.isOk());
     ret = mProvider->setCallback(nullptr);
-    ASSERT_TRUE(ret.isOk());
+    ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT), ret.getServiceSpecificError());
 }
 
 // Test if ICameraProvider::getCameraDeviceInterface returns Status::OK and non-null device
@@ -399,9 +399,6 @@
             }
         }
     }
-
-    ret = mProvider->setCallback(nullptr);
-    ASSERT_TRUE(ret.isOk());
 }
 
 // Check dump functionality.
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index fd83e37..c11fc0c 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -55,26 +55,6 @@
 using ::ndk::SpAIBinder;
 
 namespace {
-bool matchDeviceName(const std::string& deviceName, const std::string& providerType,
-                     std::string* deviceVersion, std::string* cameraId) {
-    // expected format: device@<major>.<minor>/<type>/<id>
-    std::stringstream pattern;
-    pattern << "device@[0-9]+\\.[0-9]+/" << providerType << "/(.+)";
-    std::regex e(pattern.str());
-
-    std::smatch sm;
-    if (std::regex_match(deviceName, sm, e)) {
-        if (deviceVersion != nullptr) {
-            *deviceVersion = sm[1];
-        }
-        if (cameraId != nullptr) {
-            *cameraId = sm[2];
-        }
-        return true;
-    }
-    return false;
-}
-
 bool parseProviderName(const std::string& serviceDescriptor, std::string* type /*out*/,
                        uint32_t* id /*out*/) {
     if (!type || !id) {
@@ -498,13 +478,11 @@
 
 bool CameraAidlTest::matchDeviceName(const std::string& deviceName, const std::string& providerType,
                                      std::string* deviceVersion, std::string* cameraId) {
-    // "device@<version>/legacy/<id>"
-    std::string pattern;
-    pattern.append("device@([0-9]+\\.[0-9]+)/");
-    pattern.append(providerType);
-    pattern.append("/(.+)");
+    // expected format: device@<major>.<minor>/<type>/<id>
+    std::stringstream pattern;
+    pattern << "device@([0-9]+\\.[0-9]+)/" << providerType << "/(.+)";
+    std::regex e(pattern.str());
 
-    std::regex e(pattern);
     std::smatch sm;
     if (std::regex_match(deviceName, sm, e)) {
         if (deviceVersion != nullptr) {
@@ -1160,7 +1138,7 @@
     }
 
     std::string version, cameraId;
-    ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId));
+    ASSERT_TRUE(matchDeviceName(cameraName, mProviderType, &version, &cameraId));
     std::unordered_set<std::string> physicalIds;
     rc = getPhysicalCameraIds(metadata, &physicalIds);
     ASSERT_TRUE(isUltraHighResCamera || Status::OK == rc);
@@ -1192,7 +1170,7 @@
         SystemCameraKind physSystemCameraKind = SystemCameraKind::PUBLIC;
         for (auto& deviceName : deviceNames) {
             std::string publicVersion, publicId;
-            ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
+            ASSERT_TRUE(matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
             if (physicalId == publicId) {
                 isPublicId = true;
                 fullPublicId = deviceName;
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index 7855b51..cf2c90d 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -19,6 +19,7 @@
 #include "Gnss.h"
 #include <inttypes.h>
 #include <log/log.h>
+#include <utils/Timers.h>
 #include "AGnss.h"
 #include "AGnssRil.h"
 #include "DeviceFileReader.h"
@@ -28,7 +29,6 @@
 #include "GnssConfiguration.h"
 #include "GnssDebug.h"
 #include "GnssGeofence.h"
-#include "GnssMeasurementInterface.h"
 #include "GnssNavigationMessageInterface.h"
 #include "GnssPsds.h"
 #include "GnssVisibilityControl.h"
@@ -95,6 +95,9 @@
     }
 
     mIsActive = true;
+    mThreadBlocker.reset();
+    // notify measurement engine to update measurement interval
+    mGnssMeasurementInterface->setLocationEnabled(true);
     this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
     mThread = std::thread([this]() {
         this->reportSvStatus();
@@ -102,8 +105,12 @@
             std::this_thread::sleep_for(std::chrono::milliseconds(TTFF_MILLIS));
             mFirstFixReceived = true;
         }
-        while (mIsActive == true) {
+        do {
+            if (!mIsActive) {
+                break;
+            }
             this->reportSvStatus();
+            this->reportNmea();
 
             auto currentLocation = getLocationFromHW();
             mGnssPowerIndication->notePowerConsumption();
@@ -113,12 +120,29 @@
                 const auto location = Utils::getMockLocation();
                 this->reportLocation(location);
             }
-            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMs));
-        }
+        } while (mIsActive && mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMs)));
     });
     return ScopedAStatus::ok();
 }
 
+ScopedAStatus Gnss::stop() {
+    ALOGD("stop");
+    mIsActive = false;
+    mGnssMeasurementInterface->setLocationEnabled(false);
+    this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_END);
+    mThreadBlocker.notify();
+    if (mThread.joinable()) {
+        mThread.join();
+    }
+    return ScopedAStatus::ok();
+}
+
+ScopedAStatus Gnss::close() {
+    ALOGD("close");
+    sGnssCallback = nullptr;
+    return ScopedAStatus::ok();
+}
+
 void Gnss::reportLocation(const GnssLocation& location) const {
     std::unique_lock<std::mutex> lock(mMutex);
     if (sGnssCallback == nullptr) {
@@ -153,7 +177,6 @@
 
 std::vector<GnssSvInfo> Gnss::filterBlocklistedSatellites(
         std::vector<GnssSvInfo> gnssSvInfoList) const {
-    ALOGD("filterBlocklistedSatellites");
     for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
         if (mGnssConfiguration->isBlocklisted(gnssSvInfoList[i])) {
             gnssSvInfoList[i].svFlag &= ~(uint32_t)IGnssCallback::GnssSvFlags::USED_IN_FIX;
@@ -174,14 +197,19 @@
     }
 }
 
-ScopedAStatus Gnss::stop() {
-    ALOGD("stop");
-    mIsActive = false;
-    this->reportGnssStatusValue(IGnssCallback::GnssStatusValue::SESSION_END);
-    if (mThread.joinable()) {
-        mThread.join();
+void Gnss::reportNmea() const {
+    if (mIsNmeaActive) {
+        std::unique_lock<std::mutex> lock(mMutex);
+        if (sGnssCallback == nullptr) {
+            ALOGE("%s: sGnssCallback is null.", __func__);
+            return;
+        }
+        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+        auto status = sGnssCallback->gnssNmeaCb(now, "$TEST,0,1,2,3,4,5");
+        if (!status.isOk()) {
+            ALOGE("%s: Unable to invoke callback", __func__);
+        }
     }
-    return ScopedAStatus::ok();
 }
 
 ScopedAStatus Gnss::startSvStatus() {
@@ -197,16 +225,12 @@
 }
 ScopedAStatus Gnss::startNmea() {
     ALOGD("startNmea");
+    mIsNmeaActive = true;
     return ScopedAStatus::ok();
 }
 ScopedAStatus Gnss::stopNmea() {
     ALOGD("stopNmea");
-    return ScopedAStatus::ok();
-}
-
-ScopedAStatus Gnss::close() {
-    ALOGD("close");
-    sGnssCallback = nullptr;
+    mIsNmeaActive = false;
     return ScopedAStatus::ok();
 }
 
@@ -249,7 +273,8 @@
 ScopedAStatus Gnss::setPositionMode(const PositionModeOptions& options) {
     ALOGD("setPositionMode. minIntervalMs:%d, lowPowerMode:%d", options.minIntervalMs,
           (int)options.lowPowerMode);
-    mMinIntervalMs = options.minIntervalMs;
+    mMinIntervalMs = std::max(1000, options.minIntervalMs);
+    mGnssMeasurementInterface->setLocationInterval(mMinIntervalMs);
     return ScopedAStatus::ok();
 }
 
@@ -283,8 +308,10 @@
 ScopedAStatus Gnss::getExtensionGnssMeasurement(
         std::shared_ptr<IGnssMeasurementInterface>* iGnssMeasurement) {
     ALOGD("getExtensionGnssMeasurement");
-
-    *iGnssMeasurement = SharedRefBase::make<GnssMeasurementInterface>();
+    if (mGnssMeasurementInterface == nullptr) {
+        mGnssMeasurementInterface = SharedRefBase::make<GnssMeasurementInterface>();
+    }
+    *iGnssMeasurement = mGnssMeasurementInterface;
     return ScopedAStatus::ok();
 }
 
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index 1489b4b..df10fc8 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -32,7 +32,9 @@
 #include <mutex>
 #include <thread>
 #include "GnssConfiguration.h"
+#include "GnssMeasurementInterface.h"
 #include "GnssPowerIndication.h"
+#include "Utils.h"
 
 namespace aidl::android::hardware::gnss {
 
@@ -84,6 +86,7 @@
 
     std::shared_ptr<GnssConfiguration> mGnssConfiguration;
     std::shared_ptr<GnssPowerIndication> mGnssPowerIndication;
+    std::shared_ptr<GnssMeasurementInterface> mGnssMeasurementInterface;
 
   private:
     void reportLocation(const GnssLocation&) const;
@@ -93,14 +96,17 @@
             std::vector<IGnssCallback::GnssSvInfo> gnssSvInfoList) const;
     void reportGnssStatusValue(const IGnssCallback::GnssStatusValue gnssStatusValue) const;
     std::unique_ptr<GnssLocation> getLocationFromHW();
+    void reportNmea() const;
 
     static std::shared_ptr<IGnssCallback> sGnssCallback;
 
     std::atomic<long> mMinIntervalMs;
     std::atomic<bool> mIsActive;
     std::atomic<bool> mIsSvStatusActive;
+    std::atomic<bool> mIsNmeaActive;
     std::atomic<bool> mFirstFixReceived;
     std::thread mThread;
+    ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
     mutable std::mutex mMutex;
 };
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index 2c7241b..606de07 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -33,10 +33,11 @@
 
 std::shared_ptr<IGnssMeasurementCallback> GnssMeasurementInterface::sCallback = nullptr;
 
-GnssMeasurementInterface::GnssMeasurementInterface() : mMinIntervalMillis(1000) {}
+GnssMeasurementInterface::GnssMeasurementInterface()
+    : mIntervalMs(1000), mLocationIntervalMs(1000), mFutures(std::vector<std::future<void>>()) {}
 
 GnssMeasurementInterface::~GnssMeasurementInterface() {
-    stop();
+    waitForStoppingThreads();
 }
 
 ndk::ScopedAStatus GnssMeasurementInterface::setCallback(
@@ -44,8 +45,10 @@
         const bool enableCorrVecOutputs) {
     ALOGD("setCallback: enableFullTracking: %d enableCorrVecOutputs: %d", (int)enableFullTracking,
           (int)enableCorrVecOutputs);
-    std::unique_lock<std::mutex> lock(mMutex);
-    sCallback = callback;
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        sCallback = callback;
+    }
 
     if (mIsActive) {
         ALOGW("GnssMeasurement callback already set. Resetting the callback...");
@@ -60,14 +63,16 @@
         const std::shared_ptr<IGnssMeasurementCallback>& callback, const Options& options) {
     ALOGD("setCallbackWithOptions: fullTracking:%d, corrVec:%d, intervalMs:%d",
           (int)options.enableFullTracking, (int)options.enableCorrVecOutputs, options.intervalMs);
-    std::unique_lock<std::mutex> lock(mMutex);
-    sCallback = callback;
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        sCallback = callback;
+    }
 
     if (mIsActive) {
         ALOGW("GnssMeasurement callback already set. Resetting the callback...");
         stop();
     }
-    mMinIntervalMillis = options.intervalMs;
+    mIntervalMs = std::max(options.intervalMs, 1000);
     start(options.enableCorrVecOutputs);
 
     return ndk::ScopedAStatus::ok();
@@ -75,18 +80,35 @@
 
 ndk::ScopedAStatus GnssMeasurementInterface::close() {
     ALOGD("close");
-    stop();
-    std::unique_lock<std::mutex> lock(mMutex);
-    sCallback = nullptr;
-    mMinIntervalMillis = 1000;
+    if (mIsActive) {
+        stop();
+    }
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        sCallback = nullptr;
+    }
+    mIntervalMs = 1000;
     return ndk::ScopedAStatus::ok();
 }
 
 void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) {
     ALOGD("start");
+
+    if (mIsActive) {
+        ALOGD("restarting since measurement has started");
+        stop();
+    }
+    // Wait for stopping previous thread.
+    waitForStoppingThreads();
+
     mIsActive = true;
+    mThreadBlocker.reset();
     mThread = std::thread([this, enableCorrVecOutputs]() {
-        while (mIsActive == true) {
+        int intervalMs;
+        do {
+            if (!mIsActive) {
+                break;
+            }
             std::string rawMeasurementStr = "";
             if (ReplayUtils::hasGnssDeviceFile() &&
                 ReplayUtils::isGnssRawMeasurement(
@@ -103,15 +125,19 @@
                 auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs);
                 this->reportMeasurement(measurement);
             }
-            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
-        }
+            intervalMs =
+                    (mLocationEnabled) ? std::min(mLocationIntervalMs, mIntervalMs) : mIntervalMs;
+        } while (mIsActive && mThreadBlocker.wait_for(std::chrono::milliseconds(intervalMs)));
     });
-    mThread.detach();
 }
 
 void GnssMeasurementInterface::stop() {
     ALOGD("stop");
     mIsActive = false;
+    mThreadBlocker.notify();
+    if (mThread.joinable()) {
+        mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
+    }
 }
 
 void GnssMeasurementInterface::reportMeasurement(const GnssData& data) {
@@ -128,4 +154,21 @@
     callbackCopy->gnssMeasurementCb(data);
 }
 
+void GnssMeasurementInterface::setLocationInterval(const int intervalMs) {
+    mLocationIntervalMs = intervalMs;
+}
+
+void GnssMeasurementInterface::setLocationEnabled(const bool enabled) {
+    mLocationEnabled = enabled;
+}
+
+void GnssMeasurementInterface::waitForStoppingThreads() {
+    for (auto& future : mFutures) {
+        ALOGD("Stopping previous thread.");
+        future.wait();
+        ALOGD("Done stopping thread.");
+    }
+    mFutures.clear();
+}
+
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
index bf77806..bb08027 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.h
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -19,8 +19,10 @@
 #include <aidl/android/hardware/gnss/BnGnssMeasurementCallback.h>
 #include <aidl/android/hardware/gnss/BnGnssMeasurementInterface.h>
 #include <atomic>
+#include <future>
 #include <mutex>
 #include <thread>
+#include "Utils.h"
 
 namespace aidl::android::hardware::gnss {
 
@@ -35,15 +37,22 @@
     ndk::ScopedAStatus setCallbackWithOptions(
             const std::shared_ptr<IGnssMeasurementCallback>& callback,
             const Options& options) override;
+    void setLocationInterval(const int intervalMs);
+    void setLocationEnabled(const bool enabled);
 
   private:
     void start(const bool enableCorrVecOutputs);
     void stop();
     void reportMeasurement(const GnssData&);
+    void waitForStoppingThreads();
 
-    std::atomic<long> mMinIntervalMillis;
+    std::atomic<long> mIntervalMs;
+    std::atomic<long> mLocationIntervalMs;
     std::atomic<bool> mIsActive;
+    std::atomic<bool> mLocationEnabled;
     std::thread mThread;
+    std::vector<std::future<void>> mFutures;
+    ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
     // Guarded by mMutex
     static std::shared_ptr<IGnssMeasurementCallback> sCallback;
diff --git a/gnss/aidl/default/GnssNavigationMessageInterface.cpp b/gnss/aidl/default/GnssNavigationMessageInterface.cpp
index 4bc859d..75b9624 100644
--- a/gnss/aidl/default/GnssNavigationMessageInterface.cpp
+++ b/gnss/aidl/default/GnssNavigationMessageInterface.cpp
@@ -32,7 +32,7 @@
 GnssNavigationMessageInterface::GnssNavigationMessageInterface() : mMinIntervalMillis(1000) {}
 
 GnssNavigationMessageInterface::~GnssNavigationMessageInterface() {
-    stop();
+    waitForStoppingThreads();
 }
 
 ndk::ScopedAStatus GnssNavigationMessageInterface::setCallback(
@@ -46,7 +46,9 @@
 
 ndk::ScopedAStatus GnssNavigationMessageInterface::close() {
     ALOGD("close");
-    stop();
+    if (mIsActive) {
+        stop();
+    }
     std::unique_lock<std::mutex> lock(mMutex);
     sCallback = nullptr;
     return ndk::ScopedAStatus::ok();
@@ -54,9 +56,20 @@
 
 void GnssNavigationMessageInterface::start() {
     ALOGD("start");
+
+    if (mIsActive) {
+        ALOGD("restarting since nav msg has started");
+        stop();
+    }
+    // Wait for stopping previous thread.
+    waitForStoppingThreads();
+
     mIsActive = true;
     mThread = std::thread([this]() {
-        while (mIsActive == true) {
+        do {
+            if (!mIsActive) {
+                break;
+            }
             GnssNavigationMessage message = {
                     .svid = 19,
                     .type = GnssNavigationMessageType::GPS_L1CA,
@@ -66,15 +79,18 @@
                     .data = std::vector<uint8_t>(40, 0xF9),
             };
             this->reportMessage(message);
-            std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis));
-        }
+        } while (mIsActive &&
+                 mThreadBlocker.wait_for(std::chrono::milliseconds(mMinIntervalMillis)));
     });
-    mThread.detach();
 }
 
 void GnssNavigationMessageInterface::stop() {
     ALOGD("stop");
     mIsActive = false;
+    mThreadBlocker.notify();
+    if (mThread.joinable()) {
+        mFutures.push_back(std::async(std::launch::async, [this] { mThread.join(); }));
+    }
 }
 
 void GnssNavigationMessageInterface::reportMessage(const GnssNavigationMessage& message) {
@@ -91,4 +107,13 @@
     callbackCopy->gnssNavigationMessageCb(message);
 }
 
+void GnssNavigationMessageInterface::waitForStoppingThreads() {
+    for (auto& future : mFutures) {
+        ALOGD("Stopping previous thread.");
+        future.wait();
+        ALOGD("Done stopping thread.");
+    }
+    mFutures.clear();
+}
+
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssNavigationMessageInterface.h b/gnss/aidl/default/GnssNavigationMessageInterface.h
index 600b23a..b335348 100644
--- a/gnss/aidl/default/GnssNavigationMessageInterface.h
+++ b/gnss/aidl/default/GnssNavigationMessageInterface.h
@@ -18,7 +18,9 @@
 
 #include <aidl/android/hardware/gnss/BnGnssNavigationMessageInterface.h>
 #include <atomic>
+#include <future>
 #include <thread>
+#include "Utils.h"
 
 namespace aidl::android::hardware::gnss {
 
@@ -34,10 +36,13 @@
     void start();
     void stop();
     void reportMessage(const IGnssNavigationMessageCallback::GnssNavigationMessage& message);
+    void waitForStoppingThreads();
 
     std::atomic<long> mMinIntervalMillis;
     std::atomic<bool> mIsActive;
     std::thread mThread;
+    std::vector<std::future<void>> mFutures;
+    ::android::hardware::gnss::common::ThreadBlocker mThreadBlocker;
 
     // Guarded by mMutex
     static std::shared_ptr<IGnssNavigationMessageCallback> sCallback;
diff --git a/gnss/aidl/vts/GnssCallbackAidl.cpp b/gnss/aidl/vts/GnssCallbackAidl.cpp
index 77a2506..2f6128b 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssCallbackAidl.cpp
@@ -31,7 +31,7 @@
 }
 
 Status GnssCallbackAidl::gnssStatusCb(const GnssStatusValue /* status */) {
-    ALOGI("gnssSvStatusCb");
+    ALOGI("gnssStatusCb");
     return Status::ok();
 }
 
@@ -47,7 +47,8 @@
     return Status::ok();
 }
 
-Status GnssCallbackAidl::gnssNmeaCb(const int64_t /* timestamp */, const std::string& /* nmea */) {
+Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
+    nmea_cbq_.store(std::make_pair(timestamp, nmea));
     return Status::ok();
 }
 
diff --git a/gnss/aidl/vts/GnssCallbackAidl.h b/gnss/aidl/vts/GnssCallbackAidl.h
index 209728d..a9495ba 100644
--- a/gnss/aidl/vts/GnssCallbackAidl.h
+++ b/gnss/aidl/vts/GnssCallbackAidl.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <android/hardware/gnss/BnGnssCallback.h>
+#include <utility>
 #include "GnssCallbackEventQueue.h"
 
 /* Callback class for data & Event. */
@@ -26,7 +27,8 @@
         : capabilities_cbq_("capabilities"),
           info_cbq_("system_info"),
           location_cbq_("location"),
-          sv_info_list_cbq_("sv_info"){};
+          sv_info_list_cbq_("sv_info"),
+          nmea_cbq_("nmea"){};
     ~GnssCallbackAidl(){};
 
     android::binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
@@ -55,4 +57,6 @@
     android::hardware::gnss::common::GnssCallbackEventQueue<
             std::vector<android::hardware::gnss::IGnssCallback::GnssSvInfo>>
             sv_info_list_cbq_;
+    android::hardware::gnss::common::GnssCallbackEventQueue<std::pair<int64_t, std::string>>
+            nmea_cbq_;
 };
\ No newline at end of file
diff --git a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
index c4fad7f..a553954 100644
--- a/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
+++ b/gnss/aidl/vts/GnssMeasurementCallbackAidl.cpp
@@ -24,12 +24,10 @@
 
 android::binder::Status GnssMeasurementCallbackAidl::gnssMeasurementCb(const GnssData& gnssData) {
     ALOGI("gnssMeasurementCb");
-    ALOGI("elapsedRealtime: flags = %d, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
+    ALOGV("elapsedRealtime: flags = 0x%X, timestampNs: %" PRId64 ", timeUncertaintyNs=%lf",
           gnssData.elapsedRealtime.flags, gnssData.elapsedRealtime.timestampNs,
           gnssData.elapsedRealtime.timeUncertaintyNs);
-    for (const auto& measurement : gnssData.measurements) {
-        ALOGI("measurement.receivedSvTimeInNs=%" PRId64, measurement.receivedSvTimeInNs);
-    }
+
     gnss_data_cbq_.store(gnssData);
     return android::binder::Status::ok();
 }
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
index f184f81..407ac0c 100644
--- a/gnss/aidl/vts/gnss_hal_test.cpp
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -18,15 +18,50 @@
 
 #include "gnss_hal_test.h"
 #include <hidl/ServiceManagement.h>
+#include <algorithm>
+#include <cmath>
 #include "Utils.h"
 
+using android::hardware::gnss::GnssClock;
 using android::hardware::gnss::GnssConstellationType;
+using android::hardware::gnss::GnssData;
 using android::hardware::gnss::GnssLocation;
+using android::hardware::gnss::GnssMeasurement;
 using android::hardware::gnss::IGnss;
 using android::hardware::gnss::IGnssCallback;
+using android::hardware::gnss::IGnssMeasurementInterface;
 using android::hardware::gnss::common::Utils;
 using GnssConstellationTypeV2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
 
+namespace {
+// The difference between the mean of the received intervals and the requested interval should not
+// be larger mInterval * ALLOWED_MEAN_ERROR_RATIO
+constexpr double ALLOWED_MEAN_ERROR_RATIO = 0.25;
+
+// The standard deviation computed for the deltas should not be bigger
+// than mInterval * ALLOWED_STDEV_ERROR_RATIO or MIN_STDEV_MS, whichever is higher.
+constexpr double ALLOWED_STDEV_ERROR_RATIO = 0.50;
+constexpr double MIN_STDEV_MS = 1000;
+
+double computeMean(std::vector<int>& deltas) {
+    long accumulator = 0;
+    for (auto& d : deltas) {
+        accumulator += d;
+    }
+    return accumulator / deltas.size();
+}
+
+double computeStdev(double mean, std::vector<int>& deltas) {
+    double accumulator = 0;
+    for (auto& d : deltas) {
+        double diff = d - mean;
+        accumulator += diff * diff;
+    }
+    return std::sqrt(accumulator / (deltas.size() - 1));
+}
+
+}  // anonymous namespace
+
 void GnssHalTest::SetUp() {
     // Get AIDL handle
     aidl_gnss_hal_ = android::waitForDeclaredService<IGnssAidl>(String16(GetParam().c_str()));
@@ -97,20 +132,26 @@
     ASSERT_TRUE(status.isOk());
 }
 
-bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
-                                             const bool low_power_mode) {
+bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode,
+                                             const bool start_sv_status, const bool start_nmea) {
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
         // Invoke the super method.
         return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckFirstLocation(min_interval_msec,
                                                                            low_power_mode);
     }
-
     SetPositionMode(min_interval_msec, low_power_mode);
+
     auto status = aidl_gnss_hal_->start();
     EXPECT_TRUE(status.isOk());
 
-    status = aidl_gnss_hal_->startSvStatus();
-    EXPECT_TRUE(status.isOk());
+    if (start_sv_status) {
+        status = aidl_gnss_hal_->startSvStatus();
+        EXPECT_TRUE(status.isOk());
+    }
+    if (start_nmea) {
+        status = aidl_gnss_hal_->startNmea();
+        EXPECT_TRUE(status.isOk());
+    }
 
     /*
      * GnssLocationProvider support of AGPS SUPL & XtraDownloader is not available in VTS,
@@ -131,6 +172,12 @@
     return false;
 }
 
+bool GnssHalTest::StartAndCheckFirstLocation(const int min_interval_msec,
+                                             const bool low_power_mode) {
+    return StartAndCheckFirstLocation(min_interval_msec, low_power_mode,
+                                      /* start_sv_status= */ true, /* start_nmea= */ true);
+}
+
 void GnssHalTest::StopAndClearLocations() {
     ALOGD("StopAndClearLocations");
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
@@ -139,6 +186,8 @@
     }
     auto status = aidl_gnss_hal_->stopSvStatus();
     EXPECT_TRUE(status.isOk());
+    status = aidl_gnss_hal_->stopNmea();
+    EXPECT_TRUE(status.isOk());
 
     status = aidl_gnss_hal_->stop();
     EXPECT_TRUE(status.isOk());
@@ -153,7 +202,8 @@
     aidl_gnss_cb_->location_cbq_.reset();
 }
 
-void GnssHalTest::StartAndCheckLocations(int count) {
+void GnssHalTest::StartAndCheckLocations(const int count, const bool start_sv_status,
+                                         const bool start_nmea) {
     if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
         // Invoke the super method.
         return GnssHalTestTemplate<IGnss_V2_1>::StartAndCheckLocations(count);
@@ -162,7 +212,8 @@
     const int kLocationTimeoutSubsequentSec = 2;
     const bool kLowPowerMode = false;
 
-    EXPECT_TRUE(StartAndCheckFirstLocation(kMinIntervalMsec, kLowPowerMode));
+    EXPECT_TRUE(StartAndCheckFirstLocation(kMinIntervalMsec, kLowPowerMode, start_sv_status,
+                                           start_nmea));
 
     for (int i = 1; i < count; i++) {
         EXPECT_TRUE(aidl_gnss_cb_->location_cbq_.retrieve(aidl_gnss_cb_->last_location_,
@@ -177,6 +228,10 @@
     }
 }
 
+void GnssHalTest::StartAndCheckLocations(const int count) {
+    StartAndCheckLocations(count, /* start_sv_status= */ true, /* start_nmea= */ true);
+}
+
 std::list<std::vector<IGnssCallback::GnssSvInfo>> GnssHalTest::convertToAidl(
         const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>>& sv_info_list) {
     std::list<std::vector<IGnssCallback::GnssSvInfo>> aidl_sv_info_list;
@@ -313,3 +368,109 @@
 
     return constellation_to_blocklist;
 }
+
+void GnssHalTest::checkGnssMeasurementClockFields(const GnssData& measurement) {
+    Utils::checkElapsedRealtime(measurement.elapsedRealtime);
+    ASSERT_TRUE(measurement.clock.gnssClockFlags >= 0 &&
+                measurement.clock.gnssClockFlags <=
+                        (GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
+                         GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
+                         GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
+                         GnssClock::HAS_DRIFT_UNCERTAINTY));
+}
+
+void GnssHalTest::checkGnssMeasurementFlags(const GnssMeasurement& measurement) {
+    ASSERT_TRUE(measurement.flags >= 0 &&
+                measurement.flags <=
+                        (GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
+                         GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
+                         GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
+                         GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
+                         GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
+                         GnssMeasurement::HAS_SATELLITE_ISB |
+                         GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY |
+                         GnssMeasurement::HAS_SATELLITE_PVT |
+                         GnssMeasurement::HAS_CORRELATION_VECTOR));
+}
+
+void GnssHalTest::checkGnssMeasurementFields(const GnssMeasurement& measurement,
+                                             const GnssData& data) {
+    checkGnssMeasurementFlags(measurement);
+    // Verify CodeType is valid.
+    ASSERT_NE(measurement.signalType.codeType, "");
+    // Verify basebandCn0DbHz is valid.
+    ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
+
+    if (((measurement.flags & GnssMeasurement::HAS_FULL_ISB) > 0) &&
+        ((measurement.flags & GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
+        ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB) > 0) &&
+        ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) {
+        GnssConstellationType referenceConstellation =
+                data.clock.referenceSignalTypeForIsb.constellation;
+        double carrierFrequencyHz = data.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
+        std::string codeType = data.clock.referenceSignalTypeForIsb.codeType;
+
+        ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
+                    referenceConstellation <= GnssConstellationType::IRNSS);
+        ASSERT_TRUE(carrierFrequencyHz > 0);
+        ASSERT_NE(codeType, "");
+
+        ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
+        ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
+        ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
+        ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
+    }
+}
+
+void GnssHalTest::startMeasurementWithInterval(
+        int intervalMs, const sp<IGnssMeasurementInterface>& iGnssMeasurement,
+        sp<GnssMeasurementCallbackAidl>& callback) {
+    ALOGD("Start requesting measurement at interval of %d millis.", intervalMs);
+    IGnssMeasurementInterface::Options options;
+    options.intervalMs = intervalMs;
+    auto status = iGnssMeasurement->setCallbackWithOptions(callback, options);
+    ASSERT_TRUE(status.isOk());
+}
+
+void GnssHalTest::collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
+                                              const int numMeasurementEvents,
+                                              const int timeoutSeconds,
+                                              std::vector<int>& deltasMs) {
+    int64_t lastElapsedRealtimeMillis = 0;
+    for (int i = 0; i < numMeasurementEvents; i++) {
+        GnssData lastGnssData;
+        ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastGnssData, timeoutSeconds));
+        EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+        ASSERT_TRUE(lastGnssData.measurements.size() > 0);
+
+        // Validity check GnssData fields
+        checkGnssMeasurementClockFields(lastGnssData);
+        for (const auto& measurement : lastGnssData.measurements) {
+            checkGnssMeasurementFields(measurement, lastGnssData);
+        }
+
+        long currentElapsedRealtimeMillis = lastGnssData.elapsedRealtime.timestampNs * 1e-6;
+        if (lastElapsedRealtimeMillis != 0) {
+            deltasMs.push_back(currentElapsedRealtimeMillis - lastElapsedRealtimeMillis);
+        }
+        lastElapsedRealtimeMillis = currentElapsedRealtimeMillis;
+    }
+}
+
+void GnssHalTest::assertMeanAndStdev(int intervalMs, std::vector<int>& deltasMs) {
+    double mean = computeMean(deltasMs);
+    double stdev = computeStdev(mean, deltasMs);
+    EXPECT_TRUE(std::abs(mean - intervalMs) <= intervalMs * ALLOWED_MEAN_ERROR_RATIO)
+            << "Test failed, because the mean of intervals is " << mean
+            << " millis. The test requires that abs(" << mean << " - " << intervalMs
+            << ") <= " << intervalMs * ALLOWED_MEAN_ERROR_RATIO
+            << " millis, when the requested interval is " << intervalMs << " millis.";
+
+    double maxStdev = std::max(MIN_STDEV_MS, intervalMs * ALLOWED_STDEV_ERROR_RATIO);
+    EXPECT_TRUE(stdev <= maxStdev)
+            << "Test failed, because the stdev of intervals is " << stdev
+            << " millis, which must be <= " << maxStdev
+            << " millis, when the requested interval is " << intervalMs << " millis.";
+    ALOGD("Mean of interval deltas in millis: %.1lf", mean);
+    ALOGD("Stdev of interval deltas in millis: %.1lf", stdev);
+}
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
index d479af3..645fc82 100644
--- a/gnss/aidl/vts/gnss_hal_test.h
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -25,6 +25,7 @@
 #include <android/hardware/gnss/2.1/IGnss.h>
 #include "GnssBatchingCallback.h"
 #include "GnssCallbackAidl.h"
+#include "GnssMeasurementCallbackAidl.h"
 #include "v2_1/gnss_hal_test_template.h"
 
 using IGnss_V2_1 = android::hardware::gnss::V2_1::IGnss;
@@ -68,8 +69,11 @@
                        const bool check_speed);
     void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
     bool StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode);
+    bool StartAndCheckFirstLocation(const int min_interval_msec, const bool low_power_mode,
+                                    const bool start_sv_status, const bool start_nmea);
     void StopAndClearLocations();
-    void StartAndCheckLocations(int count);
+    void StartAndCheckLocations(const int count);
+    void StartAndCheckLocations(const int count, const bool start_sv_status, const bool start_nmea);
 
     android::hardware::gnss::GnssConstellationType startLocationAndGetNonGpsConstellation(
             const int locations_to_await, const int gnss_sv_info_list_timeout);
@@ -85,6 +89,19 @@
                     sv_info_list,
             const int min_observations);
 
+    void checkGnssMeasurementClockFields(const android::hardware::gnss::GnssData& measurement);
+    void checkGnssMeasurementFlags(const android::hardware::gnss::GnssMeasurement& measurement);
+    void checkGnssMeasurementFields(const android::hardware::gnss::GnssMeasurement& measurement,
+                                    const android::hardware::gnss::GnssData& data);
+    void startMeasurementWithInterval(
+            int intervalMillis,
+            const sp<android::hardware::gnss::IGnssMeasurementInterface>& iMeasurement,
+            sp<GnssMeasurementCallbackAidl>& callback);
+    void collectMeasurementIntervals(const sp<GnssMeasurementCallbackAidl>& callback,
+                                     const int numMeasurementEvents, const int timeoutSeconds,
+                                     std::vector<int>& deltaMs);
+    void assertMeanAndStdev(int intervalMillis, std::vector<int>& deltasMillis);
+
     sp<IGnssAidl> aidl_gnss_hal_;
     sp<GnssCallbackAidl> aidl_gnss_cb_;  // Primary callback interface
 };
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 54946fb..f926c40 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -28,7 +28,9 @@
 #include <android/hardware/gnss/measurement_corrections/IMeasurementCorrectionsInterface.h>
 #include <android/hardware/gnss/visibility_control/IGnssVisibilityControl.h>
 #include <cutils/properties.h>
+#include <utils/SystemClock.h>
 #include <cmath>
+#include <utility>
 #include "AGnssCallbackAidl.h"
 #include "AGnssRilCallbackAidl.h"
 #include "GnssAntennaInfoCallbackAidl.h"
@@ -376,58 +378,6 @@
     }
 }
 
-void CheckGnssMeasurementClockFields(const GnssData& measurement) {
-    Utils::checkElapsedRealtime(measurement.elapsedRealtime);
-    ASSERT_TRUE(measurement.clock.gnssClockFlags >= 0 &&
-                measurement.clock.gnssClockFlags <=
-                        (GnssClock::HAS_LEAP_SECOND | GnssClock::HAS_TIME_UNCERTAINTY |
-                         GnssClock::HAS_FULL_BIAS | GnssClock::HAS_BIAS |
-                         GnssClock::HAS_BIAS_UNCERTAINTY | GnssClock::HAS_DRIFT |
-                         GnssClock::HAS_DRIFT_UNCERTAINTY));
-}
-
-void CheckGnssMeasurementFlags(const GnssMeasurement& measurement) {
-    ASSERT_TRUE(measurement.flags >= 0 &&
-                measurement.flags <=
-                        (GnssMeasurement::HAS_SNR | GnssMeasurement::HAS_CARRIER_FREQUENCY |
-                         GnssMeasurement::HAS_CARRIER_CYCLES | GnssMeasurement::HAS_CARRIER_PHASE |
-                         GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY |
-                         GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL |
-                         GnssMeasurement::HAS_FULL_ISB | GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY |
-                         GnssMeasurement::HAS_SATELLITE_ISB |
-                         GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY |
-                         GnssMeasurement::HAS_SATELLITE_PVT |
-                         GnssMeasurement::HAS_CORRELATION_VECTOR));
-}
-
-void CheckGnssMeasurementFields(const GnssMeasurement& measurement, const GnssData& data) {
-    CheckGnssMeasurementFlags(measurement);
-    // Verify CodeType is valid.
-    ASSERT_NE(measurement.signalType.codeType, "");
-    // Verify basebandCn0DbHz is valid.
-    ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
-
-    if (((measurement.flags & GnssMeasurement::HAS_FULL_ISB) > 0) &&
-        ((measurement.flags & GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
-        ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB) > 0) &&
-        ((measurement.flags & GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY) > 0)) {
-        GnssConstellationType referenceConstellation =
-                data.clock.referenceSignalTypeForIsb.constellation;
-        double carrierFrequencyHz = data.clock.referenceSignalTypeForIsb.carrierFrequencyHz;
-        std::string codeType = data.clock.referenceSignalTypeForIsb.codeType;
-
-        ASSERT_TRUE(referenceConstellation >= GnssConstellationType::UNKNOWN &&
-                    referenceConstellation <= GnssConstellationType::IRNSS);
-        ASSERT_TRUE(carrierFrequencyHz > 0);
-        ASSERT_NE(codeType, "");
-
-        ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
-        ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
-        ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
-        ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
-    }
-}
-
 /*
  * TestGnssMeasurementExtensionAndSatellitePvt:
  * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
@@ -465,10 +415,10 @@
         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
 
         // Validity check GnssData fields
-        CheckGnssMeasurementClockFields(lastMeasurement);
+        checkGnssMeasurementClockFields(lastMeasurement);
 
         for (const auto& measurement : lastMeasurement.measurements) {
-            CheckGnssMeasurementFields(measurement, lastMeasurement);
+            checkGnssMeasurementFields(measurement, lastMeasurement);
             if (measurement.flags & GnssMeasurement::HAS_SATELLITE_PVT &&
                 kIsSatellitePvtSupported == true) {
                 ALOGD("Found a measurement with SatellitePvt");
@@ -525,10 +475,10 @@
         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
 
         // Validity check GnssData fields
-        CheckGnssMeasurementClockFields(lastMeasurement);
+        checkGnssMeasurementClockFields(lastMeasurement);
 
         for (const auto& measurement : lastMeasurement.measurements) {
-            CheckGnssMeasurementFields(measurement, lastMeasurement);
+            checkGnssMeasurementFields(measurement, lastMeasurement);
             if (measurement.flags & GnssMeasurement::HAS_CORRELATION_VECTOR) {
                 correlationVectorFound = true;
                 ASSERT_TRUE(measurement.correlationVectors.size() > 0);
@@ -1242,48 +1192,6 @@
 }
 
 /*
- * TestGnssMeasurementSetCallbackWithOptions:
- * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
- * 2. Sets a GnssMeasurementCallback with intervalMillis option, waits for measurements reported,
- *    and verifies mandatory fields are valid.
- */
-TEST_P(GnssHalTest, TestGnssMeasurementSetCallbackWithOptions) {
-    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
-        return;
-    }
-    const int kFirstGnssMeasurementTimeoutSeconds = 10;
-    const int kNumMeasurementEvents = 5;
-
-    sp<IGnssMeasurementInterface> iGnssMeasurement;
-    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
-    ASSERT_TRUE(status.isOk());
-    ASSERT_TRUE(iGnssMeasurement != nullptr);
-
-    auto callback = sp<GnssMeasurementCallbackAidl>::make();
-    IGnssMeasurementInterface::Options options;
-    options.intervalMs = 2000;
-    status = iGnssMeasurement->setCallbackWithOptions(callback, options);
-    ASSERT_TRUE(status.isOk());
-
-    for (int i = 0; i < kNumMeasurementEvents; i++) {
-        GnssData lastMeasurement;
-        ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
-                                                      kFirstGnssMeasurementTimeoutSeconds));
-        EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
-        ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
-
-        // Validity check GnssData fields
-        CheckGnssMeasurementClockFields(lastMeasurement);
-        for (const auto& measurement : lastMeasurement.measurements) {
-            CheckGnssMeasurementFields(measurement, lastMeasurement);
-        }
-    }
-
-    status = iGnssMeasurement->close();
-    ASSERT_TRUE(status.isOk());
-}
-
-/*
  * TestGnssAgcInGnssMeasurement:
  * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
  * 2. Sets a GnssMeasurementCallback, waits for a measurement.
@@ -1293,7 +1201,7 @@
         return;
     }
     const int kFirstGnssMeasurementTimeoutSeconds = 10;
-    const int kNumMeasurementEvents = 15;
+    const int kNumMeasurementEvents = 5;
 
     sp<IGnssMeasurementInterface> iGnssMeasurement;
     auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
@@ -1313,7 +1221,7 @@
         ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
 
         // Validity check GnssData fields
-        CheckGnssMeasurementClockFields(lastMeasurement);
+        checkGnssMeasurementClockFields(lastMeasurement);
 
         ASSERT_TRUE(lastMeasurement.gnssAgcs.size() > 0);
         for (const auto& gnssAgc : lastMeasurement.gnssAgcs) {
@@ -1444,3 +1352,143 @@
             Utils::getMockMeasurementCorrections_aidl());
     ASSERT_TRUE(status.isOk());
 }
+
+/*
+ * TestStopSvStatusAndNmea:
+ * 1. Call stopSvStatus and stopNmea.
+ * 2. Start location and verify that
+ *    - no SvStatus is received.
+ *    - no Nmea is received.
+ */
+TEST_P(GnssHalTest, TestStopSvStatusAndNmea) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+        return;
+    }
+    auto status = aidl_gnss_hal_->stopSvStatus();
+    EXPECT_TRUE(status.isOk());
+    status = aidl_gnss_hal_->stopNmea();
+    EXPECT_TRUE(status.isOk());
+
+    int kLocationsToAwait = 5;
+    aidl_gnss_cb_->location_cbq_.reset();
+    aidl_gnss_cb_->sv_info_list_cbq_.reset();
+    aidl_gnss_cb_->nmea_cbq_.reset();
+    StartAndCheckLocations(/* count= */ kLocationsToAwait,
+                           /* start_sv_status= */ false, /* start_nmea= */ false);
+    int location_called_count = aidl_gnss_cb_->location_cbq_.calledCount();
+    ALOGD("Observed %d GnssSvStatus, and %d Nmea while awaiting %d locations (%d received)",
+          aidl_gnss_cb_->sv_info_list_cbq_.size(), aidl_gnss_cb_->nmea_cbq_.size(),
+          kLocationsToAwait, location_called_count);
+
+    // Ensure that no SvStatus & no Nmea is received.
+    EXPECT_EQ(aidl_gnss_cb_->sv_info_list_cbq_.size(), 0);
+    EXPECT_EQ(aidl_gnss_cb_->nmea_cbq_.size(), 0);
+
+    StopAndClearLocations();
+}
+
+/*
+ * TestGnssMeasurementIntervals_WithoutLocation:
+ * 1. start measurement with interval
+ * 2. verify that the received measurement intervals have expected mean and stdev
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIntervals_WithoutLocation) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+        return;
+    }
+
+    std::vector<int> intervals({2000, 4000});
+    std::vector<int> numEvents({10, 5});
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    ALOGD("TestGnssMeasurementIntervals_WithoutLocation");
+    for (int i = 0; i < intervals.size(); i++) {
+        auto callback = sp<GnssMeasurementCallbackAidl>::make();
+        startMeasurementWithInterval(intervals[i], iGnssMeasurement, callback);
+
+        std::vector<int> deltas;
+        collectMeasurementIntervals(callback, numEvents[i], /* timeoutSeconds= */ 10, deltas);
+
+        status = iGnssMeasurement->close();
+        ASSERT_TRUE(status.isOk());
+
+        assertMeanAndStdev(intervals[i], deltas);
+    }
+}
+
+/*
+ * TestGnssMeasurementIntervals_LocationOnBeforeMeasurement:
+ * 1. start measurement with interval
+ * 2. verify that the received measurement intervals have expected mean and stdev
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnBeforeMeasurement) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+        return;
+    }
+
+    std::vector<int> intervals({2000});
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    int locationIntervalMs = 1000;
+
+    // Start location first and then start measurement
+    ALOGD("TestGnssMeasurementIntervals_LocationOnBeforeMeasurement");
+    StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
+    for (auto& intervalMs : intervals) {
+        auto callback = sp<GnssMeasurementCallbackAidl>::make();
+        startMeasurementWithInterval(intervalMs, iGnssMeasurement, callback);
+
+        std::vector<int> deltas;
+        collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10, deltas);
+
+        status = iGnssMeasurement->close();
+        ASSERT_TRUE(status.isOk());
+
+        assertMeanAndStdev(locationIntervalMs, deltas);
+    }
+    StopAndClearLocations();
+}
+
+/*
+ * TestGnssMeasurementIntervals:
+ * 1. start measurement with interval
+ * 2. verify that the received measurement intervals have expected mean and stdev
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementIntervals_LocationOnAfterMeasurement) {
+    if (aidl_gnss_hal_->getInterfaceVersion() <= 1) {
+        return;
+    }
+
+    std::vector<int> intervals({2000});
+
+    sp<IGnssMeasurementInterface> iGnssMeasurement;
+    auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+    int locationIntervalMs = 1000;
+    // Start location first and then start measurement
+    ALOGD("TestGnssMeasurementIntervals_LocationOnAfterMeasurement");
+    for (auto& intervalMs : intervals) {
+        auto callback = sp<GnssMeasurementCallbackAidl>::make();
+        startMeasurementWithInterval(intervalMs, iGnssMeasurement, callback);
+
+        StartAndCheckFirstLocation(locationIntervalMs, /* lowPowerMode= */ false);
+        std::vector<int> deltas;
+        collectMeasurementIntervals(callback, /*numEvents=*/10, /*timeoutSeconds=*/10, deltas);
+
+        StopAndClearLocations();
+        status = iGnssMeasurement->close();
+        ASSERT_TRUE(status.isOk());
+
+        assertMeanAndStdev(locationIntervalMs, deltas);
+    }
+}
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index 7065a6fb..ad8f539 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -56,6 +56,31 @@
     static hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo> getMockAntennaInfos();
 };
 
+struct ThreadBlocker {
+    // returns false if unblocked:
+    template <class R, class P>
+    bool wait_for(std::chrono::duration<R, P> const& time) {
+        std::unique_lock<std::mutex> lock(m);
+        return !cv.wait_for(lock, time, [&] { return terminate; });
+    }
+
+    void notify() {
+        std::unique_lock<std::mutex> lock(m);
+        terminate = true;
+        cv.notify_all();
+    }
+
+    void reset() {
+        std::unique_lock<std::mutex> lock(m);
+        terminate = false;
+    }
+
+  private:
+    std::condition_variable cv;
+    std::mutex m;
+    bool terminate = false;
+};
+
 }  // namespace common
 }  // namespace gnss
 }  // namespace hardware
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index 8732d53..c0a0c07 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -32,6 +32,7 @@
         "TestCommandReader.cpp",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@3.0-vts",
@@ -39,6 +40,7 @@
         "libgtest",
     ],
     export_static_lib_headers: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.mapper@2.0-vts",
         "android.hardware.graphics.mapper@3.0-vts",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index 55aaf12..e777010 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -318,7 +318,7 @@
     [this] {
         ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
                                                                        /*errOnFailure=*/false));
-        if (mGralloc4->getAllocator() == nullptr || mGralloc4->getMapper() == nullptr) {
+        if (!mGralloc4->hasAllocator() || mGralloc4->getMapper() == nullptr) {
             mGralloc4 = nullptr;
             ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
                                                                            /*errOnFailure=*/false));
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index 9ffd7d5..502036e 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -32,14 +32,17 @@
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
         "libbase",
+        "libbinder_ndk",
         "libfmq",
         "libsync",
+        "android.hardware.common-V2-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
@@ -49,10 +52,14 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index aa8e541..cca5323 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -35,6 +35,7 @@
         "libui",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer3-V1-ndk",
@@ -52,6 +53,7 @@
         "android.hardware.graphics.mapper@4.0-vts",
     ],
     export_static_lib_headers: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1-vts",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.mapper@2.1-vts",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index a526137..7de4007 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -184,7 +184,7 @@
         ALOGD("Attempting to initialize gralloc4");
         ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
                                                                        /*errOnFailure=*/false));
-        if (mGralloc4->getMapper() == nullptr || mGralloc4->getAllocator() == nullptr) {
+        if (mGralloc4->getMapper() == nullptr || !mGralloc4->hasAllocator()) {
             mGralloc4 = nullptr;
             ALOGD("Failed to initialize gralloc4, initializing gralloc3");
             ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index dd519e7..960b62d 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -45,18 +45,21 @@
         "libGLESv1_CM",
         "libGLESv2",
         "libbase",
+        "libbinder_ndk",
         "libfmq",
         "libgui",
         "libhidlbase",
         "libprocessgroup",
         "libsync",
         "libui",
+        "android.hardware.common-V2-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
@@ -70,6 +73,7 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
         "libgtest",
         "librenderengine",
         "libshaders",
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index 70384ac..40b77d5 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -32,15 +32,18 @@
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
         "libbase",
+        "libbinder_ndk",
         "libfmq",
         "libhidlbase",
         "libsync",
+        "android.hardware.common-V2-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
@@ -54,6 +57,7 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
@@ -61,5 +65,8 @@
         "android.hardware.graphics.composer@2.3-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
index 5ef861c..de31975 100644
--- a/graphics/composer/2.4/utils/vts/Android.bp
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -32,6 +32,7 @@
         "TestCommandReader.cpp",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3-vts",
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index 22ae7c4..b73ea94 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -32,14 +32,17 @@
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
         "libbase",
+        "libbinder_ndk",
         "libfmq",
         "libsync",
+        "android.hardware.common-V2-ndk",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.graphics.mapper@3.0",
         "android.hardware.graphics.mapper@4.0",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
@@ -55,6 +58,7 @@
         "android.hardware.graphics.mapper@2.1-vts",
         "android.hardware.graphics.mapper@3.0-vts",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
     ],
     header_libs: [
         "android.hardware.graphics.composer@2.1-command-buffer",
@@ -63,5 +67,8 @@
         "android.hardware.graphics.composer@2.4-command-buffer",
     ],
     disable_framework: true,
-    test_suites: ["general-tests", "vts"],
+    test_suites: [
+        "general-tests",
+        "vts",
+    ],
 }
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
index 6331498..7abf5db 100644
--- a/graphics/mapper/4.0/utils/vts/Android.bp
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -32,14 +32,21 @@
         "-g",
     ],
     static_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@4.0",
+        "android.hardware.graphics.common-V3-ndk",
         "android.hardware.graphics.mapper@4.0",
+        "libaidlcommonsupport",
     ],
     shared_libs: [
+        "libbinder_ndk",
         "libgralloctypes",
+        "libvndksupport",
     ],
     export_static_lib_headers: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@4.0",
+        "android.hardware.graphics.common-V3-ndk",
         "android.hardware.graphics.mapper@4.0",
     ],
     export_include_dirs: ["include"],
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
index 4a6f68d..e4a2535 100644
--- a/graphics/mapper/4.0/utils/vts/MapperVts.cpp
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
+#include <aidlcommonsupport/NativeHandle.h>
 #include <android-base/properties.h>
+#include <android/binder_manager.h>
 #include <gralloctypes/Gralloc4.h>
 #include <mapper-vts/4.0/MapperVts.h>
 
@@ -35,8 +37,14 @@
 }
 
 void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
-    mAllocator = IAllocator::getService(allocatorServiceName);
-    ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+    mAidlAllocator = aidl::android::hardware::graphics::allocator::IAllocator::fromBinder(
+            ndk::SpAIBinder(AServiceManager_checkService(allocatorServiceName.c_str())));
+
+    if (mAidlAllocator == nullptr) {
+        mHidlAllocator = IAllocator::getService(allocatorServiceName);
+    }
+    ASSERT_TRUE(nullptr != mAidlAllocator || mHidlAllocator != nullptr)
+            << "failed to get allocator service";
 
     mMapper = IMapper::getService(mapperServiceName);
     ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
@@ -45,7 +53,12 @@
 
 void Gralloc::initNoErr(const std::string& allocatorServiceName,
                         const std::string& mapperServiceName) {
-    mAllocator = IAllocator::getService(allocatorServiceName);
+    mAidlAllocator = aidl::android::hardware::graphics::allocator::IAllocator::fromBinder(
+            ndk::SpAIBinder(AServiceManager_checkService(allocatorServiceName.c_str())));
+
+    if (mAidlAllocator == nullptr) {
+        mHidlAllocator = IAllocator::getService(allocatorServiceName);
+    }
 
     mMapper = IMapper::getService(mapperServiceName);
     if (mMapper.get()) {
@@ -68,10 +81,6 @@
     mImportedBuffers.clear();
 }
 
-sp<IAllocator> Gralloc::getAllocator() const {
-    return mAllocator;
-}
-
 const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle,
                                             enum Tolerance /*tolerance*/) {
     const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
@@ -90,40 +99,40 @@
                                                       uint32_t* outStride) {
     std::vector<const native_handle_t*> bufferHandles;
     bufferHandles.reserve(count);
-    mAllocator->allocate(descriptor, count,
-                         [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
-                             if (canTolerate(tolerance, tmpError)) {
-                                 return;
-                             }
 
-                             if (tmpError != Error::NONE) {
-                                 if (base::GetIntProperty("ro.vendor.build.version.sdk", 0, 0,
-                                                          INT_MAX) < 33) {
-                                     GTEST_SKIP() << "Old vendor grallocs may not support P010";
-                                 } else {
-                                     GTEST_FAIL() << "failed to allocate buffers";
-                                 }
-                             }
-                             ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
+    auto callback = [&](Error error, uint32_t stride,
+                        const hidl_vec<hidl_handle>& buffers) -> void {
+        if (canTolerate(tolerance, error)) {
+            return;
+        }
 
-                             for (uint32_t i = 0; i < count; i++) {
-                                 const native_handle_t* bufferHandle = nullptr;
-                                 if (import) {
-                                     ASSERT_NO_FATAL_FAILURE(
-                                             bufferHandle = importBuffer(tmpBuffers[i], tolerance));
-                                 } else {
-                                     ASSERT_NO_FATAL_FAILURE(
-                                             bufferHandle = cloneBuffer(tmpBuffers[i], tolerance));
-                                 }
-                                 if (bufferHandle) {
-                                     bufferHandles.push_back(bufferHandle);
-                                 }
-                             }
+        if (error != Error::NONE) {
+            if (base::GetIntProperty("ro.vendor.build.version.sdk", 0, 0, INT_MAX) < 33) {
+                GTEST_SKIP() << "Old vendor grallocs may not support P010";
+            } else {
+                GTEST_FAIL() << "failed to allocate buffers";
+            }
+        }
+        ASSERT_EQ(count, buffers.size()) << "invalid buffer array";
 
-                             if (outStride) {
-                                 *outStride = tmpStride;
-                             }
-                         });
+        for (uint32_t i = 0; i < count; i++) {
+            const native_handle_t* bufferHandle = nullptr;
+            if (import) {
+                ASSERT_NO_FATAL_FAILURE(bufferHandle = importBuffer(buffers[i], tolerance));
+            } else {
+                ASSERT_NO_FATAL_FAILURE(bufferHandle = cloneBuffer(buffers[i], tolerance));
+            }
+            if (bufferHandle) {
+                bufferHandles.push_back(bufferHandle);
+            }
+        }
+
+        if (outStride) {
+            *outStride = stride;
+        }
+    };
+
+    rawAllocate(descriptor, count, callback);
 
     if (::testing::Test::HasFatalFailure()) {
         bufferHandles.clear();
@@ -147,6 +156,23 @@
     return buffers[0];
 }
 
+void Gralloc::rawAllocate(
+        const BufferDescriptor& descriptor, uint32_t count,
+        std::function<void(Error, uint32_t, const hidl_vec<hidl_handle>&)> callback) {
+    if (mAidlAllocator) {
+        aidl::android::hardware::graphics::allocator::AllocationResult result;
+        auto status = mAidlAllocator->allocate(descriptor, count, &result);
+        const Error error = toHidlError(status);
+        std::vector<hidl_handle> handles;
+        for (const auto& aidlHandle : result.buffers) {
+            handles.push_back(hidl_handle(makeFromAidl(aidlHandle)));
+        }
+        callback(error, result.stride, handles);
+    } else {
+        mHidlAllocator->allocate(descriptor, count, callback);
+    }
+}
+
 sp<IMapper> Gralloc::getMapper() const {
     return mMapper;
 }
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
index c5406c9..b956e49 100644
--- a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -20,6 +20,8 @@
 #include <unordered_set>
 #include <vector>
 
+#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
+#include <aidl/android/hardware/graphics/allocator/IAllocator.h>
 #include <android/hardware/graphics/allocator/4.0/IAllocator.h>
 #include <android/hardware/graphics/mapper/4.0/IMapper.h>
 #include <gtest/gtest.h>
@@ -51,9 +53,33 @@
             const std::string& mapperServiceName = "default", bool errOnFailure = true);
     ~Gralloc();
 
+    static Error toHidlError(aidl::android::hardware::graphics::allocator::AllocationError error) {
+        switch (error) {
+            case aidl::android::hardware::graphics::allocator::AllocationError::BAD_DESCRIPTOR:
+                return Error::BAD_DESCRIPTOR;
+            case aidl::android::hardware::graphics::allocator::AllocationError::NO_RESOURCES:
+                return Error::NO_RESOURCES;
+            case aidl::android::hardware::graphics::allocator::AllocationError::UNSUPPORTED:
+                return Error::UNSUPPORTED;
+        }
+    }
+    static Error toHidlError(const ndk::ScopedAStatus& status) {
+        if (status.isOk()) {
+            return Error::NONE;
+        }
+
+        if (status.getExceptionCode() != EX_SERVICE_SPECIFIC) {
+            return Error::NO_RESOURCES;
+        }
+
+        return toHidlError(
+                static_cast<aidl::android::hardware::graphics::allocator::AllocationError>(
+                        status.getServiceSpecificError()));
+    }
+
     // IAllocator methods
 
-    sp<IAllocator> getAllocator() const;
+    bool hasAllocator() { return mHidlAllocator != nullptr || mAidlAllocator != nullptr; }
 
     // When import is false, this simply calls IAllocator::allocate. When import
     // is true, the returned buffers are also imported into the mapper.
@@ -81,6 +107,10 @@
         return allocate(descriptorInfo, import, Tolerance::kToleranceStrict, outStride);
     }
 
+    // Dispatches directly to the allocator
+    void rawAllocate(const BufferDescriptor& descriptor, uint32_t count,
+                     std::function<void(Error, uint32_t, const hidl_vec<hidl_handle>&)> callback);
+
     // IMapper methods
 
     sp<IMapper> getMapper() const;
@@ -143,7 +173,8 @@
         return cloneBuffer(rawHandle, Tolerance::kToleranceStrict);
     }
 
-    sp<IAllocator> mAllocator;
+    sp<IAllocator> mHidlAllocator;
+    std::shared_ptr<aidl::android::hardware::graphics::allocator::IAllocator> mAidlAllocator;
     sp<IMapper> mMapper;
 
     // Keep track of all cloned and imported handles.  When a test fails with
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
index 65bc380..e830633 100644
--- a/graphics/mapper/4.0/vts/functional/Android.bp
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -25,20 +25,27 @@
 
 cc_test {
     name: "VtsHalGraphicsMapperV4_0TargetTest",
-    defaults: ["VtsHalTargetTestDefaults"],
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
     srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
     static_libs: [
         "android.hardware.graphics.common-V3-ndk",
         "android.hardware.graphics.mapper@4.0-vts",
+        "libaidlcommonsupport",
         "libgralloctypes",
         "libsync",
     ],
     shared_libs: [
+        "android.hardware.graphics.allocator-V1-ndk",
         "android.hardware.graphics.allocator@4.0",
         "android.hardware.graphics.common@1.0",
         "android.hardware.graphics.common@1.1",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@4.0",
+        "libbinder_ndk",
+        "libvndksupport",
     ],
     header_libs: [
         "libsystem_headers",
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 2aac337..5a450e3 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -21,8 +21,12 @@
 #include <thread>
 #include <vector>
 
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationError.h>
+#include <aidl/android/hardware/graphics/allocator/AllocationResult.h>
 #include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
+#include <aidlcommonsupport/NativeHandle.h>
 
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
@@ -72,7 +76,7 @@
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>(std::get<0>(GetParam()),
                                                                      std::get<1>(GetParam())));
-        ASSERT_NE(nullptr, mGralloc->getAllocator().get());
+        ASSERT_TRUE(mGralloc->hasAllocator());
         ASSERT_NE(nullptr, mGralloc->getMapper().get());
 
         mDummyDescriptorInfo.name = "dummy";
@@ -504,10 +508,10 @@
 TEST_P(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
     // this assumes any valid descriptor is non-empty
     BufferDescriptor descriptor;
-    mGralloc->getAllocator()->allocate(descriptor, 1,
-                                       [&](const auto& tmpError, const auto&, const auto&) {
-                                           EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
-                                       });
+
+    mGralloc->rawAllocate(descriptor, 1, [&](const auto& tmpError, const auto&, const auto&) {
+        EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
+    });
 }
 
 /**
@@ -535,9 +539,9 @@
     std::atomic<uint64_t> allocationCount(0);
     auto threadLoop = [&]() {
         while (!timeUp) {
-            mGralloc->getAllocator()->allocate(
-                    descriptor, 1,
-                    [&](const auto&, const auto&, const auto&) { allocationCount++; });
+            mGralloc->rawAllocate(descriptor, 1, [&](const auto&, const auto&, const auto&) {
+                allocationCount++;
+            });
         }
     };
 
@@ -2755,8 +2759,9 @@
         BufferDescriptor descriptor;
         ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(info));
 
-        Error err;
-        mGralloc->getAllocator()->allocate(
+        Error err = Error::NONE;
+
+        mGralloc->rawAllocate(
                 descriptor, 1, [&](const auto& tmpError, const auto&, const auto& tmpBuffers) {
                     err = tmpError;
                     if (err == Error::NONE) {
@@ -2827,11 +2832,27 @@
 }
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsMapperHidlTest);
+
+namespace {
+std::vector<std::string> getAllocatorInstances() {
+    std::vector<std::string> instances;
+    for (auto halInstance : android::hardware::getAllHalInstanceNames(IAllocator::descriptor)) {
+        instances.emplace_back(std::move(halInstance));
+    }
+
+    for (auto aidlInstance : getAidlHalInstanceNames(
+                 aidl::android::hardware::graphics::allocator::IAllocator::descriptor)) {
+        instances.emplace_back(std::move(aidlInstance));
+    }
+
+    return instances;
+}
+}  // namespace
+
 INSTANTIATE_TEST_CASE_P(
         PerInstance, GraphicsMapperHidlTest,
         testing::Combine(
-                testing::ValuesIn(
-                        android::hardware::getAllHalInstanceNames(IAllocator::descriptor)),
+                testing::ValuesIn(getAllocatorInstances()),
                 testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMapper::descriptor))),
         android::hardware::PrintInstanceTupleNameToString<>);
 
diff --git a/power/aidl/vts/VtsHalPowerTargetTest.cpp b/power/aidl/vts/VtsHalPowerTargetTest.cpp
index e0ca87f..2cfa04a 100644
--- a/power/aidl/vts/VtsHalPowerTargetTest.cpp
+++ b/power/aidl/vts/VtsHalPowerTargetTest.cpp
@@ -211,19 +211,6 @@
     }
 }
 
-// GAME_LOADING mode is required for all devices which ship on Android T
-// or later
-TEST_P(PowerAidl, hasGameLoading) {
-    auto apiLevel = GetUintProperty<uint64_t>("ro.vendor.api_level", 0);
-    ASSERT_NE(apiLevel, 0);
-
-    if (apiLevel >= 33) {
-        bool supported;
-        ASSERT_TRUE(power->isModeSupported(Mode::GAME_LOADING, &supported).isOk());
-        ASSERT_TRUE(supported);
-    }
-}
-
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PowerAidl);
 INSTANTIATE_TEST_SUITE_P(Power, PowerAidl,
                          testing::ValuesIn(::android::getAidlHalInstanceNames(IPower::descriptor)),
diff --git a/wifi/1.6/default/ringbuffer.cpp b/wifi/1.6/default/ringbuffer.cpp
index 6d4ed84..981bf7b 100644
--- a/wifi/1.6/default/ringbuffer.cpp
+++ b/wifi/1.6/default/ringbuffer.cpp
@@ -26,20 +26,26 @@
 
 Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
 
-void Ringbuffer::append(const std::vector<uint8_t>& input) {
+enum Ringbuffer::AppendStatus Ringbuffer::append(const std::vector<uint8_t>& input) {
     if (input.size() == 0) {
-        return;
+        return AppendStatus::FAIL_IP_BUFFER_ZERO;
     }
     if (input.size() > maxSize_) {
         LOG(INFO) << "Oversized message of " << input.size() << " bytes is dropped";
-        return;
+        return AppendStatus::FAIL_IP_BUFFER_EXCEEDED_MAXSIZE;
     }
     data_.push_back(input);
     size_ += input.size() * sizeof(input[0]);
     while (size_ > maxSize_) {
+        if (data_.front().size() <= 0 || data_.front().size() > maxSize_) {
+            LOG(ERROR) << "First buffer in the ring buffer is Invalid. Size: "
+                       << data_.front().size();
+            return AppendStatus::FAIL_RING_BUFFER_CORRUPTED;
+        }
         size_ -= data_.front().size() * sizeof(data_.front()[0]);
         data_.pop_front();
     }
+    return AppendStatus::SUCCESS;
 }
 
 const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
diff --git a/wifi/1.6/default/ringbuffer.h b/wifi/1.6/default/ringbuffer.h
index 8571a9f..c6a1e4c 100644
--- a/wifi/1.6/default/ringbuffer.h
+++ b/wifi/1.6/default/ringbuffer.h
@@ -31,11 +31,19 @@
  */
 class Ringbuffer {
   public:
+    // Error codes for the append ring buffer operation
+    enum AppendStatus {
+        SUCCESS,
+        FAIL_GENERIC,
+        FAIL_IP_BUFFER_ZERO,
+        FAIL_IP_BUFFER_EXCEEDED_MAXSIZE,
+        FAIL_RING_BUFFER_CORRUPTED
+    };
     explicit Ringbuffer(size_t maxSize);
 
     // Appends the data buffer and deletes from the front until buffer is
     // within |maxSize_|.
-    void append(const std::vector<uint8_t>& input);
+    enum AppendStatus append(const std::vector<uint8_t>& input);
     const std::list<std::vector<uint8_t>>& getData() const;
     void clear();
 
diff --git a/wifi/1.6/default/wifi_chip.cpp b/wifi/1.6/default/wifi_chip.cpp
index f062409..c7c00b1 100644
--- a/wifi/1.6/default/wifi_chip.cpp
+++ b/wifi/1.6/default/wifi_chip.cpp
@@ -1613,6 +1613,7 @@
                     return;
                 }
                 WifiDebugRingBufferStatus hidl_status;
+                Ringbuffer::AppendStatus appendstatus;
                 if (!hidl_struct_util::convertLegacyDebugRingBufferStatusToHidl(status,
                                                                                 &hidl_status)) {
                     LOG(ERROR) << "Error converting ring buffer status";
@@ -1623,13 +1624,19 @@
                     const auto& target = shared_ptr_this->ringbuffer_map_.find(name);
                     if (target != shared_ptr_this->ringbuffer_map_.end()) {
                         Ringbuffer& cur_buffer = target->second;
-                        cur_buffer.append(data);
+                        appendstatus = cur_buffer.append(data);
                     } else {
                         LOG(ERROR) << "Ringname " << name << " not found";
                         return;
                     }
                     // unique_lock unlocked here
                 }
+                if (appendstatus == Ringbuffer::AppendStatus::FAIL_RING_BUFFER_CORRUPTED) {
+                    LOG(ERROR) << "Ringname " << name << " is corrupted. Clear the ring buffer";
+                    shared_ptr_this->writeRingbufferFilesInternal();
+                    return;
+                }
+
             };
     legacy_hal::wifi_error legacy_status = legacy_hal_.lock()->registerRingBufferCallbackHandler(
             getFirstActiveWlanIfaceName(), on_ring_buffer_data_callback);
@@ -1971,6 +1978,11 @@
             }
             unique_fd file_auto_closer(dump_fd);
             for (const auto& cur_block : cur_buffer.getData()) {
+                if (cur_block.size() <= 0 || cur_block.size() > kMaxBufferSizeBytes) {
+                    PLOG(ERROR) << "Ring buffer: " << item.first
+                                << " is corrupted. Invalid block size: " << cur_block.size();
+                    break;
+                }
                 if (write(dump_fd, cur_block.data(), sizeof(cur_block[0]) * cur_block.size()) ==
                     -1) {
                     PLOG(ERROR) << "Error writing to file";