Merge "Revert submission"
diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp
index 21dab00..c6c9464 100644
--- a/audio/core/all-versions/default/Device.cpp
+++ b/audio/core/all-versions/default/Device.cpp
@@ -84,26 +84,29 @@
         ALOGW("Can not set a master volume (%f) outside [0,1]", volume);
         return Result::INVALID_ARGUMENTS;
     }
-    return analyzeStatus("set_master_volume", mDevice->set_master_volume(mDevice, volume));
+    return analyzeStatus("set_master_volume", mDevice->set_master_volume(mDevice, volume),
+                         {ENOSYS} /*ignore*/);
 }
 
 Return<void> Device::getMasterVolume(getMasterVolume_cb _hidl_cb) {
     Result retval(Result::NOT_SUPPORTED);
     float volume = 0;
     if (mDevice->get_master_volume != NULL) {
-        retval = analyzeStatus("get_master_volume", mDevice->get_master_volume(mDevice, &volume));
+        retval = analyzeStatus("get_master_volume", mDevice->get_master_volume(mDevice, &volume),
+                               {ENOSYS} /*ignore*/);
     }
     _hidl_cb(retval, volume);
     return Void();
 }
 
 Return<Result> Device::setMicMute(bool mute) {
-    return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute));
+    return analyzeStatus("set_mic_mute", mDevice->set_mic_mute(mDevice, mute), {ENOSYS} /*ignore*/);
 }
 
 Return<void> Device::getMicMute(getMicMute_cb _hidl_cb) {
     bool mute = false;
-    Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute));
+    Result retval = analyzeStatus("get_mic_mute", mDevice->get_mic_mute(mDevice, &mute),
+                                  {ENOSYS} /*ignore*/);
     _hidl_cb(retval, mute);
     return Void();
 }
@@ -111,7 +114,8 @@
 Return<Result> Device::setMasterMute(bool mute) {
     Result retval(Result::NOT_SUPPORTED);
     if (mDevice->set_master_mute != NULL) {
-        retval = analyzeStatus("set_master_mute", mDevice->set_master_mute(mDevice, mute));
+        retval = analyzeStatus("set_master_mute", mDevice->set_master_mute(mDevice, mute),
+                               {ENOSYS} /*ignore*/);
     }
     return retval;
 }
@@ -120,7 +124,8 @@
     Result retval(Result::NOT_SUPPORTED);
     bool mute = false;
     if (mDevice->get_master_mute != NULL) {
-        retval = analyzeStatus("get_master_mute", mDevice->get_master_mute(mDevice, &mute));
+        retval = analyzeStatus("get_master_mute", mDevice->get_master_mute(mDevice, &mute),
+                               {ENOSYS} /*ignore*/);
     }
     _hidl_cb(retval, mute);
     return Void();
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 396d354..1a2a764 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -318,7 +318,8 @@
         ALOGW("Can not set a stream output volume {%f, %f} outside [0,1]", left, right);
         return Result::INVALID_ARGUMENTS;
     }
-    return Stream::analyzeStatus("set_volume", mStream->set_volume(mStream, left, right));
+    return Stream::analyzeStatus("set_volume", mStream->set_volume(mStream, left, right),
+                                 {ENOSYS} /*ignore*/);
 }
 
 Return<void> StreamOut::prepareForWriting(uint32_t frameSize, uint32_t framesCount,
@@ -403,7 +404,8 @@
 Return<void> StreamOut::getRenderPosition(getRenderPosition_cb _hidl_cb) {
     uint32_t halDspFrames;
     Result retval = Stream::analyzeStatus("get_render_position",
-                                          mStream->get_render_position(mStream, &halDspFrames));
+                                          mStream->get_render_position(mStream, &halDspFrames),
+                                          {ENOSYS} /*ignore*/);
     _hidl_cb(retval, halDspFrames);
     return Void();
 }
@@ -413,7 +415,8 @@
     int64_t timestampUs = 0;
     if (mStream->get_next_write_timestamp != NULL) {
         retval = Stream::analyzeStatus("get_next_write_timestamp",
-                                       mStream->get_next_write_timestamp(mStream, &timestampUs));
+                                       mStream->get_next_write_timestamp(mStream, &timestampUs),
+                                       {ENOSYS} /*ignore*/);
     }
     _hidl_cb(retval, timestampUs);
     return Void();
@@ -427,7 +430,7 @@
     if (result == 0) {
         mCallback = callback;
     }
-    return Stream::analyzeStatus("set_callback", result);
+    return Stream::analyzeStatus("set_callback", result, {ENOSYS} /*ignore*/);
 }
 
 Return<Result> StreamOut::clearCallback() {
@@ -473,13 +476,15 @@
 }
 
 Return<Result> StreamOut::pause() {
-    return mStream->pause != NULL ? Stream::analyzeStatus("pause", mStream->pause(mStream))
-                                  : Result::NOT_SUPPORTED;
+    return mStream->pause != NULL
+                   ? Stream::analyzeStatus("pause", mStream->pause(mStream), {ENOSYS} /*ignore*/)
+                   : Result::NOT_SUPPORTED;
 }
 
 Return<Result> StreamOut::resume() {
-    return mStream->resume != NULL ? Stream::analyzeStatus("resume", mStream->resume(mStream))
-                                   : Result::NOT_SUPPORTED;
+    return mStream->resume != NULL
+                   ? Stream::analyzeStatus("resume", mStream->resume(mStream), {ENOSYS} /*ignore*/)
+                   : Result::NOT_SUPPORTED;
 }
 
 Return<bool> StreamOut::supportsDrain() {
@@ -488,14 +493,17 @@
 
 Return<Result> StreamOut::drain(AudioDrain type) {
     return mStream->drain != NULL
-               ? Stream::analyzeStatus(
-                     "drain", mStream->drain(mStream, static_cast<audio_drain_type_t>(type)))
-               : Result::NOT_SUPPORTED;
+                   ? Stream::analyzeStatus(
+                             "drain",
+                             mStream->drain(mStream, static_cast<audio_drain_type_t>(type)),
+                             {ENOSYS} /*ignore*/)
+                   : Result::NOT_SUPPORTED;
 }
 
 Return<Result> StreamOut::flush() {
-    return mStream->flush != NULL ? Stream::analyzeStatus("flush", mStream->flush(mStream))
-                                  : Result::NOT_SUPPORTED;
+    return mStream->flush != NULL
+                   ? Stream::analyzeStatus("flush", mStream->flush(mStream), {ENOSYS} /*ignore*/)
+                   : Result::NOT_SUPPORTED;
 }
 
 // static
@@ -505,7 +513,7 @@
     // to return it sometimes. EAGAIN may be returned by A2DP audio HAL
     // implementation. ENODATA can also be reported while the writer is
     // continuously querying it, but the stream has been stopped.
-    static const std::vector<int> ignoredErrors{EINVAL, EAGAIN, ENODATA};
+    static const std::vector<int> ignoredErrors{EINVAL, EAGAIN, ENODATA, ENOSYS};
     Result retval(Result::NOT_SUPPORTED);
     if (stream->get_presentation_position == NULL) return retval;
     struct timespec halTimeStamp;
diff --git a/contexthub/1.0/vts/functional/Android.bp b/contexthub/1.0/vts/functional/Android.bp
index aef0340..9e99c33 100644
--- a/contexthub/1.0/vts/functional/Android.bp
+++ b/contexthub/1.0/vts/functional/Android.bp
@@ -19,6 +19,8 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalContexthubV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.contexthub@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: [
+        "general-tests",
+        "vts-core",
+    ],
 }
-
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index 045cc4e..161b2f0 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -4,5 +4,5 @@
 stange@google.com
 
 #VTS team
-yim@google.com
+dshi@google.com
 trong@google.com
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index 629477a..a1d173b 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -16,13 +16,14 @@
 
 #define LOG_TAG "contexthub_hidl_hal_test"
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/contexthub/1.0/IContexthub.h>
 #include <android/hardware/contexthub/1.0/IContexthubCallback.h>
 #include <android/hardware/contexthub/1.0/types.h>
 #include <android/log.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 #include <cinttypes>
@@ -76,69 +77,44 @@
 }
 
 // Gets a list of valid hub IDs in the system
-std::vector<uint32_t> getHubIds() {
-  static std::vector<uint32_t> hubIds;
+std::vector<std::string> getHubIds(const std::string& service_name) {
+    std::vector<std::string> hubIds;
 
-  if (hubIds.size() == 0) {
-    sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>();
+    sp<IContexthub> hubApi = IContexthub::getService(service_name);
 
     if (hubApi != nullptr) {
-      for (const ContextHub& hub : getHubsSync(hubApi)) {
-        hubIds.push_back(hub.hubId);
-      }
+        for (const ContextHub& hub : getHubsSync(hubApi)) {
+            hubIds.push_back(std::to_string(hub.hubId));
+        }
     }
-  }
 
-  ALOGD("Running tests against all %zu reported hubs", hubIds.size());
-  return hubIds;
+    ALOGD("Running tests against all %zu reported hubs for service %s", hubIds.size(),
+          service_name.c_str());
+    return hubIds;
 }
 
-// Test environment for Contexthub HIDL HAL.
-class ContexthubHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static ContexthubHidlEnvironment* Instance() {
-    static ContexthubHidlEnvironment* instance = new ContexthubHidlEnvironment;
-    return instance;
-  }
+// Test fixture parameterized by hub ID, initializes the HAL and makes the context hub API handle
+// available.
+class ContexthubHidlTest : public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
+  public:
+    virtual void SetUp() override {
+        hubApi = IContexthub::getService(std::get<0>(GetParam()));
+        ASSERT_NE(hubApi, nullptr);
 
-  virtual void registerTestServices() override { registerTestService<IContexthub>(); }
- private:
-  ContexthubHidlEnvironment() {}
-};
+        // getHubs() must be called at least once for proper initialization of the
+        // HAL implementation
+        getHubsSync(hubApi);
+    }
 
-// Base test fixture that initializes the HAL and makes the context hub API
-// handle available
-class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
- public:
-  virtual void SetUp() override {
-    hubApi = ::testing::VtsHalHidlTargetTestBase::getService<IContexthub>(
-        ContexthubHidlEnvironment::Instance()->getServiceName<IContexthub>());
-    ASSERT_NE(hubApi, nullptr);
+    uint32_t getHubId() { return std::stoi(std::get<1>(GetParam())); }
 
-    // getHubs() must be called at least once for proper initialization of the
-    // HAL implementation
-    getHubsSync(hubApi);
-  }
+    Result registerCallback(sp<IContexthubCallback> cb) {
+        Result result = hubApi->registerCallback(getHubId(), cb);
+        ALOGD("Registered callback, result %" PRIu32, result);
+        return result;
+    }
 
-  virtual void TearDown() override {}
-
-  sp<IContexthub> hubApi;
-};
-
-// Test fixture parameterized by hub ID
-class ContexthubHidlTest : public ContexthubHidlTestBase,
-                           public ::testing::WithParamInterface<uint32_t> {
- public:
-  uint32_t getHubId() {
-    return GetParam();
-  }
-
-  Result registerCallback(sp<IContexthubCallback> cb) {
-    Result result = hubApi->registerCallback(getHubId(), cb);
-    ALOGD("Registered callback, result %" PRIu32, result);
-    return result;
-  }
+    sp<IContexthub> hubApi;
 };
 
 // Base callback implementation that just logs all callbacks by default
@@ -202,24 +178,24 @@
 }
 
 // Ensures that the metadata reported in getHubs() is sane
-TEST_F(ContexthubHidlTestBase, TestGetHubs) {
-  hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
-  ALOGD("System reports %zu hubs", hubs.size());
+TEST_P(ContexthubHidlTest, TestGetHubs) {
+    hidl_vec<ContextHub> hubs = getHubsSync(hubApi);
+    ALOGD("System reports %zu hubs", hubs.size());
 
-  for (const ContextHub& hub : hubs) {
-    ALOGD("Checking hub ID %" PRIu32, hub.hubId);
+    for (const ContextHub& hub : hubs) {
+        ALOGD("Checking hub ID %" PRIu32, hub.hubId);
 
-    EXPECT_FALSE(hub.name.empty());
-    EXPECT_FALSE(hub.vendor.empty());
-    EXPECT_FALSE(hub.toolchain.empty());
-    EXPECT_GT(hub.peakMips, 0);
-    EXPECT_GE(hub.stoppedPowerDrawMw, 0);
-    EXPECT_GE(hub.sleepPowerDrawMw, 0);
-    EXPECT_GT(hub.peakPowerDrawMw, 0);
+        EXPECT_FALSE(hub.name.empty());
+        EXPECT_FALSE(hub.vendor.empty());
+        EXPECT_FALSE(hub.toolchain.empty());
+        EXPECT_GT(hub.peakMips, 0);
+        EXPECT_GE(hub.stoppedPowerDrawMw, 0);
+        EXPECT_GE(hub.sleepPowerDrawMw, 0);
+        EXPECT_GT(hub.peakPowerDrawMw, 0);
 
-    // Minimum 128 byte MTU as required by CHRE API v1.0
-    EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
-  }
+        // Minimum 128 byte MTU as required by CHRE API v1.0
+        EXPECT_GE(hub.maxSupportedMsgLen, UINT32_C(128));
+    }
 }
 
 TEST_P(ContexthubHidlTest, TestRegisterCallback) {
@@ -388,20 +364,28 @@
                                       cb->promise.get_future()));
 }
 
-// Parameterize all SingleContexthubTest tests against each valid hub ID
-INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubHidlTest,
-                        ::testing::ValuesIn(getHubIds()));
-INSTANTIATE_TEST_CASE_P(HubIdSpecificTests, ContexthubTxnTest,
-                        ::testing::ValuesIn(getHubIds()));
+// Return the test parameters of a vecter of tuples for all IContexthub services and each of its hub
+// id: <service name of IContexthub, hub id of the IContexthub service>
+static std::vector<std::tuple<std::string, std::string>> get_parameters() {
+    std::vector<std::tuple<std::string, std::string>> parameters;
+    std::vector<std::string> service_names =
+            android::hardware::getAllHalInstanceNames(IContexthub::descriptor);
+    for (const std::string& service_name : service_names) {
+        std::vector<std::string> ids = getHubIds(service_name);
+        for (const std::string& id : ids) {
+            parameters.push_back(std::make_tuple(service_name, id));
+        }
+    }
 
-} // anonymous namespace
-
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(ContexthubHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  ContexthubHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI ("Test result = %d", status);
-  return status;
+    return parameters;
 }
 
+static std::vector<std::tuple<std::string, std::string>> kTestParameters = get_parameters();
+
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubHidlTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+INSTANTIATE_TEST_SUITE_P(HubIdSpecificTests, ContexthubTxnTest, testing::ValuesIn(kTestParameters),
+                         android::hardware::PrintInstanceTupleNameToString<>);
+
+}  // anonymous namespace
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index f3b376e..e6e3c85 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -177,6 +177,42 @@
     return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
 }
 
+GnssConstellationType GnssHalTest::startLocationAndGetNonGpsConstellation() {
+    const int kLocationsToAwait = 3;
+
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+          (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
+
+    // Find first non-GPS constellation
+    GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
+    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+        for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
+            const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
+            if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+                (gnss_sv.constellation != GnssConstellationType::UNKNOWN) &&
+                (gnss_sv.constellation != GnssConstellationType::GPS)) {
+                // found a non-GPS constellation
+                constellation_to_blacklist = gnss_sv.constellation;
+                break;
+            }
+        }
+        if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
+            break;
+        }
+    }
+
+    if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
+        ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+        // Proceed functionally to return something.
+        constellation_to_blacklist = GnssConstellationType::GLONASS;
+    }
+    return constellation_to_blacklist;
+}
+
 void GnssHalTest::notify() {
     std::unique_lock<std::mutex> lock(mtx_);
     notify_count_++;
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index 84a9f84..09ebadc 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -31,9 +31,10 @@
 
 using android::hardware::gnss::V1_0::GnssLocation;
 
+using android::hardware::gnss::V1_0::GnssConstellationType;
+using android::hardware::gnss::V1_0::GnssLocationFlags;
 using android::hardware::gnss::V1_1::IGnss;
 using android::hardware::gnss::V1_1::IGnssCallback;
-using android::hardware::gnss::V1_0::GnssLocationFlags;
 
 using android::sp;
 
@@ -151,6 +152,16 @@
      */
     bool IsGnssHalVersion_1_1() const;
 
+    /*
+     * startLocationAndGetNonGpsConstellation:
+     * 1. Start location
+     * 2. Find and return first non-GPS constellation
+     *
+     * Note that location is not stopped in this method. The client should call
+     * StopAndClearLocations() after the call.
+     */
+    GnssConstellationType startLocationAndGetNonGpsConstellation();
+
     sp<IGnss> gnss_hal_;         // GNSS HAL to call into
     sp<IGnssCallback> gnss_cb_;  // Primary callback interface
 
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index ee236ba..503e419 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -330,7 +330,7 @@
 }
 
 /*
- * BlacklistConstellation:
+ * BlacklistConstellationWithLocationOff:
  *
  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
  * GnssStatus for any non-GPS constellations.
@@ -339,44 +339,19 @@
  * GnssStatus does not use any constellation but GPS.
  * 4a & b) Clean up by turning off location, and send in empty blacklist.
  */
-TEST_F(GnssHalTest, BlacklistConstellation) {
+TEST_F(GnssHalTest, BlacklistConstellationWithLocationOff) {
     if (!IsGnssHalVersion_1_1()) {
         ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
         return;
     }
 
     const int kLocationsToAwait = 3;
-
-    StartAndCheckLocations(kLocationsToAwait);
-
-    // Tolerate 1 less sv status to handle edge cases in reporting.
-    EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
-    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
-          (int)list_gnss_sv_status_.size(), kLocationsToAwait, location_called_count_);
-
     // Find first non-GPS constellation to blacklist
-    GnssConstellationType constellation_to_blacklist = GnssConstellationType::UNKNOWN;
-    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
-        for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
-            const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
-            if ((gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
-                (gnss_sv.constellation != GnssConstellationType::UNKNOWN) &&
-                (gnss_sv.constellation != GnssConstellationType::GPS)) {
-                // found a non-GPS constellation
-                constellation_to_blacklist = gnss_sv.constellation;
-                break;
-            }
-        }
-        if (constellation_to_blacklist != GnssConstellationType::UNKNOWN) {
-            break;
-        }
-    }
+    GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
 
-    if (constellation_to_blacklist == GnssConstellationType::UNKNOWN) {
-        ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
-        // Proceed functionally to blacklist something.
-        constellation_to_blacklist = GnssConstellationType::GLONASS;
-    }
+    // Turns off location
+    StopAndClearLocations();
+
     IGnssConfiguration::BlacklistedSource source_to_blacklist;
     source_to_blacklist.constellation = constellation_to_blacklist;
     source_to_blacklist.svid = 0;  // documented wildcard for all satellites in this constellation
@@ -421,6 +396,71 @@
 }
 
 /*
+ * BlacklistConstellationWithLocationOn:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Blacklist first non-GPS constellations, and turns off location.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blacklist.
+ */
+TEST_F(GnssHalTest, BlacklistConstellationWithLocationOn) {
+    if (!IsGnssHalVersion_1_1()) {
+        ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
+        return;
+    }
+
+    const int kLocationsToAwait = 3;
+    GnssConstellationType constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
+
+    IGnssConfiguration::BlacklistedSource source_to_blacklist;
+    source_to_blacklist.constellation = constellation_to_blacklist;
+    source_to_blacklist.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
+    ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+    sp<IGnssConfiguration> gnss_configuration_hal = gnss_configuration_hal_return;
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<IGnssConfiguration::BlacklistedSource> sources;
+    sources.resize(1);
+    sources[0] = source_to_blacklist;
+
+    auto result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    // Turns off location
+    StopAndClearLocations();
+
+    // retry and ensure constellation not used
+    list_gnss_sv_status_.clear();
+
+    location_called_count_ = 0;
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    EXPECT_GE((int)list_gnss_sv_status_.size() + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+          kLocationsToAwait);
+    for (const auto& gnss_sv_status : list_gnss_sv_status_) {
+        for (uint32_t iSv = 0; iSv < gnss_sv_status.numSvs; iSv++) {
+            const auto& gnss_sv = gnss_sv_status.gnssSvList[iSv];
+            EXPECT_FALSE((gnss_sv.constellation == source_to_blacklist.constellation) &&
+                         (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clean up
+    StopAndClearLocations();
+    sources.resize(0);
+    result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+/*
  * InjectBestLocation
  *
  * Ensure successfully injecting a location.
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index ebf5faa..f553664 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -48,6 +48,10 @@
      * Whether compose is supported.
      */
     const int CAP_COMPOSE_EFFECTS = 1 << 5;
+    /**
+     * Whether alwaysOnEnable/alwaysOnDisable is supported.
+     */
+    const int CAP_ALWAYS_ON_CONTROL = 1 << 6;
 
     /**
      * Determine capabilities of the vibrator HAL (CAP_* mask)
@@ -165,4 +169,31 @@
      */
     void compose(in CompositeEffect[] composite, in IVibratorCallback callback);
 
+    /**
+     * List of supported always-on effects.
+     *
+     * Return the effects which are supported by the alwaysOnEnable (an effect
+     * is expected to be supported at every strength level.
+     */
+    Effect[] getSupportedAlwaysOnEffects();
+
+    /**
+     * Enable an always-on haptic source, assigning a specific effect. An
+     * always-on haptic source is a source that can be triggered externally
+     * once enabled and assigned an effect to play. This may not be supported
+     * and this support is reflected in getCapabilities (CAP_ALWAYS_ON_CONTROL).
+     *
+     * @param id The device-specific always-on source ID to enable.
+     * @param effect The type of haptic event to trigger.
+     * @param strength The intensity of haptic event to trigger.
+     */
+    void alwaysOnEnable(in int id, in Effect effect, in EffectStrength strength);
+
+    /**
+     * Disable an always-on haptic source. This may not be supported and this
+     * support is reflected in getCapabilities (CAP_ALWAYS_ON_CONTROL).
+     *
+     * @param id The device-specific always-on source ID to disable.
+     */
+    void alwaysOnDisable(in int id);
 }
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index befdeab..cedd9cb 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -31,7 +31,8 @@
     LOG(INFO) << "Vibrator reporting capabilities";
     *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
                     IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL |
-                    IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS;
+                    IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL | IVibrator::CAP_COMPOSE_EFFECTS |
+                    IVibrator::CAP_ALWAYS_ON_CONTROL;
     return ndk::ScopedAStatus::ok();
 }
 
@@ -151,6 +152,28 @@
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) {
+    return getSupportedEffects(_aidl_return);
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) {
+    std::vector<Effect> effects;
+    getSupportedAlwaysOnEffects(&effects);
+
+    if (std::find(effects.begin(), effects.end(), effect) == effects.end()) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    } else {
+        LOG(INFO) << "Enabling always-on ID " << id << " with " << toString(effect) << "/"
+                  << toString(strength);
+        return ndk::ScopedAStatus::ok();
+    }
+}
+
+ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id) {
+    LOG(INFO) << "Disabling always-on ID " << id;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace vibrator
 }  // namespace hardware
 }  // namespace android
diff --git a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
index 817ec80..0eb957d 100644
--- a/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
+++ b/vibrator/aidl/default/include/vibrator-impl/Vibrator.h
@@ -38,6 +38,9 @@
     ndk::ScopedAStatus getCompositionSizeMax(int32_t* maxSize);
     ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
                                const std::shared_ptr<IVibratorCallback>& callback) override;
+    ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
+    ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override;
+    ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
 };
 
 }  // namespace vibrator
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 7ed04f6..0e2b3e1 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -362,6 +362,32 @@
     }
 }
 
+TEST_P(VibratorAidl, AlwaysOn) {
+    if (capabilities & IVibrator::CAP_ALWAYS_ON_CONTROL) {
+        std::vector<Effect> supported;
+        ASSERT_TRUE(vibrator->getSupportedAlwaysOnEffects(&supported).isOk());
+
+        for (Effect effect : kEffects) {
+            bool isEffectSupported =
+                    std::find(supported.begin(), supported.end(), effect) != supported.end();
+
+            for (EffectStrength strength : kEffectStrengths) {
+                Status status = vibrator->alwaysOnEnable(0, effect, strength);
+
+                if (isEffectSupported) {
+                    EXPECT_EQ(Status::EX_NONE, status.exceptionCode())
+                            << toString(effect) << " " << toString(strength);
+                } else {
+                    EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode())
+                            << toString(effect) << " " << toString(strength);
+                }
+            }
+        }
+
+        EXPECT_EQ(Status::EX_NONE, vibrator->alwaysOnDisable(0).exceptionCode());
+    }
+}
+
 INSTANTIATE_TEST_SUITE_P(Vibrator, VibratorAidl,
                          testing::ValuesIn(android::getAidlHalInstanceNames(IVibrator::descriptor)),
                          android::PrintInstanceNameToString);