GNSS Satellite Use Blacklist HAL

Adding .hal change IGnssConfiguration to enable
external (system) control of satellite usage.
Adding VTS tests of the new .hal (ready for
partners to integrate against.)

Bug: 38269641
Test: .hal & vts builds,
 vts test runs and fails fast (no 1.1 HAL on
 initial test device),
 vts test logs run as expected on a 1.0 device (with tests to make
 this run),
 on-device sanity check of GPS works,
 builds with JNI test code (to be submitted separately)
Change-Id: I72b5045eb0eea30d51ed5098248482cbbfc5aaff
diff --git a/gnss/1.1/Android.bp b/gnss/1.1/Android.bp
index 6909807..417b4f5 100644
--- a/gnss/1.1/Android.bp
+++ b/gnss/1.1/Android.bp
@@ -9,6 +9,7 @@
     srcs: [
         "IGnss.hal",
         "IGnssCallback.hal",
+        "IGnssConfiguration.hal",
         "IGnssMeasurement.hal",
     ],
     interfaces: [
diff --git a/gnss/1.1/IGnss.hal b/gnss/1.1/IGnss.hal
index d5e0c3e..0c3d876 100644
--- a/gnss/1.1/IGnss.hal
+++ b/gnss/1.1/IGnss.hal
@@ -18,8 +18,9 @@
 
 import @1.0::IGnss;
 
-import IGnssMeasurement;
 import IGnssCallback;
+import IGnssConfiguration;
+import IGnssMeasurement;
 
 /** Represents the standard GNSS (Global Navigation Satellite System) interface. */
 interface IGnss extends @1.0::IGnss {
@@ -65,6 +66,13 @@
              generates (bool success);
 
    /**
+    * This method returns the IGnssConfiguration interface.
+    *
+    * @return gnssConfigurationIface Handle to the IGnssConfiguration interface.
+    */
+    getExtensionGnssConfiguration_1_1() generates (IGnssConfiguration gnssConfigurationIface);
+
+   /**
     * This method returns the IGnssMeasurement interface.
     *
     * @return gnssMeasurementIface Handle to the IGnssMeasurement interface.
diff --git a/gnss/1.1/IGnssConfiguration.hal b/gnss/1.1/IGnssConfiguration.hal
new file mode 100644
index 0000000..105fda3
--- /dev/null
+++ b/gnss/1.1/IGnssConfiguration.hal
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.gnss@1.1;
+
+import @1.0::IGnssConfiguration;
+import @1.0::GnssConstellationType;
+
+/**
+ * Extended interface for GNSS Configuration support.
+ */
+interface IGnssConfiguration extends @1.0::IGnssConfiguration {
+    struct BlacklistedSource {
+        /**
+         * Defines the constellation of the given satellite(s).
+         */
+        GnssConstellationType constellation;
+
+        /**
+         * Satellite (space vehicle) ID number, as defined in GnssSvInfo::svid
+         *
+         * Or 0 to blacklist all svid's for the specified constellation
+         */
+        int16_t svid;
+    };
+
+    /**
+     * Injects a vector of BlacklistedSource(s) which the HAL must not use to calculate the
+     * GNSS location output.
+     *
+     * The superset of all satellite sources provided, including wildcards, in the latest call
+     * to this method, is the set of satellites sources that must not be used in calculating
+     * location.
+     *
+     * All measurements from the specified satellites, across frequency bands, are blacklisted
+     * together.
+     *
+     * If this method is never called after the IGnssConfiguration.hal connection is made on boot,
+     * or is called with an empty vector, then no satellites are to be blacklisted as a result of
+     * this API.
+     *
+     * This blacklist must be considered as an additional source of which satellites
+     * should not be trusted for location on top of existing sources of similar information
+     * such as satellite broadcast health being unhealthy and measurement outlier removal.
+     *
+     * @param blacklist The BlacklistedSource(s) of satellites the HAL must not use.
+     *
+     * @return success Whether the HAL accepts and abides by the provided blacklist.
+     */
+    setBlacklist(vec<BlacklistedSource> blacklist) generates (bool success);
+};
\ No newline at end of file
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 2f4dd93..7e43b92 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "VtsHalGnssV1_1TargetTest"
-#include <log/log.h>
-
 #include <gnss_hal_test.h>
 
 #include <chrono>
@@ -31,6 +28,7 @@
 
 void GnssHalTest::SetUp() {
     gnss_hal_ = ::testing::VtsHalHidlTargetTestBase::getService<IGnss>();
+    list_gnss_sv_status_.clear();
     ASSERT_NE(gnss_hal_, nullptr);
 }
 
@@ -43,18 +41,156 @@
     }
 }
 
+void GnssHalTest::StopAndClearLocations() {
+    auto result = gnss_hal_->stop();
+
+    EXPECT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    /*
+     * Clear notify/waiting counter, allowing up till the timeout after
+     * the last reply for final startup messages to arrive (esp. system
+     * info.)
+     */
+    while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
+    }
+}
+
+void GnssHalTest::SetPositionMode(const int min_interval_msec, const bool low_power_mode) {
+    const int kPreferredAccuracy = 0;  // Ideally perfect (matches GnssLocationProvider)
+    const int kPreferredTimeMsec = 0;  // Ideally immediate
+
+    auto result = gnss_hal_->setPositionMode_1_1(
+        IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
+        min_interval_msec, kPreferredAccuracy, kPreferredTimeMsec, low_power_mode);
+
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+bool GnssHalTest::StartAndGetSingleLocation() {
+    auto result = gnss_hal_->start();
+
+    EXPECT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    /*
+     * GPS signals initially optional for this test, so don't expect fast fix,
+     * or no timeout, unless signal is present
+     */
+    const int kFirstGnssLocationTimeoutSeconds = 15;
+
+    wait(kFirstGnssLocationTimeoutSeconds);
+    EXPECT_EQ(location_called_count_, 1);
+
+    if (location_called_count_ > 0) {
+        // don't require speed on first fix
+        CheckLocation(last_location_, false);
+        return true;
+    }
+    return false;
+}
+
+void GnssHalTest::CheckLocation(GnssLocation& location, bool check_speed) {
+    bool check_more_accuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
+
+    EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG);
+    EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE);
+    if (check_speed) {
+        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED);
+    }
+    EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY);
+    // New uncertainties available in O must be provided,
+    // at least when paired with modern hardware (2017+)
+    if (check_more_accuracies) {
+        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY);
+        if (check_speed) {
+            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY);
+            if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+                EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY);
+            }
+        }
+    }
+    EXPECT_GE(location.latitudeDegrees, -90.0);
+    EXPECT_LE(location.latitudeDegrees, 90.0);
+    EXPECT_GE(location.longitudeDegrees, -180.0);
+    EXPECT_LE(location.longitudeDegrees, 180.0);
+    EXPECT_GE(location.altitudeMeters, -1000.0);
+    EXPECT_LE(location.altitudeMeters, 30000.0);
+    if (check_speed) {
+        EXPECT_GE(location.speedMetersPerSec, 0.0);
+        EXPECT_LE(location.speedMetersPerSec, 5.0);  // VTS tests are stationary.
+
+        // Non-zero speeds must be reported with an associated bearing
+        if (location.speedMetersPerSec > 0.0) {
+            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING);
+        }
+    }
+
+    /*
+     * Tolerating some especially high values for accuracy estimate, in case of
+     * first fix with especially poor geometry (happens occasionally)
+     */
+    EXPECT_GT(location.horizontalAccuracyMeters, 0.0);
+    EXPECT_LE(location.horizontalAccuracyMeters, 250.0);
+
+    /*
+     * Some devices may define bearing as -180 to +180, others as 0 to 360.
+     * Both are okay & understandable.
+     */
+    if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+        EXPECT_GE(location.bearingDegrees, -180.0);
+        EXPECT_LE(location.bearingDegrees, 360.0);
+    }
+    if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+        EXPECT_GT(location.verticalAccuracyMeters, 0.0);
+        EXPECT_LE(location.verticalAccuracyMeters, 500.0);
+    }
+    if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+        EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0);
+        EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0);
+    }
+    if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+        EXPECT_GT(location.bearingAccuracyDegrees, 0.0);
+        EXPECT_LE(location.bearingAccuracyDegrees, 360.0);
+    }
+
+    // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+)
+    EXPECT_GT(location.timestamp, 1.48e12);
+}
+
+void GnssHalTest::StartAndCheckLocations(int count) {
+    const int kMinIntervalMsec = 500;
+    const int kLocationTimeoutSubsequentSec = 2;
+    const bool kLowPowerMode = true;
+
+    SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+    EXPECT_TRUE(StartAndGetSingleLocation());
+
+    for (int i = 1; i < count; i++) {
+        EXPECT_EQ(std::cv_status::no_timeout, wait(kLocationTimeoutSubsequentSec));
+        EXPECT_EQ(location_called_count_, i + 1);
+        // Don't cause confusion by checking details if no location yet
+        if (location_called_count_ > 0) {
+            // Should be more than 1 location by now, but if not, still don't check first fix speed
+            CheckLocation(last_location_, location_called_count_ > 1);
+        }
+    }
+}
+
 void GnssHalTest::notify() {
     std::unique_lock<std::mutex> lock(mtx_);
     notify_count_++;
     cv_.notify_one();
 }
 
-std::cv_status GnssHalTest::wait(int timeoutSeconds) {
+std::cv_status GnssHalTest::wait(int timeout_seconds) {
     std::unique_lock<std::mutex> lock(mtx_);
 
     auto status = std::cv_status::no_timeout;
     while (notify_count_ == 0) {
-        status = cv_.wait_for(lock, std::chrono::seconds(timeoutSeconds));
+        status = cv_.wait_for(lock, std::chrono::seconds(timeout_seconds));
         if (status == std::cv_status::timeout) return status;
     }
     notify_count_--;
@@ -93,3 +229,10 @@
     parent_.notify();
     return Void();
 }
+
+Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb(
+    const IGnssCallback::GnssSvStatus& svStatus) {
+    ALOGI("GnssSvStatus received");
+    parent_.list_gnss_sv_status_.emplace_back(svStatus);
+    return Void();
+}
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index bbc8d9f..a06db5d 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -17,11 +17,14 @@
 #ifndef GNSS_HAL_TEST_H_
 #define GNSS_HAL_TEST_H_
 
+#define LOG_TAG "VtsHalGnssV1_1TargetTest"
+
 #include <android/hardware/gnss/1.1/IGnss.h>
 
 #include <VtsHalHidlTargetTestBase.h>
 
 #include <condition_variable>
+#include <list>
 #include <mutex>
 
 using android::hardware::Return;
@@ -32,7 +35,9 @@
 using android::hardware::gnss::V1_1::IGnss;
 using android::hardware::gnss::V1_1::IGnssCallback;
 using android::hardware::gnss::V1_0::GnssLocationFlags;
+
 using android::sp;
+
 #define TIMEOUT_SEC 2  // for basic commands/responses
 
 // The main test class for GNSS HAL.
@@ -48,7 +53,7 @@
     void notify();
 
     /* Test code calls this function to wait for a callback */
-    std::cv_status wait(int timeoutSeconds);
+    std::cv_status wait(int timeout_seconds);
 
     /* Callback class for data & Event. */
     class GnssCallback : public IGnssCallback {
@@ -63,9 +68,6 @@
         Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue /* status */) override {
             return Void();
         }
-        Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& /* svStatus */) override {
-            return Void();
-        }
         Return<void> gnssNmeaCb(int64_t /* timestamp */,
                                 const android::hardware::hidl_string& /* nmea */) override {
             return Void();
@@ -74,10 +76,11 @@
         Return<void> gnssReleaseWakelockCb() override { return Void(); }
         Return<void> gnssRequestTimeCb() override { return Void(); }
         // Actual (test) callback handlers
+        Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
         Return<void> gnssLocationCb(const GnssLocation& location) override;
         Return<void> gnssSetCapabilitesCb(uint32_t capabilities) override;
         Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
-        Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
+        Return<void> gnssSvStatusCb(const IGnssCallback::GnssSvStatus& svStatus) override;
     };
 
     /*
@@ -86,120 +89,35 @@
      *
      * returns  true if a location was successfully generated
      */
-    bool StartAndGetSingleLocation(bool checkAccuracies) {
-        auto result = gnss_hal_->start();
-
-        EXPECT_TRUE(result.isOk());
-        EXPECT_TRUE(result);
-
-        /*
-         * GPS signals initially optional for this test, so don't expect fast fix,
-         * or no timeout, unless signal is present
-         */
-        int firstGnssLocationTimeoutSeconds = 15;
-
-        wait(firstGnssLocationTimeoutSeconds);
-        EXPECT_EQ(location_called_count_, 1);
-
-        if (location_called_count_ > 0) {
-            // don't require speed on first fix
-            CheckLocation(last_location_, checkAccuracies, false);
-            return true;
-        }
-        return false;
-    }
+    bool StartAndGetSingleLocation();
 
     /*
      * CheckLocation:
-     *   Helper function to vet Location fields when calling setPositionMode_1_1()
+     *   Helper function to vet Location fields
      */
-    void CheckLocation(GnssLocation& location, bool checkAccuracies, bool checkSpeed) {
-        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG);
-        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE);
-        if (checkSpeed) {
-            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED);
-        }
-        EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY);
-        // New uncertainties available in O must be provided,
-        // at least when paired with modern hardware (2017+)
-        if (checkAccuracies) {
-            EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY);
-            if (checkSpeed) {
-                EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY);
-                if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
-                    EXPECT_TRUE(location.gnssLocationFlags &
-                                GnssLocationFlags::HAS_BEARING_ACCURACY);
-                }
-            }
-        }
-        EXPECT_GE(location.latitudeDegrees, -90.0);
-        EXPECT_LE(location.latitudeDegrees, 90.0);
-        EXPECT_GE(location.longitudeDegrees, -180.0);
-        EXPECT_LE(location.longitudeDegrees, 180.0);
-        EXPECT_GE(location.altitudeMeters, -1000.0);
-        EXPECT_LE(location.altitudeMeters, 30000.0);
-        if (checkSpeed) {
-            EXPECT_GE(location.speedMetersPerSec, 0.0);
-            EXPECT_LE(location.speedMetersPerSec, 5.0);  // VTS tests are stationary.
+    void CheckLocation(GnssLocation& location, bool check_speed);
 
-            // Non-zero speeds must be reported with an associated bearing
-            if (location.speedMetersPerSec > 0.0) {
-                EXPECT_TRUE(location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING);
-            }
-        }
-
-        /*
-         * Tolerating some especially high values for accuracy estimate, in case of
-         * first fix with especially poor geometry (happens occasionally)
-         */
-        EXPECT_GT(location.horizontalAccuracyMeters, 0.0);
-        EXPECT_LE(location.horizontalAccuracyMeters, 250.0);
-
-        /*
-         * Some devices may define bearing as -180 to +180, others as 0 to 360.
-         * Both are okay & understandable.
-         */
-        if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
-            EXPECT_GE(location.bearingDegrees, -180.0);
-            EXPECT_LE(location.bearingDegrees, 360.0);
-        }
-        if (location.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
-            EXPECT_GT(location.verticalAccuracyMeters, 0.0);
-            EXPECT_LE(location.verticalAccuracyMeters, 500.0);
-        }
-        if (location.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
-            EXPECT_GT(location.speedAccuracyMetersPerSecond, 0.0);
-            EXPECT_LE(location.speedAccuracyMetersPerSecond, 50.0);
-        }
-        if (location.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
-            EXPECT_GT(location.bearingAccuracyDegrees, 0.0);
-            EXPECT_LE(location.bearingAccuracyDegrees, 360.0);
-        }
-
-        // Check timestamp > 1.48e12 (47 years in msec - 1970->2017+)
-        EXPECT_GT(location.timestamp, 1.48e12);
-    }
+    /*
+     * StartAndCheckLocations:
+     *   Helper function to collect, and check a number of
+     *   normal ~1Hz locations.
+     *
+     *   Note this leaves the Location request active, to enable Stop call vs. other call
+     *   reordering tests.
+     */
+    void StartAndCheckLocations(int count);
 
     /*
      * StopAndClearLocations:
-     * Helper function to stop locations
-     *
-     * returns  true if a location was successfully generated
+     * Helper function to stop locations, and clear any remaining notifications
      */
-    void StopAndClearLocations() {
-        auto result = gnss_hal_->stop();
+    void StopAndClearLocations();
 
-        EXPECT_TRUE(result.isOk());
-        EXPECT_TRUE(result);
-
-        /*
-         * Clear notify/waiting counter, allowing up till the timeout after
-         * the last reply for final startup messages to arrive (esp. system
-         * info.)
-         */
-        while (wait(TIMEOUT_SEC) == std::cv_status::no_timeout) {
-        }
-    }
+    /*
+     * SetPositionMode:
+     * Helper function to set positioning mode and verify output
+     */
+    void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
 
     sp<IGnss> gnss_hal_;         // GNSS HAL to call into
     sp<IGnssCallback> gnss_cb_;  // Primary callback interface
@@ -213,6 +131,7 @@
     int capabilities_called_count_;
     int location_called_count_;
     GnssLocation last_location_;
+    list<IGnssCallback::GnssSvStatus> list_gnss_sv_status_;
 
     int name_called_count_;
     android::hardware::hidl_string last_name_;
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 47bad34..c9e36a9 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -18,6 +18,12 @@
 
 #include <VtsHalHidlTargetTestBase.h>
 
+#include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+
+using android::hardware::hidl_vec;
+
+using android::hardware::gnss::V1_0::GnssConstellationType;
+using android::hardware::gnss::V1_1::IGnssConfiguration;
 using android::hardware::gnss::V1_1::IGnssMeasurement;
 
 /*
@@ -70,43 +76,291 @@
 }
 
 /*
- * GetLocation:
+ * GetLocationLowPower:
  * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
  * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
  * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
  * each received location.
  */
 TEST_F(GnssHalTest, GetLocationLowPower) {
-#define MIN_INTERVAL_MSEC 5000
-#define PREFERRED_ACCURACY 0   // Ideally perfect (matches GnssLocationProvider)
-#define PREFERRED_TIME_MSEC 0  // Ideally immediate
+    const int kMinIntervalMsec = 5000;
+    const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) + 1;
+    const int kNoLocationPeriodSec = 2;
+    const int kLocationsToCheck = 5;
+    const bool kLowPowerMode = true;
 
-#define LOCATION_TIMEOUT_SUBSEQUENT_SEC (MIN_INTERVAL_MSEC + 1000) / 1000
-#define NO_LOCATION_PERIOD_SEC 2
-#define LOCATIONS_TO_CHECK 5
-#define LOW_POWER_MODE true
+    SetPositionMode(kMinIntervalMsec, kLowPowerMode);
 
-    bool checkMoreAccuracies = (info_called_count_ > 0 && last_info_.yearOfHw >= 2017);
+    EXPECT_TRUE(StartAndGetSingleLocation());
 
-    auto result = gnss_hal_->setPositionMode_1_1(
-        IGnss::GnssPositionMode::MS_BASED, IGnss::GnssPositionRecurrence::RECURRENCE_PERIODIC,
-        MIN_INTERVAL_MSEC, PREFERRED_ACCURACY, PREFERRED_TIME_MSEC, LOW_POWER_MODE);
-
-    ASSERT_TRUE(result.isOk());
-    EXPECT_TRUE(result);
-
-    EXPECT_TRUE(StartAndGetSingleLocation(checkMoreAccuracies));
-
-    for (int i = 1; i < LOCATIONS_TO_CHECK; i++) {
-        // Verify that MIN_INTERVAL_MSEC is respected by waiting NO_LOCATION_PERIOD_SEC and
+    for (int i = 1; i < kLocationsToCheck; i++) {
+        // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
         // ensure that no location is received yet
-        wait(NO_LOCATION_PERIOD_SEC);
+        wait(kNoLocationPeriodSec);
         EXPECT_EQ(location_called_count_, i);
         EXPECT_EQ(std::cv_status::no_timeout,
-                  wait(LOCATION_TIMEOUT_SUBSEQUENT_SEC - NO_LOCATION_PERIOD_SEC));
+                  wait(kLocationTimeoutSubsequentSec - kNoLocationPeriodSec));
         EXPECT_EQ(location_called_count_, i + 1);
-        CheckLocation(last_location_, checkMoreAccuracies, true);
+        CheckLocation(last_location_, true);
     }
 
     StopAndClearLocations();
+}
+
+/*
+ * FindStrongFrequentSource:
+ *
+ * Search through a GnssSvStatus list for the strongest satellite observed enough times
+ *
+ * returns the strongest source,
+ *         or a source with constellation == UNKNOWN if none are found sufficient times
+ */
+
+IGnssConfiguration::BlacklistedSource FindStrongFrequentSource(
+    const list<IGnssCallback::GnssSvStatus> list_gnss_sv_status, const int min_observations) {
+    struct ComparableBlacklistedSource {
+        IGnssConfiguration::BlacklistedSource id;
+
+        bool operator<(const ComparableBlacklistedSource& compare) const {
+            return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
+                                                    (id.constellation < compare.id.constellation)));
+        }
+    };
+
+    struct SignalCounts {
+        int observations;
+        float max_cn0_dbhz;
+    };
+
+    std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
+
+    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) {
+                ComparableBlacklistedSource source;
+                source.id.svid = gnss_sv.svid;
+                source.id.constellation = gnss_sv.constellation;
+
+                const auto& itSignal = mapSignals.find(source);
+                if (itSignal == mapSignals.end()) {
+                    SignalCounts counts;
+                    counts.observations = 1;
+                    counts.max_cn0_dbhz = gnss_sv.cN0Dbhz;
+                    mapSignals.insert(
+                        std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
+                } else {
+                    itSignal->second.observations++;
+                    if (itSignal->second.max_cn0_dbhz < gnss_sv.cN0Dbhz) {
+                        itSignal->second.max_cn0_dbhz = gnss_sv.cN0Dbhz;
+                    }
+                }
+            }
+        }
+    }
+
+    float max_cn0_dbhz_with_sufficient_count = 0.;
+    int total_observation_count = 0;
+    int blacklisted_source_count_observation = 0;
+
+    ComparableBlacklistedSource source_to_blacklist;  // initializes to zero = UNKNOWN constellation
+    for (auto const& pairSignal : mapSignals) {
+        total_observation_count += pairSignal.second.observations;
+        if ((pairSignal.second.observations >= min_observations) &&
+            (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
+            source_to_blacklist = pairSignal.first;
+            blacklisted_source_count_observation = pairSignal.second.observations;
+            max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
+        }
+    }
+    ALOGD(
+        "Among %d observations, chose svid %d, constellation %d, "
+        "with %d observations at %.1f max CNo",
+        total_observation_count, source_to_blacklist.id.svid,
+        (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
+        max_cn0_dbhz_with_sufficient_count);
+
+    return source_to_blacklist.id;
+}
+
+/*
+ * BlacklistIndividualSatellites:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for common satellites (strongest and one other.)
+ * 2a & b) Turns off location, and blacklists common satellites.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use those satellites.
+ * 4a & b) Turns off location, and send in empty blacklist.
+ * 5) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does re-use at least the previously strongest satellite
+ */
+TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+    const int kLocationsToAwait = 3;
+
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+          kLocationsToAwait);
+
+    /*
+     * Identify strongest SV seen at least kLocationsToAwait -1 times
+     * Why -1?  To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
+     * observability (one epoch RF null)
+     */
+
+    IGnssConfiguration::BlacklistedSource source_to_blacklist =
+        FindStrongFrequentSource(list_gnss_sv_status_, kLocationsToAwait - 1);
+    EXPECT_NE(source_to_blacklist.constellation, GnssConstellationType::UNKNOWN);
+
+    // Stop locations, blacklist the common SV
+    StopAndClearLocations();
+
+    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);
+
+    // retry and ensure satellite not used
+    list_gnss_sv_status_.clear();
+
+    location_called_count_ = 0;
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), 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.svid == source_to_blacklist.svid) &&
+                         (gnss_sv.constellation == source_to_blacklist.constellation) &&
+                         (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clear blacklist and restart - this time updating the blacklist while location is still on
+    sources.resize(0);
+
+    result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    location_called_count_ = 0;
+    StopAndClearLocations();
+    list_gnss_sv_status_.clear();
+
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+          kLocationsToAwait);
+
+    bool strongest_sv_is_reobserved = false;
+    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.svid == source_to_blacklist.svid) &&
+                (gnss_sv.constellation == source_to_blacklist.constellation) &&
+                (gnss_sv.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
+                strongest_sv_is_reobserved = true;
+                break;
+            }
+        }
+        if (strongest_sv_is_reobserved) break;
+    }
+    EXPECT_TRUE(strongest_sv_is_reobserved);
+}
+
+/*
+ * BlacklistConstellation:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Turns off location, and blacklist first non-GPS constellations.
+ * 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, BlacklistConstellation) {
+    const int kLocationsToAwait = 3;
+
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", (int)list_gnss_sv_status_.size(),
+          kLocationsToAwait);
+
+    // 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;
+        }
+    }
+
+    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;
+    }
+    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);
+
+    // retry and ensure constellation not used
+    list_gnss_sv_status_.clear();
+
+    location_called_count_ = 0;
+    StartAndCheckLocations(kLocationsToAwait);
+
+    EXPECT_GE((int)list_gnss_sv_status_.size(), 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);
 }
\ No newline at end of file