Merge "Add IGnssConfiguration AIDL HAL (hardware/interfaces)"
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl
new file mode 100644
index 0000000..89f5d53
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/BlocklistedSource.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+parcelable BlocklistedSource {
+  android.hardware.gnss.GnssConstellationType constellation;
+  int svid;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl
new file mode 100644
index 0000000..30d0227
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/GnssConstellationType.aidl
@@ -0,0 +1,29 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@Backing(type="int") @VintfStability
+enum GnssConstellationType {
+  UNKNOWN = 0,
+  GPS = 1,
+  SBAS = 2,
+  GLONASS = 3,
+  QZSS = 4,
+  BEIDOU = 5,
+  GALILEO = 6,
+  IRNSS = 7,
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
index 33377ca..146577e 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnss.aidl
@@ -18,5 +18,9 @@
 package android.hardware.gnss;
 @VintfStability
 interface IGnss {
+  void setCallback(in android.hardware.gnss.IGnssCallback callback);
+  void close();
   android.hardware.gnss.IGnssPsds getExtensionPsds();
+  android.hardware.gnss.IGnssConfiguration getExtensionGnssConfiguration();
+  const int ERROR_INVALID_ARGUMENT = 1;
 }
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
new file mode 100644
index 0000000..62870d6
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssCallback.aidl
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+interface IGnssCallback {
+  void gnssSetCapabilitiesCb(in int capabilities);
+  const int CAPABILITY_SATELLITE_BLOCKLIST = 1;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
new file mode 100644
index 0000000..5af30cf
--- /dev/null
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssConfiguration.aidl
@@ -0,0 +1,35 @@
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE.                          //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL interface (or parcelable). Do not try to
+// edit this file. It looks like you are doing that because you have modified
+// an AIDL interface in a backward-incompatible way, e.g., deleting a function
+// from an interface or a field from a parcelable and it broke the build. That
+// breakage is intended.
+//
+// You must not make a backward incompatible changes to the AIDL files built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.gnss;
+@VintfStability
+interface IGnssConfiguration {
+  void setSuplVersion(in int version);
+  void setSuplMode(in int mode);
+  void setLppProfile(in int lppProfile);
+  void setGlonassPositioningProtocol(in int protocol);
+  void setEmergencySuplPdn(in boolean enable);
+  void setEsExtensionSec(in int emergencyExtensionSeconds);
+  void setBlocklist(in android.hardware.gnss.BlocklistedSource[] blocklist);
+  const int SUPL_MODE_MSB = 1;
+  const int SUPL_MODE_MSA = 2;
+  const int LPP_PROFILE_USER_PLANE = 1;
+  const int LPP_PROFILE_CONTROL_PLANE = 2;
+  const int GLONASS_POS_PROTOCOL_RRC_CPLANE = 1;
+  const int GLONASS_POS_PROTOCOL_RRLP_UPLANE = 2;
+  const int GLONASS_POS_PROTOCOL_LPP_UPLANE = 4;
+}
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
index 352a694..ddef928 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssPsds.aidl
@@ -18,6 +18,6 @@
 package android.hardware.gnss;
 @VintfStability
 interface IGnssPsds {
-  boolean injectPsdsData(in android.hardware.gnss.PsdsType psdsType, in byte[] psdsData);
-  boolean setCallback(in android.hardware.gnss.IGnssPsdsCallback callback);
+  void injectPsdsData(in android.hardware.gnss.PsdsType psdsType, in byte[] psdsData);
+  void setCallback(in android.hardware.gnss.IGnssPsdsCallback callback);
 }
diff --git a/gnss/aidl/android/hardware/gnss/BlocklistedSource.aidl b/gnss/aidl/android/hardware/gnss/BlocklistedSource.aidl
new file mode 100644
index 0000000..2fde5b2
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/BlocklistedSource.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 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;
+
+import android.hardware.gnss.GnssConstellationType;
+
+/**
+ * Represents a blocklisted source.
+ */
+@VintfStability
+parcelable BlocklistedSource {
+    /**
+     * Defines the constellation of the given satellite(s).
+     */
+    GnssConstellationType constellation;
+
+    /**
+     * Satellite (space vehicle) ID number, as defined in GnssSvInfo::svid, or 0 to blocklist all
+     * svid's for the specified constellation.
+     */
+    int svid;
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/GnssConstellationType.aidl b/gnss/aidl/android/hardware/gnss/GnssConstellationType.aidl
new file mode 100644
index 0000000..af3e089
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/GnssConstellationType.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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;
+
+/**
+ * GNSS constellation type
+ *
+ * This is to specify the navigation satellite system, for example, as listed in Section 3.5 in
+ * RINEX Version 3.04.
+ */
+@VintfStability
+@Backing(type="int")
+enum GnssConstellationType {
+    UNKNOWN = 0,
+    /** Global Positioning System. */
+    GPS     = 1,
+    /** Satellite-Based Augmentation System. */
+    SBAS    = 2,
+    /** Global Navigation Satellite System. */
+    GLONASS = 3,
+    /** Quasi-Zenith Satellite System. */
+    QZSS    = 4,
+    /** BeiDou Navigation Satellite System. */
+    BEIDOU  = 5,
+    /** Galileo Navigation Satellite System. */
+    GALILEO = 6,
+    /** Indian Regional Navigation Satellite System. */
+    IRNSS   = 7,
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnss.aidl b/gnss/aidl/android/hardware/gnss/IGnss.aidl
index 1da254c..24632aa 100644
--- a/gnss/aidl/android/hardware/gnss/IGnss.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnss.aidl
@@ -16,7 +16,9 @@
 
 package android.hardware.gnss;
 
+import android.hardware.gnss.IGnssCallback;
 import android.hardware.gnss.IGnssPsds;
+import android.hardware.gnss.IGnssConfiguration;
 
 /**
  * Represents the standard GNSS (Global Navigation Satellite System) interface.
@@ -25,9 +27,52 @@
 interface IGnss {
 
     /**
+     * All GNSS Binder calls may return a ServiceSpecificException with the following error
+     * codes.
+     */
+    const int ERROR_INVALID_ARGUMENT = 1;
+
+    /**
+     * Opens the interface and provides the callback routines to the implementation of this
+     * interface.
+     *
+     * The framework calls this method to instruct the GPS engine to prepare for serving requests
+     * from the framework. The GNSS HAL implementation must respond to all GNSS requests from the
+     * framework upon successful return from this method until cleanup() method is called to
+     * close this interface.
+     *
+     * @param callback Callback interface for IGnss.
+     */
+    void setCallback(in IGnssCallback callback);
+
+    /**
+     * Closes the interface.
+     *
+     * The close() method is called by the framework to tell the GNSS HAL implementation to
+     * clear the callback and not expect any GNSS requests in the immediate future - e.g. this may
+     * be called when location is disabled by a user setting or low battery conditions. The GNSS HAL
+     * implementation must immediately stop responding to any existing requests until the
+     * setCallback() method is called again and the requests are re-initiated by the framework.
+     *
+     * After this method is called, the GNSS HAL implementation may choose to modify GNSS hardware
+     * states to save power. It is expected that when setCallback() method is called again to
+     * reopen this interface, to serve requests, there may be some minor delays in GNSS response
+     * requests as hardware readiness states are restored, not to exceed those that occur on normal
+     * device boot up.
+     */
+    void close();
+
+    /**
      * This method returns the IGnssPsds interface.
      *
      * @return Handle to the IGnssPsds interface.
      */
     IGnssPsds getExtensionPsds();
+
+    /**
+     * This method returns the IGnssConfiguration interface.
+     *
+     * @return Handle to the IGnssConfiguration interface.
+     */
+    IGnssConfiguration getExtensionGnssConfiguration();
 }
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
new file mode 100644
index 0000000..a46a018
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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;
+
+import android.hardware.gnss.IGnssPsds;
+import android.hardware.gnss.IGnssConfiguration;
+
+/**
+ * This interface is required for the HAL to communicate certain information
+ * like status and location info back to the framework, the framework implements
+ * the interfaces and passes a handle to the HAL.
+ */
+@VintfStability
+interface IGnssCallback {
+
+    /** Capability bit mask indicating GNSS supports blocklisting satellites */
+    const int CAPABILITY_SATELLITE_BLOCKLIST = 1 << 0;
+
+    /**
+     * Callback to inform framework of the GNSS HAL implementation's capabilities.
+     *
+     * @param capabilities Capability parameter is a bit field of the Capability bit masks.
+     */
+    void gnssSetCapabilitiesCb(in int capabilities);
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl b/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl
new file mode 100644
index 0000000..e0ad357
--- /dev/null
+++ b/gnss/aidl/android/hardware/gnss/IGnssConfiguration.aidl
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 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;
+
+import android.hardware.gnss.BlocklistedSource;
+
+/**
+ * Extended interface for GNSS Configuration support.
+ */
+@VintfStability
+interface IGnssConfiguration {
+
+    /** SUPL mode bitmask for Mobile Station Based. */
+    const int SUPL_MODE_MSB = 0x01;
+
+    /** SUPL mode bitmask for Mobile Station Assisted. */
+    const int SUPL_MODE_MSA = 0x02;
+
+    /** LPP profile settings bitmask for enabling LTE Positioning Protocol User Plane. */
+    const int LPP_PROFILE_USER_PLANE = 0x01;
+
+    /** LPP profile settings bitmask for enabling LTE Positioning Protocol Control Plane. */
+    const int LPP_PROFILE_CONTROL_PLANE = 0x02;
+
+    /** A-Glonass positioning protocol bitmask for Radio Resource Control (RRC) Control Plane. */
+    const int GLONASS_POS_PROTOCOL_RRC_CPLANE = 0x01;
+
+    /** A-Glonass positioning protocol bitmask for Radio Resource Location User Plane. */
+    const int GLONASS_POS_PROTOCOL_RRLP_UPLANE = 0x02;
+
+    /** A-Glonass positioning protocol bitmask for LTE Positioning Protocol User Plane. */
+    const int GLONASS_POS_PROTOCOL_LPP_UPLANE = 0x04;
+
+    /**
+     * This method sets the SUPL version requested by Carrier. The GNSS HAL must use this version
+     * of the SUPL protocol if supported.
+     *
+     * @param version SUPL version requested by carrier. This is a bit mask with bits 0:7
+     * representing a service indicator field, bits 8:15 representing the minor version and bits
+     * 16:23 representing the major version.
+     */
+    void setSuplVersion(in int version);
+
+    /**
+     * This method sets the SUPL mode.
+     *
+     * @param mode Bitmask that specifies the SUPL mode which is set with the SUPL_MODE_* constants.
+     */
+    void setSuplMode(in int mode);
+
+    /**
+     * This method sets the LTE Positioning Profile configuration.
+     *
+     * @param lppProfile Bitmask that specifies the LTE Positioning Profile configuration to be set
+     * as per the LPP_PROFILE_* constants. If none of the bits are set, the default setting is
+     * Radio Resource Location Protocol (RRLP).
+     */
+    void setLppProfile(in int lppProfile);
+
+    /**
+     * This method selects positioning protocol on A-Glonass system.
+     *
+     * @param protocol Bitmask that specifies the positioning protocol to be set as per
+     * GLONASS_POS_PROTOCOL_* constants.
+     */
+    void setGlonassPositioningProtocol(in int protocol);
+
+    /**
+     * This method configures which PDN to use.
+     *
+     * @param enable Use emergency PDN if true and regular PDN if false.
+     */
+    void setEmergencySuplPdn(in boolean enable);
+
+    /**
+     * This method sets the emergency session extension duration. The GNSS HAL
+     * implementation must serve emergency SUPL and Control Plane network initiated
+     * location requests for this extra duration after the user initiated emergency
+     * session ends.
+     *
+     * @param emergencyExtensionSeconds Number of seconds to extend the emergency
+     * session duration post emergency call.
+     */
+    void setEsExtensionSec(in int emergencyExtensionSeconds);
+
+    /**
+     * Injects a vector of BlocklistedSource(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 blocklisted
+     * 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 blocklisted as a result of
+     * this API.
+     *
+     * This blocklist 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 blocklist The BlocklistedSource(s) of satellites the HAL must not use.
+     */
+    void setBlocklist(in BlocklistedSource[] blocklist);
+}
\ No newline at end of file
diff --git a/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl b/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl
index 6f53d6f..7c46096 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssPsds.aidl
@@ -32,18 +32,14 @@
      * @param psdsType Type of PSDS data.
      * @param psdsData GNSS PSDS data. Framework must not parse the data since the data format is
      *                 opaque to framework.
-     *
-     * @return True if the operation is successful.
      */
-    boolean injectPsdsData(in PsdsType psdsType, in byte[] psdsData);
+    void injectPsdsData(in PsdsType psdsType, in byte[] psdsData);
 
     /**
      * Opens the PSDS interface and provides the callback routines to the implementation of this
      * interface.
      *
      * @param callback Handle to the IGnssPsdsCallback interface.
-     *
-     * @return True if the operation is successful.
      */
-    boolean setCallback(in IGnssPsdsCallback callback);
+    void setCallback(in IGnssPsdsCallback callback);
 }
\ No newline at end of file
diff --git a/gnss/aidl/default/Android.bp b/gnss/aidl/default/Android.bp
index 8c4ee40..1fe43c3 100644
--- a/gnss/aidl/default/Android.bp
+++ b/gnss/aidl/default/Android.bp
@@ -17,8 +17,13 @@
 cc_binary {
     name: "android.hardware.gnss-service.example",
     relative_install_path: "hw",
-    init_rc: ["gnss-default.rc"],
-    vintf_fragments: ["gnss-default.xml"],
+    init_rc: [
+        "gnss-default.rc",
+    ],
+    vintf_fragments: [
+        "gnss-default.xml",
+        "gnss@2.1-service.xml",
+    ],
     vendor: true,
     cflags: [
         "-Wall",
@@ -27,12 +32,26 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
+        "libhidlbase",
+        "libutils",
         "liblog",
+        "android.hardware.gnss@2.1",
+        "android.hardware.gnss@2.0",
+        "android.hardware.gnss@1.1",
+        "android.hardware.gnss@1.0",
+        "android.hardware.gnss.measurement_corrections@1.1",
+        "android.hardware.gnss.measurement_corrections@1.0",
+        "android.hardware.gnss.visibility_control@1.0",
         "android.hardware.gnss-ndk_platform",
     ],
     srcs: [
         "Gnss.cpp",
+        "GnssHidlHal.cpp",
         "GnssPsds.cpp",
+        "GnssConfiguration.cpp",
         "service.cpp",
     ],
+    static_libs: [
+        "android.hardware.gnss@common-default-lib",
+    ],
 }
diff --git a/gnss/aidl/default/Gnss.cpp b/gnss/aidl/default/Gnss.cpp
index 2a35924..b4d92fd 100644
--- a/gnss/aidl/default/Gnss.cpp
+++ b/gnss/aidl/default/Gnss.cpp
@@ -18,14 +18,51 @@
 
 #include "Gnss.h"
 #include <log/log.h>
+#include "GnssConfiguration.h"
 #include "GnssPsds.h"
 
 namespace aidl::android::hardware::gnss {
 
+std::shared_ptr<IGnssCallback> Gnss::sGnssCallback = nullptr;
+
+ndk::ScopedAStatus Gnss::setCallback(const std::shared_ptr<IGnssCallback>& callback) {
+    ALOGD("Gnss::setCallback");
+    if (callback == nullptr) {
+        ALOGE("%s: Null callback ignored", __func__);
+        return ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
+    }
+
+    sGnssCallback = callback;
+
+    int capabilities = (int)IGnssCallback::CAPABILITY_SATELLITE_BLOCKLIST;
+    auto status = sGnssCallback->gnssSetCapabilitiesCb(capabilities);
+    if (!status.isOk()) {
+        ALOGE("%s: Unable to invoke callback.gnssSetCapabilities", __func__);
+    }
+
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Gnss::close() {
+    ALOGD("Gnss::close");
+    sGnssCallback = nullptr;
+    return ndk::ScopedAStatus::ok();
+}
+
 ndk::ScopedAStatus Gnss::getExtensionPsds(std::shared_ptr<IGnssPsds>* iGnssPsds) {
     ALOGD("Gnss::getExtensionPsds");
     *iGnssPsds = SharedRefBase::make<GnssPsds>();
     return ndk::ScopedAStatus::ok();
 }
 
+ndk::ScopedAStatus Gnss::getExtensionGnssConfiguration(
+        std::shared_ptr<IGnssConfiguration>* iGnssConfiguration) {
+    ALOGD("Gnss::getExtensionGnssConfiguration");
+    if (mGnssConfiguration == nullptr) {
+        mGnssConfiguration = SharedRefBase::make<GnssConfiguration>();
+    }
+    *iGnssConfiguration = mGnssConfiguration;
+    return ndk::ScopedAStatus::ok();
+}
+
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/Gnss.h b/gnss/aidl/default/Gnss.h
index 9864e9d..61d7cf7 100644
--- a/gnss/aidl/default/Gnss.h
+++ b/gnss/aidl/default/Gnss.h
@@ -17,12 +17,24 @@
 #pragma once
 
 #include <aidl/android/hardware/gnss/BnGnss.h>
+#include <aidl/android/hardware/gnss/BnGnssConfiguration.h>
 #include <aidl/android/hardware/gnss/BnGnssPsds.h>
+#include "GnssConfiguration.h"
 
 namespace aidl::android::hardware::gnss {
 
 class Gnss : public BnGnss {
+  public:
+    ndk::ScopedAStatus setCallback(const std::shared_ptr<IGnssCallback>& callback) override;
+    ndk::ScopedAStatus close() override;
     ndk::ScopedAStatus getExtensionPsds(std::shared_ptr<IGnssPsds>* iGnssPsds) override;
+    ndk::ScopedAStatus getExtensionGnssConfiguration(
+            std::shared_ptr<IGnssConfiguration>* iGnssConfiguration) override;
+
+    std::shared_ptr<GnssConfiguration> mGnssConfiguration;
+
+  private:
+    static std::shared_ptr<IGnssCallback> sGnssCallback;
 };
 
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssConfiguration.cpp b/gnss/aidl/default/GnssConfiguration.cpp
new file mode 100644
index 0000000..30e0d8c
--- /dev/null
+++ b/gnss/aidl/default/GnssConfiguration.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "GnssConfigurationAidl"
+
+#include "GnssConfiguration.h"
+#include <log/log.h>
+
+namespace aidl::android::hardware::gnss {
+
+ndk::ScopedAStatus GnssConfiguration::setBlocklist(const vector<BlocklistedSource>& sourceList) {
+    ALOGD("GnssConfiguration::setBlocklist");
+    std::unique_lock<std::recursive_mutex> lock(mMutex);
+    mBlocklistedConstellationSet.clear();
+    mBlocklistedSourceSet.clear();
+    for (const auto& source : sourceList) {
+        if (source.svid == 0) {
+            // Wildcard blocklist, i.e., blocklist entire constellation.
+            mBlocklistedConstellationSet.insert(source.constellation);
+        } else {
+            mBlocklistedSourceSet.insert(source);
+        }
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+bool GnssConfiguration::isBlocklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const {
+    std::unique_lock<std::recursive_mutex> lock(mMutex);
+    if (mBlocklistedConstellationSet.find(static_cast<GnssConstellationType>(
+                gnssSvInfo.v2_0.constellation)) != mBlocklistedConstellationSet.end()) {
+        return true;
+    }
+    BlocklistedSource source = {
+            .constellation = static_cast<GnssConstellationType>(gnssSvInfo.v2_0.constellation),
+            .svid = gnssSvInfo.v2_0.v1_0.svid};
+    return (mBlocklistedSourceSet.find(source) != mBlocklistedSourceSet.end());
+}
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssConfiguration.h b/gnss/aidl/default/GnssConfiguration.h
new file mode 100644
index 0000000..25fa16e
--- /dev/null
+++ b/gnss/aidl/default/GnssConfiguration.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/gnss/BnGnssConfiguration.h>
+#include <android/hardware/gnss/2.1/IGnssCallback.h>
+#include <mutex>
+#include <unordered_set>
+#include <vector>
+
+namespace aidl::android::hardware::gnss {
+
+using android::hardware::gnss::GnssConstellationType;
+
+struct BlocklistedSourceHash {
+    inline int operator()(const BlocklistedSource& source) const {
+        return int(source.constellation) * 1000 + int(source.svid);
+    }
+};
+
+struct BlocklistedSourceEqual {
+    inline bool operator()(const BlocklistedSource& s1, const BlocklistedSource& s2) const {
+        return (s1.constellation == s2.constellation) && (s1.svid == s2.svid);
+    }
+};
+
+using GnssSvInfoV2_1 = ::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo;
+using std::vector;
+using BlocklistedSourceSet =
+        std::unordered_set<BlocklistedSource, BlocklistedSourceHash, BlocklistedSourceEqual>;
+using BlocklistedConstellationSet = std::unordered_set<GnssConstellationType>;
+
+struct GnssConfiguration : public BnGnssConfiguration {
+  public:
+    ndk::ScopedAStatus setSuplVersion(int) override { return ndk::ScopedAStatus::ok(); }
+
+    ndk::ScopedAStatus setSuplMode(int) override { return ndk::ScopedAStatus::ok(); }
+
+    ndk::ScopedAStatus setLppProfile(int) override { return ndk::ScopedAStatus::ok(); }
+
+    ndk::ScopedAStatus setGlonassPositioningProtocol(int) override {
+        return ndk::ScopedAStatus::ok();
+    }
+
+    ndk::ScopedAStatus setEmergencySuplPdn(bool) override { return ndk::ScopedAStatus::ok(); }
+
+    ndk::ScopedAStatus setEsExtensionSec(int) override { return ndk::ScopedAStatus::ok(); }
+
+    ndk::ScopedAStatus setBlocklist(const vector<BlocklistedSource>& blocklist) override;
+
+    bool isBlocklistedV2_1(const GnssSvInfoV2_1& gnssSvInfo) const;
+
+  private:
+    BlocklistedSourceSet mBlocklistedSourceSet;
+    BlocklistedConstellationSet mBlocklistedConstellationSet;
+    mutable std::recursive_mutex mMutex;
+};
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssHidlHal.cpp b/gnss/aidl/default/GnssHidlHal.cpp
new file mode 100644
index 0000000..11fc806
--- /dev/null
+++ b/gnss/aidl/default/GnssHidlHal.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "GnssHidlHal"
+
+#include "GnssHidlHal.h"
+//#include <android/hardware/gnss/1.0/IGnssCallback.h>
+
+namespace aidl::android::hardware::gnss {
+
+namespace V1_0 = ::android::hardware::gnss::V1_0;
+
+GnssHidlHal::GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl) : mGnssAidl(gnssAidl) {
+    Gnss* iGnss = mGnssAidl.get();
+    std::shared_ptr<IGnssConfiguration> iGnssConfiguration;
+    auto status = iGnss->getExtensionGnssConfiguration(&iGnssConfiguration);
+    if (!status.isOk()) {
+        ALOGE("Failed to getExtensionGnssConfiguration.");
+    } else {
+        mGnssConfigurationAidl = iGnss->mGnssConfiguration;
+    }
+};
+
+hidl_vec<GnssSvInfo> GnssHidlHal::filterBlocklistedSatellitesV2_1(
+        hidl_vec<GnssSvInfo> gnssSvInfoList) {
+    ALOGD("filterBlocklistSatellitesV2_1 - overridden by GnssHidlHal class");
+    if (mGnssConfigurationAidl == nullptr) {
+        ALOGE("Handle to AIDL GnssConfiguration is not available.");
+        return gnssSvInfoList;
+    }
+    for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
+        if (mGnssConfigurationAidl->isBlocklistedV2_1(gnssSvInfoList[i])) {
+            ALOGD("Blocklisted constellation: %d, svid: %d",
+                  (int)gnssSvInfoList[i].v2_0.constellation, gnssSvInfoList[i].v2_0.v1_0.svid);
+            gnssSvInfoList[i].v2_0.v1_0.svFlag &=
+                    ~static_cast<uint8_t>(V1_0::IGnssCallback::GnssSvFlags::USED_IN_FIX);
+        }
+    }
+    return gnssSvInfoList;
+}
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssHidlHal.h b/gnss/aidl/default/GnssHidlHal.h
new file mode 100644
index 0000000..50aad3a
--- /dev/null
+++ b/gnss/aidl/default/GnssHidlHal.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include "Gnss.h"
+#include "GnssConfiguration.h"
+#include "v2_1/GnssTemplate.h"
+
+namespace aidl::android::hardware::gnss {
+
+using ::android::hardware::gnss::common::implementation::GnssTemplate;
+using GnssSvInfo = ::android::hardware::gnss::V2_1::IGnssCallback::GnssSvInfo;
+
+class GnssHidlHal : public GnssTemplate<::android::hardware::gnss::V2_1::IGnss> {
+  public:
+    GnssHidlHal(const std::shared_ptr<Gnss>& gnssAidl);
+
+  private:
+    hidl_vec<GnssSvInfo> filterBlocklistedSatellitesV2_1(
+            hidl_vec<GnssSvInfo> gnssSvInfoList) override;
+
+    std::shared_ptr<Gnss> mGnssAidl;
+    std::shared_ptr<GnssConfiguration> mGnssConfigurationAidl;
+};
+
+}  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssPsds.cpp b/gnss/aidl/default/GnssPsds.cpp
index c354217..6512af6 100644
--- a/gnss/aidl/default/GnssPsds.cpp
+++ b/gnss/aidl/default/GnssPsds.cpp
@@ -17,27 +17,28 @@
 #define LOG_TAG "GnssPsdsAidl"
 
 #include "GnssPsds.h"
-
+#include <aidl/android/hardware/gnss/BnGnss.h>
 #include <log/log.h>
 
 namespace aidl::android::hardware::gnss {
 
 std::shared_ptr<IGnssPsdsCallback> GnssPsds::sCallback = nullptr;
 
-ndk::ScopedAStatus GnssPsds::setCallback(const std::shared_ptr<IGnssPsdsCallback>& callback,
-                                         bool* success) {
+ndk::ScopedAStatus GnssPsds::setCallback(const std::shared_ptr<IGnssPsdsCallback>& callback) {
     ALOGD("setCallback");
     std::unique_lock<std::mutex> lock(mMutex);
     sCallback = callback;
-    *success = true;
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus GnssPsds::injectPsdsData(PsdsType psdsType, const std::vector<uint8_t>& psdsData,
-                                            bool* success) {
+ndk::ScopedAStatus GnssPsds::injectPsdsData(PsdsType psdsType,
+                                            const std::vector<uint8_t>& psdsData) {
     ALOGD("injectPsdsData. psdsType: %d, psdsData: %d bytes", static_cast<int>(psdsType),
           static_cast<int>(psdsData.size()));
-    *success = (psdsData.size() > 0);
-    return ndk::ScopedAStatus::ok();
+    if (psdsData.size() > 0) {
+        return ndk::ScopedAStatus::ok();
+    } else {
+        return ndk::ScopedAStatus::fromServiceSpecificError(IGnss::ERROR_INVALID_ARGUMENT);
+    }
 }
 }  // namespace aidl::android::hardware::gnss
diff --git a/gnss/aidl/default/GnssPsds.h b/gnss/aidl/default/GnssPsds.h
index fc65bc1..de9e68f 100644
--- a/gnss/aidl/default/GnssPsds.h
+++ b/gnss/aidl/default/GnssPsds.h
@@ -22,10 +22,9 @@
 
 struct GnssPsds : public BnGnssPsds {
   public:
-    ndk::ScopedAStatus setCallback(const std::shared_ptr<IGnssPsdsCallback>& callback,
-                                   bool* success) override;
-    ndk::ScopedAStatus injectPsdsData(PsdsType psdsType, const std::vector<uint8_t>& psdsData,
-                                      bool* success) override;
+    ndk::ScopedAStatus setCallback(const std::shared_ptr<IGnssPsdsCallback>& callback) override;
+    ndk::ScopedAStatus injectPsdsData(PsdsType psdsType,
+                                      const std::vector<uint8_t>& psdsData) override;
 
   private:
     // Guarded by mMutex
diff --git a/gnss/aidl/default/gnss@2.1-service.xml b/gnss/aidl/default/gnss@2.1-service.xml
new file mode 100644
index 0000000..12a1fdf
--- /dev/null
+++ b/gnss/aidl/default/gnss@2.1-service.xml
@@ -0,0 +1,12 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.gnss</name>
+        <transport>hwbinder</transport>
+        <version>2.1</version>
+        <version>1.1</version>
+        <interface>
+            <name>IGnss</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/gnss/aidl/default/service.cpp b/gnss/aidl/default/service.cpp
index c79a271..09f1ad2 100644
--- a/gnss/aidl/default/service.cpp
+++ b/gnss/aidl/default/service.cpp
@@ -14,22 +14,45 @@
  * limitations under the License.
  */
 
-#include "Gnss.h"
+#define LOG_TAG "Gnss-main"
 
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <pthread.h>
+#include "Gnss.h"
+#include "GnssHidlHal.h"
 
 using aidl::android::hardware::gnss::Gnss;
+using aidl::android::hardware::gnss::GnssHidlHal;
+using ::android::OK;
+using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::gnss::V2_1::IGnss;
 
 int main() {
-    ABinderProcess_setThreadPoolMaxThreadCount(0);
-    std::shared_ptr<Gnss> vib = ndk::SharedRefBase::make<Gnss>();
+    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_startThreadPool();
 
+    std::shared_ptr<Gnss> gnssAidl = ndk::SharedRefBase::make<Gnss>();
     const std::string instance = std::string() + Gnss::descriptor + "/default";
-    binder_status_t status = AServiceManager_addService(vib->asBinder().get(), instance.c_str());
+    binder_status_t status =
+            AServiceManager_addService(gnssAidl->asBinder().get(), instance.c_str());
     CHECK(status == STATUS_OK);
 
+    sp<IGnss> gnss = new GnssHidlHal(gnssAidl);
+    configureRpcThreadpool(1, true /* will join */);
+    if (gnss->registerAsService() != OK) {
+        ALOGE("Could not register gnss 2.1 service.");
+        return 0;
+    }
+
+    joinRpcThreadpool();
     ABinderProcess_joinThreadPool();
+
     return EXIT_FAILURE;  // should not reach
 }
diff --git a/gnss/aidl/vts/Android.bp b/gnss/aidl/vts/Android.bp
index e57b421..7f3e5ef 100644
--- a/gnss/aidl/vts/Android.bp
+++ b/gnss/aidl/vts/Android.bp
@@ -18,14 +18,22 @@
         "VtsHalTargetTestDefaults",
         "use_libaidlvintf_gtest_helper_static",
     ],
-    srcs: ["VtsHalGnssTargetTest.cpp"],
+    srcs: [
+        "gnss_hal_test.cpp",
+        "gnss_hal_test_cases.cpp",
+        "GnssCallbackAidl.cpp",
+        "VtsHalGnssTargetTest.cpp",
+    ],
     shared_libs: [
+        "android.hardware.gnss@2.1",
         "libbinder",
     ],
     static_libs: [
         "android.hardware.gnss-cpp",
+        "android.hardware.gnss@common-vts-lib",
     ],
     test_suites: [
+        "general-tests",
         "vts",
     ],
 }
diff --git a/gnss/aidl/vts/GnssCallbackAidl.cpp b/gnss/aidl/vts/GnssCallbackAidl.cpp
new file mode 100644
index 0000000..f5c745b
--- /dev/null
+++ b/gnss/aidl/vts/GnssCallbackAidl.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "GnssCallbackAidl.h"
+#include <log/log.h>
+
+android::binder::Status GnssCallbackAidl::gnssSetCapabilitiesCb(const int capabilities) {
+    ALOGI("Capabilities received %d", capabilities);
+    capabilities_cbq_.store(capabilities);
+    return android::binder::Status::ok();
+}
diff --git a/gnss/aidl/vts/GnssCallbackAidl.h b/gnss/aidl/vts/GnssCallbackAidl.h
new file mode 100644
index 0000000..7f802ea
--- /dev/null
+++ b/gnss/aidl/vts/GnssCallbackAidl.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <android/hardware/gnss/BnGnssCallback.h>
+#include "GnssCallbackEventQueue.h"
+
+/* Callback class for data & Event. */
+class GnssCallbackAidl : public android::hardware::gnss::BnGnssCallback {
+  public:
+    GnssCallbackAidl() : capabilities_cbq_("capabilities"){};
+    ~GnssCallbackAidl(){};
+
+    android::binder::Status gnssSetCapabilitiesCb(const int capabilities) override;
+
+    int last_capabilities_;
+    android::hardware::gnss::common::GnssCallbackEventQueue<int> capabilities_cbq_;
+};
\ No newline at end of file
diff --git a/gnss/aidl/vts/VtsHalGnssTargetTest.cpp b/gnss/aidl/vts/VtsHalGnssTargetTest.cpp
index e7ffc05..4bba92b 100644
--- a/gnss/aidl/vts/VtsHalGnssTargetTest.cpp
+++ b/gnss/aidl/vts/VtsHalGnssTargetTest.cpp
@@ -13,60 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <aidl/Gtest.h>
-#include <aidl/Vintf.h>
+
+#include "gnss_hal_test.h"
 
 #include <android/hardware/gnss/IGnss.h>
-#include <android/hardware/gnss/IGnssPsds.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 
 using android::ProcessState;
-using android::sp;
-using android::String16;
-using android::binder::Status;
-using android::hardware::gnss::IGnss;
-using android::hardware::gnss::IGnssPsds;
-using android::hardware::gnss::PsdsType;
 
-class GnssAidlHalTest : public testing::TestWithParam<std::string> {
-  public:
-    virtual void SetUp() override {
-        gnss_hal_ = android::waitForDeclaredService<IGnss>(String16(GetParam().c_str()));
-        ASSERT_NE(gnss_hal_, nullptr);
-    }
-
-    sp<IGnss> gnss_hal_;
-};
-
-/*
- * SetupTeardownCreateCleanup:
- * Requests the gnss HAL then calls cleanup
- *
- * Empty test fixture to verify basic Setup & Teardown
- */
-TEST_P(GnssAidlHalTest, SetupTeardownCreateCleanup) {}
-
-/*
- * TestPsdsExtension:
- * 1. Gets the PsdsExtension and verifies that it returns a non-null extension.
- * 2. Injects empty PSDS data and verifies that it returns false.
- */
-TEST_P(GnssAidlHalTest, TestPsdsExtension) {
-    sp<IGnssPsds> iGnssPsds;
-    auto status = gnss_hal_->getExtensionPsds(&iGnssPsds);
-    ASSERT_TRUE(status.isOk());
-    ASSERT_TRUE(iGnssPsds != nullptr);
-
-    bool success;
-    status = iGnssPsds->injectPsdsData(PsdsType::LONG_TERM, std::vector<uint8_t>(), &success);
-    ASSERT_TRUE(status.isOk());
-    ASSERT_FALSE(success);
-}
-
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssAidlHalTest);
-INSTANTIATE_TEST_SUITE_P(, GnssAidlHalTest,
-                         testing::ValuesIn(android::getAidlHalInstanceNames(IGnss::descriptor)),
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GnssHalTest);
+INSTANTIATE_TEST_SUITE_P(, GnssHalTest,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IGnssAidl::descriptor)),
                          android::PrintInstanceNameToString);
 
 int main(int argc, char** argv) {
diff --git a/gnss/aidl/vts/gnss_hal_test.cpp b/gnss/aidl/vts/gnss_hal_test.cpp
new file mode 100644
index 0000000..2447bf8
--- /dev/null
+++ b/gnss/aidl/vts/gnss_hal_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gnss_hal_test.h"
+#include <hidl/ServiceManagement.h>
+
+using GnssConstellationTypeAidl = android::hardware::gnss::GnssConstellationType;
+
+void GnssHalTest::SetUp() {
+    // Get AIDL handle
+    aidl_gnss_hal_ = android::waitForDeclaredService<IGnssAidl>(String16(GetParam().c_str()));
+    ASSERT_NE(aidl_gnss_hal_, nullptr);
+
+    const auto& hidlInstanceNames = android::hardware::getAllHalInstanceNames(
+            android::hardware::gnss::V2_1::IGnss::descriptor);
+    gnss_hal_ = IGnss_V2_1::getService(hidlInstanceNames[0]);
+    ASSERT_NE(gnss_hal_, nullptr);
+
+    SetUpGnssCallback();
+}
+
+void GnssHalTest::SetUpGnssCallback() {
+    aidl_gnss_cb_ = new GnssCallbackAidl();
+    ASSERT_NE(aidl_gnss_cb_, nullptr);
+
+    auto status = aidl_gnss_hal_->setCallback(aidl_gnss_cb_);
+    if (!status.isOk()) {
+        ALOGE("Failed to setCallback");
+    }
+
+    ASSERT_TRUE(status.isOk());
+
+    /*
+     * Capabilities callback should trigger.
+     */
+    EXPECT_TRUE(aidl_gnss_cb_->capabilities_cbq_.retrieve(aidl_gnss_cb_->last_capabilities_,
+                                                          TIMEOUT_SEC));
+
+    EXPECT_EQ(aidl_gnss_cb_->capabilities_cbq_.calledCount(), 1);
+
+    // Invoke the super method.
+    GnssHalTestTemplate<IGnss_V2_1>::SetUpGnssCallback();
+}
diff --git a/gnss/aidl/vts/gnss_hal_test.h b/gnss/aidl/vts/gnss_hal_test.h
new file mode 100644
index 0000000..eb5301e
--- /dev/null
+++ b/gnss/aidl/vts/gnss_hal_test.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android/hardware/gnss/IGnss.h>
+#include <binder/IServiceManager.h>
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include "GnssCallbackAidl.h"
+#include "v2_1/gnss_hal_test_template.h"
+
+using IGnss_V2_1 = android::hardware::gnss::V2_1::IGnss;
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using IGnssAidl = android::hardware::gnss::IGnss;
+using android::hardware::gnss::BlocklistedSource;
+using android::hardware::gnss::IGnssConfiguration;
+
+// The main test class for GNSS HAL.
+class GnssHalTest : public GnssHalTestTemplate<IGnss_V2_1> {
+  public:
+    GnssHalTest(){};
+    ~GnssHalTest(){};
+    virtual void SetUp() override;
+    virtual void SetUpGnssCallback() override;
+
+    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
new file mode 100644
index 0000000..2b8a447
--- /dev/null
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "GnssHalTestCases"
+
+#include <android/hardware/gnss/IGnssPsds.h>
+#include "gnss_hal_test.h"
+
+using android::sp;
+using android::hardware::gnss::BlocklistedSource;
+using GnssConstellationTypeAidl = android::hardware::gnss::GnssConstellationType;
+using android::hardware::gnss::IGnssConfiguration;
+using android::hardware::gnss::IGnssPsds;
+using android::hardware::gnss::PsdsType;
+
+/*
+ * SetupTeardownCreateCleanup:
+ * Requests the gnss HAL then calls cleanup
+ *
+ * Empty test fixture to verify basic Setup & Teardown
+ */
+TEST_P(GnssHalTest, SetupTeardownCreateCleanup) {}
+
+/*
+ * TestPsdsExtension:
+ * 1. Gets the PsdsExtension and verifies that it returns a non-null extension.
+ * 2. Injects empty PSDS data and verifies that it returns false.
+ */
+TEST_P(GnssHalTest, TestPsdsExtension) {
+    sp<IGnssPsds> iGnssPsds;
+    auto status = aidl_gnss_hal_->getExtensionPsds(&iGnssPsds);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_TRUE(iGnssPsds != nullptr);
+
+    status = iGnssPsds->injectPsdsData(PsdsType::LONG_TERM, std::vector<uint8_t>());
+    ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * FindStrongFrequentNonGpsSource:
+ *
+ * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
+ *
+ * returns the strongest source,
+ *         or a source with constellation == UNKNOWN if none are found sufficient times
+ */
+BlocklistedSource FindStrongFrequentNonGpsSource(
+        const std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_list,
+        const int min_observations) {
+    struct ComparableBlocklistedSource {
+        BlocklistedSource id;
+
+        ComparableBlocklistedSource() {
+            id.constellation = GnssConstellationTypeAidl::UNKNOWN;
+            id.svid = 0;
+        }
+
+        bool operator<(const ComparableBlocklistedSource& 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<ComparableBlocklistedSource, SignalCounts> mapSignals;
+
+    for (const auto& sv_info_vec : sv_info_list) {
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            if ((gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX) &&
+                (gnss_sv.v2_0.constellation != GnssConstellationType::GPS)) {
+                ComparableBlocklistedSource source;
+                source.id.svid = gnss_sv.v2_0.v1_0.svid;
+                source.id.constellation =
+                        static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation);
+
+                const auto& itSignal = mapSignals.find(source);
+                if (itSignal == mapSignals.end()) {
+                    SignalCounts counts;
+                    counts.observations = 1;
+                    counts.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
+                    mapSignals.insert(
+                            std::pair<ComparableBlocklistedSource, SignalCounts>(source, counts));
+                } else {
+                    itSignal->second.observations++;
+                    if (itSignal->second.max_cn0_dbhz < gnss_sv.v2_0.v1_0.cN0Dbhz) {
+                        itSignal->second.max_cn0_dbhz = gnss_sv.v2_0.v1_0.cN0Dbhz;
+                    }
+                }
+            }
+        }
+    }
+
+    float max_cn0_dbhz_with_sufficient_count = 0.;
+    int total_observation_count = 0;
+    int blocklisted_source_count_observation = 0;
+
+    ComparableBlocklistedSource source_to_blocklist;  // 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_blocklist = pairSignal.first;
+            blocklisted_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_blocklist.id.svid,
+          (int)source_to_blocklist.id.constellation, blocklisted_source_count_observation,
+          max_cn0_dbhz_with_sufficient_count);
+
+    return source_to_blocklist.id;
+}
+
+/*
+ * BlocklistIndividualSatellites:
+ *
+ * 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 blocklists 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 blocklist.
+ * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does re-use at least the previously strongest satellite
+ * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
+ * formerly strongest satellite
+ */
+TEST_P(GnssHalTest, BlocklistIndividualSatellites) {
+    if (!(aidl_gnss_cb_->last_capabilities_ &
+          (int)GnssCallbackAidl::CAPABILITY_SATELLITE_BLOCKLIST)) {
+        ALOGI("Test BlocklistIndividualSatellites skipped. SATELLITE_BLOCKLIST capability not "
+              "supported.");
+        return;
+    }
+
+    const int kLocationsToAwait = 3;
+    const int kRetriesToUnBlocklist = 10;
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+    int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+
+    /*
+     * 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)
+     */
+
+    const int kGnssSvInfoListTimeout = 2;
+    std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
+    int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size,
+                                                     kGnssSvInfoListTimeout);
+
+    ASSERT_EQ(count, sv_info_list_cbq_size);
+
+    BlocklistedSource source_to_blocklist =
+            FindStrongFrequentNonGpsSource(sv_info_vec_list, kLocationsToAwait - 1);
+
+    if (source_to_blocklist.constellation == GnssConstellationTypeAidl::UNKNOWN) {
+        // Cannot find a non-GPS satellite. Let the test pass.
+        ALOGD("Cannot find a non-GPS satellite. Letting the test pass.");
+        return;
+    }
+
+    // Stop locations, blocklist the common SV
+    StopAndClearLocations();
+
+    sp<IGnssConfiguration> gnss_configuration_hal;
+    auto status = aidl_gnss_hal_->getExtensionGnssConfiguration(&gnss_configuration_hal);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    std::vector<BlocklistedSource> sources;
+    sources.resize(1);
+    sources[0] = source_to_blocklist;
+
+    status = gnss_configuration_hal->setBlocklist(sources);
+    ASSERT_TRUE(status.isOk());
+
+    // retry and ensure satellite not used
+    gnss_cb_->sv_info_list_cbq_.reset();
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // early exit if test is being run with insufficient signal
+    location_called_count = gnss_cb_->location_cbq_.calledCount();
+    if (location_called_count == 0) {
+        ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+    }
+    ASSERT_TRUE(location_called_count > 0);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            EXPECT_FALSE((gnss_sv.v2_0.v1_0.svid == source_to_blocklist.svid) &&
+                         (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                          source_to_blocklist.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clear blocklist and restart - this time updating the blocklist while location is still on
+    sources.resize(0);
+
+    status = gnss_configuration_hal->setBlocklist(sources);
+    ASSERT_TRUE(status.isOk());
+
+    bool strongest_sv_is_reobserved = false;
+    // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
+    int unblocklist_loops_remaining = kRetriesToUnBlocklist;
+    while (!strongest_sv_is_reobserved && (unblocklist_loops_remaining-- > 0)) {
+        StopAndClearLocations();
+        gnss_cb_->sv_info_list_cbq_.reset();
+
+        gnss_cb_->location_cbq_.reset();
+        StartAndCheckLocations(kLocationsToAwait);
+
+        // early exit loop if test is being run with insufficient signal
+        location_called_count = gnss_cb_->location_cbq_.calledCount();
+        if (location_called_count == 0) {
+            ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+        }
+        ASSERT_TRUE(location_called_count > 0);
+
+        // Tolerate 1 less sv status to handle edge cases in reporting.
+        sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+        EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+        ALOGD("Clear blocklist, observed %d GnssSvInfo, while awaiting %d Locations"
+              ", tries remaining %d",
+              sv_info_list_cbq_size, kLocationsToAwait, unblocklist_loops_remaining);
+
+        for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+            hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+            gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+            for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+                const auto& gnss_sv = sv_info_vec[iSv];
+                if ((gnss_sv.v2_0.v1_0.svid == source_to_blocklist.svid) &&
+                    (static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                     source_to_blocklist.constellation) &&
+                    (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX)) {
+                    strongest_sv_is_reobserved = true;
+                    break;
+                }
+            }
+            if (strongest_sv_is_reobserved) break;
+        }
+    }
+    EXPECT_TRUE(strongest_sv_is_reobserved);
+    StopAndClearLocations();
+}
+
+/*
+ * BlocklistConstellationLocationOff:
+ *
+ * 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 blocklist 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 blocklist.
+ */
+TEST_P(GnssHalTest, BlocklistConstellationLocationOff) {
+    if (!(aidl_gnss_cb_->last_capabilities_ &
+          (int)GnssCallbackAidl::CAPABILITY_SATELLITE_BLOCKLIST)) {
+        ALOGI("Test BlocklistConstellationLocationOff skipped. SATELLITE_BLOCKLIST capability not "
+              "supported.");
+        return;
+    }
+
+    const int kLocationsToAwait = 3;
+    const int kGnssSvInfoListTimeout = 2;
+
+    // Find first non-GPS constellation to blocklist
+    GnssConstellationTypeAidl constellation_to_blocklist = static_cast<GnssConstellationTypeAidl>(
+            startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
+
+    // Turns off location
+    StopAndClearLocations();
+
+    BlocklistedSource source_to_blocklist_1;
+    source_to_blocklist_1.constellation = constellation_to_blocklist;
+    source_to_blocklist_1.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    // IRNSS was added in 2.0. Always attempt to blocklist IRNSS to verify that the new enum is
+    // supported.
+    BlocklistedSource source_to_blocklist_2;
+    source_to_blocklist_2.constellation = GnssConstellationTypeAidl::IRNSS;
+    source_to_blocklist_2.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    sp<IGnssConfiguration> gnss_configuration_hal;
+    auto status = aidl_gnss_hal_->getExtensionGnssConfiguration(&gnss_configuration_hal);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<BlocklistedSource> sources;
+    sources.resize(2);
+    sources[0] = source_to_blocklist_1;
+    sources[1] = source_to_blocklist_2;
+
+    status = gnss_configuration_hal->setBlocklist(sources);
+    ASSERT_TRUE(status.isOk());
+
+    // retry and ensure constellation not used
+    gnss_cb_->sv_info_list_cbq_.reset();
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
+          kLocationsToAwait);
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                          source_to_blocklist_1.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+            EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                          source_to_blocklist_2.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clean up
+    StopAndClearLocations();
+    sources.resize(0);
+    status = gnss_configuration_hal->setBlocklist(sources);
+    ASSERT_TRUE(status.isOk());
+}
+
+/*
+ * BlocklistConstellationLocationOn:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Blocklist first non-GPS constellation, and turn 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 blocklist.
+ */
+TEST_P(GnssHalTest, BlocklistConstellationLocationOn) {
+    if (!(aidl_gnss_cb_->last_capabilities_ &
+          (int)GnssCallbackAidl::CAPABILITY_SATELLITE_BLOCKLIST)) {
+        ALOGI("Test BlocklistConstellationLocationOn skipped. SATELLITE_BLOCKLIST capability not "
+              "supported.");
+        return;
+    }
+
+    const int kLocationsToAwait = 3;
+    const int kGnssSvInfoListTimeout = 2;
+
+    // Find first non-GPS constellation to blocklist
+    GnssConstellationTypeAidl constellation_to_blocklist = static_cast<GnssConstellationTypeAidl>(
+            startLocationAndGetNonGpsConstellation(kLocationsToAwait, kGnssSvInfoListTimeout));
+
+    BlocklistedSource source_to_blocklist_1;
+    source_to_blocklist_1.constellation = constellation_to_blocklist;
+    source_to_blocklist_1.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    // IRNSS was added in 2.0. Always attempt to blocklist IRNSS to verify that the new enum is
+    // supported.
+    BlocklistedSource source_to_blocklist_2;
+    source_to_blocklist_2.constellation = GnssConstellationTypeAidl::IRNSS;
+    source_to_blocklist_2.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    sp<IGnssConfiguration> gnss_configuration_hal;
+    auto status = aidl_gnss_hal_->getExtensionGnssConfiguration(&gnss_configuration_hal);
+    ASSERT_TRUE(status.isOk());
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<BlocklistedSource> sources;
+    sources.resize(2);
+    sources[0] = source_to_blocklist_1;
+    sources[1] = source_to_blocklist_2;
+
+    status = gnss_configuration_hal->setBlocklist(sources);
+    ASSERT_TRUE(status.isOk());
+
+    // Turns off location
+    StopAndClearLocations();
+
+    // retry and ensure constellation not used
+    gnss_cb_->sv_info_list_cbq_.reset();
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvInfo, while awaiting %d Locations", sv_info_list_cbq_size,
+          kLocationsToAwait);
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_1::GnssSvInfo> sv_info_vec;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec, kGnssSvInfoListTimeout);
+        for (uint32_t iSv = 0; iSv < sv_info_vec.size(); iSv++) {
+            const auto& gnss_sv = sv_info_vec[iSv];
+            EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                          source_to_blocklist_1.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+            EXPECT_FALSE((static_cast<GnssConstellationTypeAidl>(gnss_sv.v2_0.constellation) ==
+                          source_to_blocklist_2.constellation) &&
+                         (gnss_sv.v2_0.v1_0.svFlag & IGnssCallback_1_0::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clean up
+    StopAndClearLocations();
+    sources.resize(0);
+    status = gnss_configuration_hal->setBlocklist(sources);
+    ASSERT_TRUE(status.isOk());
+}
diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
index 1fe6c3e..0128df4 100644
--- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h
+++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
@@ -127,12 +127,13 @@
     std::atomic<long> mMinIntervalMs;
     sp<GnssConfiguration> mGnssConfiguration;
     std::atomic<bool> mIsActive;
-    std::atomic<bool> mHardwareModeOn;
+    std::atomic<bool> mHardwareModeChecked;
     std::atomic<int> mGnssFd;
     std::thread mThread;
 
     mutable std::mutex mMutex;
-    hidl_vec<GnssSvInfo> filterBlacklistedSatellitesV2_1(hidl_vec<GnssSvInfo> gnssSvInfoList);
+    virtual hidl_vec<GnssSvInfo> filterBlocklistedSatellitesV2_1(
+            hidl_vec<GnssSvInfo> gnssSvInfoList);
 };
 
 template <class T_IGnss>
@@ -148,7 +149,7 @@
 GnssTemplate<T_IGnss>::GnssTemplate()
     : mMinIntervalMs(1000),
       mGnssConfiguration{new GnssConfiguration()},
-      mHardwareModeOn(false),
+      mHardwareModeChecked(false),
       mGnssFd(-1) {}
 
 template <class T_IGnss>
@@ -159,16 +160,18 @@
 template <class T_IGnss>
 std::unique_ptr<V2_0::GnssLocation> GnssTemplate<T_IGnss>::getLocationFromHW() {
     char inputBuffer[INPUT_BUFFER_SIZE];
-    if (mGnssFd == -1) {
+    if (!mHardwareModeChecked) {
         mGnssFd = open(GNSS_PATH, O_RDWR | O_NONBLOCK);
+        if (mGnssFd == -1) {
+            ALOGW("Failed to open /dev/gnss0 errno: %d", errno);
+        }
+        mHardwareModeChecked = true;
     }
 
     if (mGnssFd == -1) {
-        ALOGW("Failed to open /dev/gnss0 errno: %d", errno);
         return nullptr;
     }
-    // Indicates it is a hardwareMode, don't report the default location.
-    mHardwareModeOn = true;
+
     int bytes_write = write(mGnssFd, CMD_GET_LOCATION, strlen(CMD_GET_LOCATION));
     if (bytes_write <= 0) {
         return nullptr;
@@ -206,14 +209,12 @@
     mIsActive = true;
     mThread = std::thread([this]() {
         while (mIsActive == true) {
-            auto svStatus = filterBlacklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
+            auto svStatus = filterBlocklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
             this->reportSvStatus(svStatus);
             auto currentLocation = getLocationFromHW();
-            if (mHardwareModeOn) {
-                if (currentLocation != nullptr) {
-                    // Only report location if the return from hardware is valid
-                    this->reportLocation(*currentLocation);
-                }
+            if (mGnssFd != -1 && currentLocation != nullptr) {
+                // Only report location if the return from hardware is valid
+                this->reportLocation(*currentLocation);
             } else {
                 if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) {
                     const auto location = Utils::getMockLocationV2_0();
@@ -230,8 +231,9 @@
 }
 
 template <class T_IGnss>
-hidl_vec<GnssSvInfo> GnssTemplate<T_IGnss>::filterBlacklistedSatellitesV2_1(
+hidl_vec<GnssSvInfo> GnssTemplate<T_IGnss>::filterBlocklistedSatellitesV2_1(
         hidl_vec<GnssSvInfo> gnssSvInfoList) {
+    ALOGD("filterBlocklistedSatellitesV2_1");
     for (uint32_t i = 0; i < gnssSvInfoList.size(); i++) {
         if (mGnssConfiguration->isBlacklistedV2_1(gnssSvInfoList[i])) {
             gnssSvInfoList[i].v2_0.v1_0.svFlag &=
diff --git a/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h b/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h
index d057c61..1439158 100644
--- a/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h
+++ b/gnss/common/utils/vts/include/v2_1/gnss_hal_test_template.h
@@ -119,7 +119,7 @@
      * SetUpGnssCallback:
      *   Set GnssCallback and verify the result.
      */
-    void SetUpGnssCallback();
+    virtual void SetUpGnssCallback();
 
     /*
      * StartAndCheckFirstLocation: