FR 45651 - GNSS SV/Constellation Control

Adding support for configuring GNSS SVs
and constellations to be used.

Change-Id: I47d5cd9d08ac9aaf633be2fe3b1bd152a2f4293b
CRs-Fixed: 2184871
diff --git a/sdm845/android/Gnss.cpp b/sdm845/android/Gnss.cpp
index 878cd20..d31a18b 100644
--- a/sdm845/android/Gnss.cpp
+++ b/sdm845/android/Gnss.cpp
@@ -234,6 +234,10 @@
             mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
             mPendingConfig.suplModeMask = gnssConfig.suplModeMask;
         }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+            mPendingConfig.blacklistedSvIds = gnssConfig.blacklistedSvIds;
+        }
     }
     return true;
 }
diff --git a/sdm845/android/GnssConfiguration.cpp b/sdm845/android/GnssConfiguration.cpp
index 9eeceac..cee928a 100644
--- a/sdm845/android/GnssConfiguration.cpp
+++ b/sdm845/android/GnssConfiguration.cpp
@@ -23,6 +23,7 @@
 #include <log_util.h>
 #include "Gnss.h"
 #include "GnssConfiguration.h"
+#include <android/hardware/gnss/1.0/types.h>
 
 namespace android {
 namespace hardware {
@@ -30,6 +31,8 @@
 namespace V1_1 {
 namespace implementation {
 
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+
 GnssConfiguration::GnssConfiguration(Gnss* gnss) : mGnss(gnss) {
 }
 
@@ -222,10 +225,60 @@
 
 // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
 Return<bool> GnssConfiguration::setBlacklist(
-            const hidl_vec<GnssConfiguration::BlacklistedSource>& /*blacklist*/) {
+            const hidl_vec<GnssConfiguration::BlacklistedSource>& blacklist) {
 
     ENTRY_LOG_CALLFLOW();
-    return true;
+    if (nullptr == mGnss) {
+        LOC_LOGe("mGnss is null");
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+    config.blacklistedSvIds.clear();
+
+    GnssSvIdSource source = {};
+    for (int idx = 0; idx < (int)blacklist.size(); idx++) {
+        setBlacklistedSource(source, blacklist[idx]);
+        config.blacklistedSvIds.push_back(source);
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+void GnssConfiguration::setBlacklistedSource(
+        GnssSvIdSource& copyToSource,
+        const GnssConfiguration::BlacklistedSource& copyFromSource) {
+
+    copyToSource.size = sizeof(GnssSvIdSource);
+
+    switch(copyFromSource.constellation) {
+    case GnssConstellationType::GPS:
+        copyToSource.constellation = GNSS_SV_TYPE_GPS;
+        break;
+    case GnssConstellationType::SBAS:
+        copyToSource.constellation = GNSS_SV_TYPE_SBAS;
+        break;
+    case GnssConstellationType::GLONASS:
+        copyToSource.constellation = GNSS_SV_TYPE_GLONASS;
+        break;
+    case GnssConstellationType::QZSS:
+        copyToSource.constellation = GNSS_SV_TYPE_QZSS;
+        break;
+    case GnssConstellationType::BEIDOU:
+        copyToSource.constellation = GNSS_SV_TYPE_BEIDOU;
+        break;
+    case GnssConstellationType::GALILEO:
+        copyToSource.constellation = GNSS_SV_TYPE_GALILEO;
+        break;
+    default:
+        copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
+        break;
+    }
+
+    copyToSource.svId = copyFromSource.svid;
 }
 
 }  // namespace implementation
diff --git a/sdm845/android/GnssConfiguration.h b/sdm845/android/GnssConfiguration.h
index f46f607..15ee290 100644
--- a/sdm845/android/GnssConfiguration.h
+++ b/sdm845/android/GnssConfiguration.h
@@ -64,6 +64,9 @@
 
  private:
     Gnss* mGnss = nullptr;
+    void setBlacklistedSource(
+            GnssSvIdSource& copyToSource,
+            const GnssConfiguration::BlacklistedSource& copyFromSource);
 };
 
 }  // namespace implementation
diff --git a/sdm845/core/LocAdapterBase.cpp b/sdm845/core/LocAdapterBase.cpp
index 6b5f75a..162b14b 100644
--- a/sdm845/core/LocAdapterBase.cpp
+++ b/sdm845/core/LocAdapterBase.cpp
@@ -161,4 +161,10 @@
     reportWwanZppFix(LocGpsLocation &/*zppLoc*/)
 DEFAULT_IMPL(false)
 
+void LocAdapterBase::reportGnssSvIdConfigEvent(const GnssSvIdConfig& /*config*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& /*config*/)
+DEFAULT_IMPL()
+
 } // namespace loc_core
diff --git a/sdm845/core/LocAdapterBase.h b/sdm845/core/LocAdapterBase.h
index 8e854f4..d08864d 100644
--- a/sdm845/core/LocAdapterBase.h
+++ b/sdm845/core/LocAdapterBase.h
@@ -153,6 +153,8 @@
     virtual void reportGnssMeasurementDataEvent(const GnssMeasurementsNotification& measurements,
                                                 int msInWeek);
     virtual bool reportWwanZppFix(LocGpsLocation &zppLoc);
+    virtual void reportGnssSvIdConfigEvent(const GnssSvIdConfig& config);
+    virtual void reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config);
 };
 
 } // namespace loc_core
diff --git a/sdm845/core/LocApiBase.cpp b/sdm845/core/LocApiBase.cpp
index f0af91f..01e8565 100644
--- a/sdm845/core/LocApiBase.cpp
+++ b/sdm845/core/LocApiBase.cpp
@@ -408,6 +408,28 @@
     TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssMeasurementDataEvent(measurements, msInWeek));
 }
 
+void LocApiBase::reportGnssSvIdConfig(const GnssSvIdConfig& config)
+{
+    // Print the config
+    LOC_LOGv("gloBlacklistSvMask: %" PRIu64 ", bdsBlacklistSvMask: %" PRIu64 ",\n"
+             "qzssBlacklistSvMask: %" PRIu64 ", galBlacklistSvMask: %" PRIu64,
+             config.gloBlacklistSvMask, config.bdsBlacklistSvMask,
+             config.qzssBlacklistSvMask, config.galBlacklistSvMask);
+
+    // Loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssSvIdConfigEvent(config));
+}
+
+void LocApiBase::reportGnssSvTypeConfig(const GnssSvTypeConfig& config)
+{
+    // Print the config
+    LOC_LOGv("blacklistedMask: %" PRIu64 ", enabledMask: %" PRIu64,
+             config.blacklistedSvTypesMask, config.enabledSvTypesMask);
+
+    // Loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssSvTypeConfigEvent(config));
+}
+
 enum loc_api_adapter_err LocApiBase::
    open(LOC_API_ADAPTER_EVENT_MASK_T /*mask*/)
 DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
@@ -606,4 +628,24 @@
     return ((mFeaturesSupported[arrayIndex] >> bitPos ) & 0x1);
 }
 
+LocationError LocApiBase::
+    setBlacklistSv(const GnssSvIdConfig& /*config*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+    getBlacklistSv()
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+    setConstellationControl(const GnssSvTypeConfig& /*config*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+    getConstellationControl()
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+    resetConstellationControl()
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
 } // namespace loc_core
diff --git a/sdm845/core/LocApiBase.h b/sdm845/core/LocApiBase.h
index d6b213b..042ef2c 100644
--- a/sdm845/core/LocApiBase.h
+++ b/sdm845/core/LocApiBase.h
@@ -134,6 +134,8 @@
     void reportGnssMeasurementData(GnssMeasurementsNotification& measurements, int msInWeek);
     void saveSupportedFeatureList(uint8_t *featureList);
     void reportWwanZppFix(LocGpsLocation &zppLoc);
+    void reportGnssSvIdConfig(const GnssSvIdConfig& config);
+    void reportGnssSvTypeConfig(const GnssSvTypeConfig& config);
 
     // downward calls
     // All below functions are to be defined by adapter specific modules:
@@ -256,6 +258,13 @@
        Check if a feature is supported
       */
     bool isFeatureSupported(uint8_t featureVal);
+
+    /* Requests for SV/Constellation Control */
+    virtual LocationError setBlacklistSv(const GnssSvIdConfig& config);
+    virtual LocationError getBlacklistSv();
+    virtual LocationError setConstellationControl(const GnssSvTypeConfig& config);
+    virtual LocationError getConstellationControl();
+    virtual LocationError resetConstellationControl();
 };
 
 typedef LocApiBase* (getLocApi_t)(const MsgTask* msgTask,
diff --git a/sdm845/gnss/GnssAdapter.cpp b/sdm845/gnss/GnssAdapter.cpp
index 2761543..bc1e111 100644
--- a/sdm845/gnss/GnssAdapter.cpp
+++ b/sdm845/gnss/GnssAdapter.cpp
@@ -72,6 +72,9 @@
     mControlCallbacks(),
     mPowerVoteId(0),
     mNmeaMask(0),
+    mGnssSvIdConfig(),
+    mGnssSvTypeConfig(),
+    mGnssSvTypeConfigCb(nullptr),
     mNiData(),
     mAgpsManager(),
     mAgpsCbInfo(),
@@ -894,6 +897,23 @@
                     errs[index++] = err;
                 }
             }
+            if (mConfig.flags & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) {
+                // Check if feature is supported
+                if (!mApi.isFeatureSupported(
+                        LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+                    LOC_LOGe("Feature constellation enablement not supported.");
+                    err = LOCATION_ERROR_NOT_SUPPORTED;
+                } else {
+                    // Send the SV ID Config to Modem
+                    err = mAdapter.gnssSvIdConfigUpdate(mConfig.blacklistedSvIds);
+                    if (LOCATION_ERROR_SUCCESS != err) {
+                        LOC_LOGe("Failed to send config to modem, err %d", err);
+                    }
+                }
+                if (index < mCount) {
+                    errs[index++] = err;
+                }
+            }
 
             mAdapter.reportResponse(index, errs, mIds);
             delete[] errs;
@@ -909,6 +929,516 @@
     return ids;
 }
 
+LocationError
+GnssAdapter::gnssSvIdConfigUpdate(const std::vector<GnssSvIdSource>& blacklistedSvIds)
+{
+    // Clear the existing config
+    memset(&mGnssSvIdConfig, 0, sizeof(GnssSvIdConfig));
+
+    // Convert the sv id lists to masks
+    convertToGnssSvIdConfig(blacklistedSvIds, mGnssSvIdConfig);
+
+    // Now send to Modem
+    return gnssSvIdConfigUpdate();
+}
+
+LocationError
+GnssAdapter::gnssSvIdConfigUpdate()
+{
+    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64,
+            mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+            mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask);
+
+    // Now set required blacklisted SVs
+    return mLocApi->setBlacklistSv(mGnssSvIdConfig);
+}
+
+uint32_t*
+GnssAdapter::gnssGetConfigCommand(GnssConfigFlagsMask configMask) {
+
+    // count the number of bits set
+    GnssConfigFlagsMask flagsCopy = configMask;
+    size_t count = 0;
+    while (flagsCopy > 0) {
+        if (flagsCopy & 1) {
+            count++;
+        }
+        flagsCopy >>= 1;
+    }
+    std::string idsString = "[";
+    uint32_t* ids = NULL;
+    if (count > 0) {
+        ids = new uint32_t[count];
+        if (nullptr == ids) {
+            LOC_LOGe("new allocation failed, fatal error.");
+            return nullptr;
+        }
+        for (size_t i=0; i < count; ++i) {
+            ids[i] = generateSessionId();
+            IF_LOC_LOGD {
+                idsString += std::to_string(ids[i]) + " ";
+            }
+        }
+    }
+    idsString += "]";
+
+    LOC_LOGd("ids %s flags 0x%X", idsString.c_str(), configMask);
+
+    struct MsgGnssGetConfig : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        GnssConfigFlagsMask mConfigMask;
+        uint32_t* mIds;
+        size_t mCount;
+        inline MsgGnssGetConfig(GnssAdapter& adapter,
+                                LocApiBase& api,
+                                GnssConfigFlagsMask configMask,
+                                uint32_t* ids,
+                                size_t count) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mConfigMask(configMask),
+            mIds(ids),
+            mCount(count) {}
+        inline virtual ~MsgGnssGetConfig()
+        {
+            delete[] mIds;
+        }
+        inline virtual void proc() const {
+
+            LocationError* errs = new LocationError[mCount];
+            LocationError err = LOCATION_ERROR_SUCCESS;
+            uint32_t index = 0;
+
+            if (nullptr == errs) {
+                LOC_LOGE("%s] new allocation failed, fatal error.", __func__);
+                return;
+            }
+
+            if (mConfigMask & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+                err = LOCATION_ERROR_NOT_SUPPORTED;
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) {
+                // Check if feature is supported
+                if (!mApi.isFeatureSupported(
+                        LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+                    LOC_LOGe("Feature not supported.");
+                    err = LOCATION_ERROR_NOT_SUPPORTED;
+                } else {
+                    // Send request to Modem to fetch the config
+                    err = mApi.getBlacklistSv();
+                    if (LOCATION_ERROR_SUCCESS != err) {
+                        LOC_LOGe("getConfig request to modem failed, err %d", err);
+                    }
+                }
+                if (index < mCount) {
+                    errs[index++] = err;
+                }
+            }
+
+            mAdapter.reportResponse(index, errs, mIds);
+            delete[] errs;
+        }
+    };
+
+    if (NULL != ids) {
+        sendMsg(new MsgGnssGetConfig(*this, *mLocApi, configMask, ids, count));
+    } else {
+        LOC_LOGe("No GNSS config items to Get");
+    }
+
+    return ids;
+}
+
+void
+GnssAdapter::convertToGnssSvIdConfig(
+        const std::vector<GnssSvIdSource>& blacklistedSvIds, GnssSvIdConfig& config)
+{
+    config.size = sizeof(GnssSvIdConfig);
+
+    // Empty vector => Clear any previous blacklisted SVs
+    if (0 == blacklistedSvIds.size()) {
+        config.gloBlacklistSvMask = 0;
+        config.bdsBlacklistSvMask = 0;
+        config.qzssBlacklistSvMask = 0;
+        config.galBlacklistSvMask = 0;
+    } else {
+        // Parse the vector and convert SV IDs to mask values
+        for (GnssSvIdSource source : blacklistedSvIds) {
+            uint64_t* svMaskPtr = NULL;
+            GnssSvId initialSvId = 0;
+            switch(source.constellation) {
+            case GNSS_SV_TYPE_GLONASS:
+                svMaskPtr = &config.gloBlacklistSvMask;
+                initialSvId = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID;
+                break;
+            case GNSS_SV_TYPE_BEIDOU:
+                svMaskPtr = &config.bdsBlacklistSvMask;
+                initialSvId = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID;
+                break;
+            case GNSS_SV_TYPE_QZSS:
+                svMaskPtr = &config.qzssBlacklistSvMask;
+                initialSvId = GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID;
+                break;
+            case GNSS_SV_TYPE_GALILEO:
+                svMaskPtr = &config.galBlacklistSvMask;
+                initialSvId = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID;
+                break;
+            default:
+                break;
+            }
+
+            if (NULL == svMaskPtr) {
+                LOC_LOGe("Invalid constellation %d", source.constellation);
+            } else {
+                // SV ID 0 = All SV IDs
+                if (0 == source.svId) {
+                    *svMaskPtr = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+                } else if (source.svId < initialSvId || source.svId >= initialSvId + 64) {
+                    LOC_LOGe("Invalid sv id %d for sv type %d",
+                            source.svId, source.constellation);
+                } else {
+                    *svMaskPtr |= (1 << (source.svId - initialSvId));
+                }
+            }
+        }
+    }
+}
+
+void GnssAdapter::convertFromGnssSvIdConfig(
+        const GnssSvIdConfig& svConfig, GnssConfig& config)
+{
+    // Convert blacklisted SV mask values to vectors
+    if (svConfig.bdsBlacklistSvMask) {
+        convertGnssSvIdMaskToList(
+                svConfig.bdsBlacklistSvMask, config.blacklistedSvIds,
+                GNSS_SV_CONFIG_BDS_INITIAL_SV_ID, GNSS_SV_TYPE_BEIDOU);
+        config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+    }
+    if (svConfig.galBlacklistSvMask) {
+        convertGnssSvIdMaskToList(
+                svConfig.galBlacklistSvMask, config.blacklistedSvIds,
+                GNSS_SV_CONFIG_GAL_INITIAL_SV_ID, GNSS_SV_TYPE_GALILEO);
+        config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+    }
+    if (svConfig.gloBlacklistSvMask) {
+        convertGnssSvIdMaskToList(
+                svConfig.gloBlacklistSvMask, config.blacklistedSvIds,
+                GNSS_SV_CONFIG_GLO_INITIAL_SV_ID, GNSS_SV_TYPE_GLONASS);
+        config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+    }
+    if (svConfig.qzssBlacklistSvMask) {
+        convertGnssSvIdMaskToList(
+                svConfig.qzssBlacklistSvMask, config.blacklistedSvIds,
+                GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID, GNSS_SV_TYPE_QZSS);
+        config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+    }
+}
+
+void GnssAdapter::convertGnssSvIdMaskToList(
+        uint64_t svIdMask, std::vector<GnssSvIdSource>& svIds,
+        GnssSvId initialSvId, GnssSvType svType)
+{
+    GnssSvIdSource source = {};
+    source.size = sizeof(GnssSvIdSource);
+    source.constellation = svType;
+
+    // SV ID 0 => All SV IDs in mask
+    if (GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK == svIdMask) {
+        source.svId = 0;
+        svIds.push_back(source);
+        return;
+    }
+
+    // Convert each bit in svIdMask to vector entry
+    uint32_t bitNumber = 0;
+    while (svIdMask > 0) {
+        if (svIdMask & 0x1) {
+            source.svId = bitNumber + initialSvId;
+            svIds.push_back(source);
+        }
+        bitNumber++;
+        svIdMask >>= 1;
+    }
+}
+
+void GnssAdapter::reportGnssSvIdConfigEvent(const GnssSvIdConfig& config)
+{
+    struct MsgReportGnssSvIdConfig : public LocMsg {
+        GnssAdapter& mAdapter;
+        const GnssSvIdConfig mConfig;
+        inline MsgReportGnssSvIdConfig(GnssAdapter& adapter,
+                                 const GnssSvIdConfig& config) :
+            LocMsg(),
+            mAdapter(adapter),
+            mConfig(config) {}
+        inline virtual void proc() const {
+            mAdapter.reportGnssSvIdConfig(mConfig);
+        }
+    };
+
+    sendMsg(new MsgReportGnssSvIdConfig(*this, config));
+}
+
+void GnssAdapter::reportGnssSvIdConfig(const GnssSvIdConfig& svIdConfig)
+{
+    GnssConfig config = {};
+    config.size = sizeof(GnssConfig);
+
+    // Invoke control clients config callback
+    if (nullptr != mControlCallbacks.gnssConfigCb &&
+            svIdConfig.size == sizeof(GnssSvIdConfig)) {
+        convertFromGnssSvIdConfig(svIdConfig, config);
+        LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+                ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64,
+                svIdConfig.bdsBlacklistSvMask, svIdConfig.gloBlacklistSvMask,
+                svIdConfig.qzssBlacklistSvMask, svIdConfig.galBlacklistSvMask);
+        mControlCallbacks.gnssConfigCb(config);
+    } else {
+        LOC_LOGe("Failed to report, size %d", (uint32_t)config.size);
+    }
+}
+
+void
+GnssAdapter::gnssUpdateSvTypeConfigCommand(GnssSvTypeConfig config)
+{
+    struct MsgGnssUpdateSvTypeConfig : public LocMsg {
+        GnssAdapter* mAdapter;
+        LocApiBase* mApi;
+        GnssSvTypeConfig mConfig;
+        inline MsgGnssUpdateSvTypeConfig(
+                GnssAdapter* adapter,
+                LocApiBase* api,
+                GnssSvTypeConfig& config) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mConfig(config) {}
+        inline virtual void proc() const {
+            // Check if feature is supported
+            if (!mApi->isFeatureSupported(
+                    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+                LOC_LOGe("Feature not supported.");
+            } else {
+                // Send update request to modem
+                LocationError err = mAdapter->gnssSvTypeConfigUpdate(mConfig);
+                if (err != LOCATION_ERROR_SUCCESS) {
+                    LOC_LOGe("Set constellation request failed, err %d", err);
+                }
+            }
+        }
+    };
+
+    sendMsg(new MsgGnssUpdateSvTypeConfig(this, mLocApi, config));
+}
+
+LocationError
+GnssAdapter::gnssSvTypeConfigUpdate(const GnssSvTypeConfig& config)
+{
+    gnssSetSvTypeConfig(config);
+    return gnssSvTypeConfigUpdate();
+}
+
+LocationError
+GnssAdapter::gnssSvTypeConfigUpdate()
+{
+    LocationError err = LOCATION_ERROR_GENERAL_FAILURE;
+    LOC_LOGd("constellations blacklisted 0x%" PRIx64 ", enabled 0x%" PRIx64,
+             mGnssSvTypeConfig.blacklistedSvTypesMask, mGnssSvTypeConfig.enabledSvTypesMask);
+
+    if (mGnssSvTypeConfig.size == sizeof(mGnssSvTypeConfig)) {
+        GnssSvIdConfig blacklistConfig = {};
+        // Revert to previously blacklisted SVs for each enabled constellation
+        blacklistConfig = mGnssSvIdConfig;
+        // Blacklist all SVs for each disabled constellation
+        if (mGnssSvTypeConfig.blacklistedSvTypesMask) {
+            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_GLO_BIT) {
+                blacklistConfig.gloBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+            }
+            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_BDS_BIT) {
+                blacklistConfig.bdsBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+            }
+            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_QZSS_BIT) {
+                blacklistConfig.qzssBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+            }
+            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_GAL_BIT) {
+                blacklistConfig.galBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+            }
+        }
+
+        // Send blacklist info
+        err = mLocApi->setBlacklistSv(blacklistConfig);
+        if (LOCATION_ERROR_SUCCESS != err) {
+            LOC_LOGE("Failed to send Set Blacklist");
+        }
+        // Send only enabled constellation config
+        if (mGnssSvTypeConfig.enabledSvTypesMask) {
+            GnssSvTypeConfig svTypeConfig = {sizeof(GnssSvTypeConfig), 0, 0};
+            svTypeConfig.enabledSvTypesMask = mGnssSvTypeConfig.enabledSvTypesMask;
+            err = mLocApi->setConstellationControl(svTypeConfig);
+            if (LOCATION_ERROR_SUCCESS != err) {
+                LOC_LOGE("Failed to send Set Constellation");
+            }
+        }
+    } else {
+        LOC_LOGE("Invalid GnssSvTypeConfig size");
+        err = LOCATION_ERROR_SUCCESS;
+    }
+
+    return err;
+}
+
+void
+GnssAdapter::gnssGetSvTypeConfigCommand(GnssSvTypeConfigCallback callback)
+{
+    struct MsgGnssGetSvTypeConfig : public LocMsg {
+        GnssAdapter* mAdapter;
+        LocApiBase* mApi;
+        GnssSvTypeConfigCallback mCallback;
+        inline MsgGnssGetSvTypeConfig(
+                GnssAdapter* adapter,
+                LocApiBase* api,
+                GnssSvTypeConfigCallback callback) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mCallback(callback) {}
+        inline virtual void proc() const {
+            if (!mApi->isFeatureSupported(
+                    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+                LOC_LOGe("Feature not supported.");
+            } else {
+                // Save the callback
+                mAdapter->gnssSetSvTypeConfigCallback(mCallback);
+                // Send GET request to modem
+                LocationError err = mApi->getConstellationControl();
+                if (err != LOCATION_ERROR_SUCCESS) {
+                    LOC_LOGe("Get constellation request failed, err %d", err);
+                }
+            }
+        }
+    };
+
+    sendMsg(new MsgGnssGetSvTypeConfig(this, mLocApi, callback));
+}
+
+void
+GnssAdapter::gnssResetSvTypeConfigCommand()
+{
+    struct MsgGnssResetSvTypeConfig : public LocMsg {
+        GnssAdapter* mAdapter;
+        LocApiBase* mApi;
+        inline MsgGnssResetSvTypeConfig(
+                GnssAdapter* adapter,
+                LocApiBase* api) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api) {}
+        inline virtual void proc() const {
+            if (!mApi->isFeatureSupported(
+                    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+                LOC_LOGe("Feature not supported.");
+            } else {
+                // Reset constellation config
+                mAdapter->gnssSetSvTypeConfig({sizeof(GnssSvTypeConfig), 0, 0});
+                // Re-enforce SV blacklist config
+                LocationError err = mAdapter->gnssSvIdConfigUpdate();
+                if (err != LOCATION_ERROR_SUCCESS) {
+                    LOC_LOGe("SV Config request failed, err %d", err);
+                }
+                // Send reset request to modem
+                err = mApi->resetConstellationControl();
+                if (err != LOCATION_ERROR_SUCCESS) {
+                    LOC_LOGe("Reset constellation request failed, err %d", err);
+                }
+            }
+        }
+    };
+
+    sendMsg(new MsgGnssResetSvTypeConfig(this, mLocApi));
+}
+
+void GnssAdapter::reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config)
+{
+    struct MsgReportGnssSvTypeConfig : public LocMsg {
+        GnssAdapter& mAdapter;
+        const GnssSvTypeConfig mConfig;
+        inline MsgReportGnssSvTypeConfig(GnssAdapter& adapter,
+                                 const GnssSvTypeConfig& config) :
+            LocMsg(),
+            mAdapter(adapter),
+            mConfig(config) {}
+        inline virtual void proc() const {
+            mAdapter.reportGnssSvTypeConfig(mConfig);
+        }
+    };
+
+    sendMsg(new MsgReportGnssSvTypeConfig(*this, config));
+}
+
+void GnssAdapter::reportGnssSvTypeConfig(const GnssSvTypeConfig& config)
+{
+    // Invoke Get SV Type Callback
+    if (NULL != mGnssSvTypeConfigCb &&
+            config.size == sizeof(GnssSvTypeConfig)) {
+        LOC_LOGd("constellations blacklisted 0x%" PRIx64 ", enabled 0x%" PRIx64,
+                 config.blacklistedSvTypesMask, config.enabledSvTypesMask);
+        mGnssSvTypeConfigCb(config);
+    } else {
+        LOC_LOGe("Failed to report, size %d", (uint32_t)config.size);
+    }
+}
+
 uint32_t
 GnssAdapter::gnssDeleteAidingDataCommand(GnssAidingData& data)
 {
@@ -1140,7 +1670,6 @@
         }
         ++it; // increment only when not erasing an iterator
     }
-
 }
 
 void
@@ -1193,6 +1722,8 @@
             mAdapter(adapter) {}
         virtual void proc() const {
             mAdapter.restartSessions();
+            mAdapter.gnssSvIdConfigUpdate();
+            mAdapter.gnssSvTypeConfigUpdate();
         }
     };
 
diff --git a/sdm845/gnss/GnssAdapter.h b/sdm845/gnss/GnssAdapter.h
index 7f4986f..580c7cd 100644
--- a/sdm845/gnss/GnssAdapter.h
+++ b/sdm845/gnss/GnssAdapter.h
@@ -94,10 +94,13 @@
     GnssSvUsedInPosition mGnssSvIdUsedInPosition;
     bool mGnssSvIdUsedInPosAvail;
 
-    /* ==== CONTROL ======================================================================== */
+    /* ==== CONTROL ================================================================= */
     LocationControlCallbacks mControlCallbacks;
     uint32_t mPowerVoteId;
     uint32_t mNmeaMask;
+    GnssSvIdConfig mGnssSvIdConfig;
+    GnssSvTypeConfig mGnssSvTypeConfig;
+    GnssSvTypeConfigCallback mGnssSvTypeConfigCb;
 
     /* ==== NI ============================================================================= */
     NiData mNiData;
@@ -191,7 +194,7 @@
     bool hasNiNotifyCallback(LocationAPI* client);
     NiData& getNiData() { return mNiData; }
 
-    /* ==== CONTROL ======================================================================== */
+    /* ==== CONTROL CLIENT ================================================================= */
     /* ======== COMMANDS ====(Called from Client Thread)==================================== */
     uint32_t enableCommand(LocationTechnologyType techType);
     void disableCommand(uint32_t id);
@@ -199,9 +202,31 @@
     void readConfigCommand();
     void setConfigCommand();
     uint32_t* gnssUpdateConfigCommand(GnssConfig config);
+    uint32_t* gnssGetConfigCommand(GnssConfigFlagsMask mask);
     uint32_t gnssDeleteAidingDataCommand(GnssAidingData& data);
     void gnssUpdateXtraThrottleCommand(const bool enabled);
 
+    /* ==== GNSS SV TYPE CONFIG ============================================================ */
+    /* ==== COMMANDS ====(Called from Client Thread)======================================== */
+    /* ==== These commands are received directly from client bypassing Location API ======== */
+    void gnssUpdateSvTypeConfigCommand(GnssSvTypeConfig config);
+    void gnssGetSvTypeConfigCommand(GnssSvTypeConfigCallback callback);
+    void gnssResetSvTypeConfigCommand();
+
+    /* ==== UTILITIES ====================================================================== */
+    LocationError gnssSvIdConfigUpdate(const std::vector<GnssSvIdSource>& blacklistedSvIds);
+    LocationError gnssSvIdConfigUpdate();
+    LocationError gnssSvTypeConfigUpdate(const GnssSvTypeConfig& config);
+    LocationError gnssSvTypeConfigUpdate();
+    inline void gnssSetSvTypeConfig(const GnssSvTypeConfig& config)
+    { mGnssSvTypeConfig = config; }
+    inline void gnssSetSvTypeConfigCallback(GnssSvTypeConfigCallback callback)
+    { mGnssSvTypeConfigCb = callback; }
+    inline GnssSvTypeConfigCallback gnssGetSvTypeConfigCallback()
+    { return mGnssSvTypeConfigCb; }
+
+    /* ==== AGPS =========================================================================== */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
     void initDefaultAgpsCommand();
     void initAgpsCommand(const AgpsCbInfo& cbInfo);
     void dataConnOpenCommand(AGpsExtType agpsType,
@@ -236,6 +261,8 @@
                                                 int msInWeek);
     virtual void reportSvMeasurementEvent(GnssSvMeasurementSet &svMeasurementSet);
     virtual void reportSvPolynomialEvent(GnssSvPolynomial &svPolynomial);
+    virtual void reportGnssSvIdConfigEvent(const GnssSvIdConfig& config);
+    virtual void reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config);
 
     virtual bool requestATL(int connHandle, LocAGpsType agps_type, LocApnTypeMask mask);
     virtual bool releaseATL(int connHandle);
@@ -254,6 +281,8 @@
     void reportNmea(const char* nmea, size_t length);
     bool requestNiNotify(const GnssNiNotification& notify, const void* data);
     void reportGnssMeasurementData(const GnssMeasurementsNotification& measurements);
+    void reportGnssSvIdConfig(const GnssSvIdConfig& config);
+    void reportGnssSvTypeConfig(const GnssSvTypeConfig& config);
 
     /*======== GNSSDEBUG ================================================================*/
     bool getDebugReport(GnssDebugReport& report);
@@ -283,6 +312,13 @@
     static void convertSatelliteInfo(std::vector<GnssDebugSatelliteInfo>& out,
                                      const GnssSvType& in_constellation,
                                      const SystemStatusReports& in);
+    static void convertToGnssSvIdConfig(
+            const std::vector<GnssSvIdSource>& blacklistedSvIds, GnssSvIdConfig& config);
+    static void convertFromGnssSvIdConfig(
+            const GnssSvIdConfig& svConfig, GnssConfig& config);
+    static void convertGnssSvIdMaskToList(
+            uint64_t svIdMask, std::vector<GnssSvIdSource>& svIds,
+            GnssSvId initialSvId, GnssSvType svType);
 
     void injectLocationCommand(double latitude, double longitude, float accuracy);
     void injectTimeCommand(int64_t time, int64_t timeReference, int32_t uncertainty);
diff --git a/sdm845/gnss/location_gnss.cpp b/sdm845/gnss/location_gnss.cpp
index 3e989c9..0dac13d 100644
--- a/sdm845/gnss/location_gnss.cpp
+++ b/sdm845/gnss/location_gnss.cpp
@@ -51,6 +51,11 @@
 static uint32_t enable(LocationTechnologyType techType);
 static void disable(uint32_t id);
 static uint32_t* gnssUpdateConfig(GnssConfig config);
+static uint32_t* gnssGetConfig(GnssConfigFlagsMask mask);
+
+static void gnssUpdateSvTypeConfig(GnssSvTypeConfig& config);
+static void gnssGetSvTypeConfig(GnssSvTypeConfigCallback& callback);
+static void gnssResetSvTypeConfig();
 
 static void injectLocation(double latitude, double longitude, float accuracy);
 static void injectTime(int64_t time, int64_t timeReference, int32_t uncertainty);
@@ -77,6 +82,10 @@
     enable,
     disable,
     gnssUpdateConfig,
+    gnssGetConfig,
+    gnssUpdateSvTypeConfig,
+    gnssGetSvTypeConfig,
+    gnssResetSvTypeConfig,
     gnssDeleteAidingData,
     gnssUpdateXtraThrottle,
     injectLocation,
@@ -167,7 +176,7 @@
 static void setControlCallbacks(LocationControlCallbacks& controlCallbacks)
 {
     if (NULL != gGnssAdapter) {
-        return gGnssAdapter->setControlCallbacksCommand(controlCallbacks);
+        gGnssAdapter->setControlCallbacksCommand(controlCallbacks);
     }
 }
 
@@ -183,7 +192,7 @@
 static void disable(uint32_t id)
 {
     if (NULL != gGnssAdapter) {
-        return gGnssAdapter->disableCommand(id);
+        gGnssAdapter->disableCommand(id);
     }
 }
 
@@ -196,6 +205,36 @@
     }
 }
 
+static uint32_t* gnssGetConfig(GnssConfigFlagsMask mask)
+{
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->gnssGetConfigCommand(mask);
+    } else {
+        return NULL;
+    }
+}
+
+static void gnssUpdateSvTypeConfig(GnssSvTypeConfig& config)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->gnssUpdateSvTypeConfigCommand(config);
+    }
+}
+
+static void gnssGetSvTypeConfig(GnssSvTypeConfigCallback& callback)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->gnssGetSvTypeConfigCommand(callback);
+    }
+}
+
+static void gnssResetSvTypeConfig()
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->gnssResetSvTypeConfigCommand();
+    }
+}
+
 static uint32_t gnssDeleteAidingData(GnssAidingData& data)
 {
     if (NULL != gGnssAdapter) {
diff --git a/sdm845/location/LocationAPI.cpp b/sdm845/location/LocationAPI.cpp
index 0111a9c..6bd5b15 100644
--- a/sdm845/location/LocationAPI.cpp
+++ b/sdm845/location/LocationAPI.cpp
@@ -627,6 +627,21 @@
     return ids;
 }
 
+uint32_t* LocationControlAPI::gnssGetConfig(GnssConfigFlagsMask mask) {
+
+    uint32_t* ids = NULL;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (NULL != gData.gnssInterface) {
+        ids = gData.gnssInterface->gnssGetConfig(mask);
+    } else {
+        LOC_LOGe("No gnss interface available for Control API client %p", this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return ids;
+}
+
 uint32_t
 LocationControlAPI::gnssDeleteAidingData(GnssAidingData& data)
 {
diff --git a/sdm845/location/LocationAPI.h b/sdm845/location/LocationAPI.h
index 530b1b0..de18031 100644
--- a/sdm845/location/LocationAPI.h
+++ b/sdm845/location/LocationAPI.h
@@ -229,6 +229,7 @@
     GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT         = (1<<7),
     GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT                 = (1<<8),
     GNSS_CONFIG_FLAGS_SUPL_MODE_BIT                        = (1<<9),
+    GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT               = (1<<10)
 } GnssConfigFlagsBits;
 
 typedef enum {
@@ -537,12 +538,22 @@
     GnssSvOptionsMask gnssSvOptionsMask; // Bitwise OR of GnssSvOptionsBits
 } GnssSv;
 
-typedef struct {
+struct GnssConfigSetAssistanceServer {
     size_t size;             // set to sizeof(GnssConfigSetAssistanceServer)
     GnssAssistanceType type; // SUPL or C2K
     const char* hostName;    // null terminated string
     uint32_t port;           // port of server
-} GnssConfigSetAssistanceServer;
+
+    inline bool equals(const GnssConfigSetAssistanceServer& config) {
+        if (config.type == type && config.port == port &&
+               ((NULL == config.hostName && NULL == hostName) ||
+                (NULL != config.hostName && NULL != hostName &&
+                     0 == strcmp(config.hostName, hostName)))) {
+            return true;
+        }
+        return false;
+    }
+};
 
 typedef struct {
     size_t size;                               // set to sizeof(GnssMeasurementsData)
@@ -602,7 +613,40 @@
     GnssMeasurementsClock clock; // clock
 } GnssMeasurementsNotification;
 
+typedef uint32_t GnssSvId;
+
+struct GnssSvIdSource{
+    size_t size;                 // set to sizeof(GnssSvIdSource)
+    GnssSvType constellation;    // constellation for the sv to blacklist
+    GnssSvId svId;           // sv id to blacklist
+};
+inline bool operator ==(GnssSvIdSource const& left, GnssSvIdSource const& right) {
+    return left.size == right.size &&
+            left.constellation == right.constellation && left.svId == right.svId;
+}
+
+#define GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK ((uint64_t)0xFFFFFFFFFFFFFFFF)
 typedef struct {
+    size_t size; // set to sizeof(GnssSvIdConfig)
+
+    // GLONASS - SV 65 maps to bit 0
+#define GNSS_SV_CONFIG_GLO_INITIAL_SV_ID 65
+    uint64_t gloBlacklistSvMask;
+
+    // BEIDOU - SV 201 maps to bit 0
+#define GNSS_SV_CONFIG_BDS_INITIAL_SV_ID 201
+    uint64_t bdsBlacklistSvMask;
+
+    // QZSS - SV 193 maps to bit 0
+#define GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID 193
+    uint64_t qzssBlacklistSvMask;
+
+    // GAL - SV 301 maps to bit 0
+#define GNSS_SV_CONFIG_GAL_INITIAL_SV_ID 301
+    uint64_t galBlacklistSvMask;
+} GnssSvIdConfig;
+
+struct GnssConfig{
     size_t size;  // set to sizeof(GnssConfig)
     GnssConfigFlagsMask flags; // bitwise OR of GnssConfigFlagsBits to mark which params are valid
     GnssConfigGpsLock gpsLock;
@@ -615,7 +659,26 @@
     GnssConfigEmergencyPdnForEmergencySupl emergencyPdnForEmergencySupl;
     GnssConfigSuplEmergencyServices suplEmergencyServices;
     GnssConfigSuplModeMask suplModeMask; //bitwise OR of GnssConfigSuplModeBits
-} GnssConfig;
+    std::vector<GnssSvIdSource> blacklistedSvIds;
+
+    inline bool equals(const GnssConfig& config) {
+        if (flags == config.flags &&
+                gpsLock == config.gpsLock &&
+                suplVersion == config.suplVersion &&
+                assistanceServer.equals(config.assistanceServer) &&
+                lppProfile == config.lppProfile &&
+                lppeControlPlaneMask == config.lppeControlPlaneMask &&
+                lppeUserPlaneMask == config.lppeUserPlaneMask &&
+                aGlonassPositionProtocolMask == config.aGlonassPositionProtocolMask &&
+                emergencyPdnForEmergencySupl == config.emergencyPdnForEmergencySupl &&
+                suplEmergencyServices == config.suplEmergencyServices &&
+                suplModeMask == config.suplModeMask  &&
+                blacklistedSvIds == config.blacklistedSvIds) {
+            return true;
+        }
+        return false;
+    }
+};
 
 typedef struct {
     size_t size;                        // set to sizeof
@@ -744,6 +807,11 @@
     GnssMeasurementsNotification gnssMeasurementsNotification
 )> gnssMeasurementsCallback;
 
+/* Provides the current GNSS configuration to the client */
+typedef std::function<void(
+    GnssConfig& config
+)> gnssConfigCallback;
+
 typedef struct {
     size_t size; // set to sizeof(LocationCallbacks)
     capabilitiesCallback capabilitiesCb;             // mandatory
@@ -908,6 +976,7 @@
     size_t size; // set to sizeof(LocationControlCallbacks)
     responseCallback responseCb;                     // mandatory
     collectiveResponseCallback collectiveResponseCb; // mandatory
+    gnssConfigCallback gnssConfigCb;                 // optional
 } LocationControlCallbacks;
 
 class LocationControlAPI
@@ -961,6 +1030,21 @@
                 LOCATION_ERROR_GENERAL_FAILURE if failure for any other reason */
     uint32_t* gnssUpdateConfig(GnssConfig config);
 
+    /* gnssGetConfig fetches the current constellation and SV configuration
+       on the GNSS engine.
+       Returns a session id array with an id for each of the bits set in
+       the mask parameter, order from low bits to high bits.
+       Response is sent via the registered gnssConfigCallback.
+       This effect is global for all clients of LocationAPI
+       collectiveResponseCallback returns:
+           LOCATION_ERROR_SUCCESS if session was successful
+           LOCATION_ERROR_INVALID_PARAMETER if any parameter is invalid
+           LOCATION_ERROR_CALLBACK_MISSING If no gnssConfigCallback
+                                           was passed in createInstance
+           LOCATION_ERROR_NOT_SUPPORTED If read of requested configuration
+                                        is not supported */
+    uint32_t* gnssGetConfig(GnssConfigFlagsMask mask);
+
     /* delete specific gnss aiding data for testing, which returns a session id
        that will be returned in responseCallback to match command with response.
        Only allowed in userdebug builds. This effect is global for all clients of LocationAPI
diff --git a/sdm845/location/LocationAPIClientBase.cpp b/sdm845/location/LocationAPIClientBase.cpp
index 626968c..65a0984 100644
--- a/sdm845/location/LocationAPIClientBase.cpp
+++ b/sdm845/location/LocationAPIClientBase.cpp
@@ -26,7 +26,7 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#define LOG_NDDEBUG 0
+#define LOG_NDEBUG 0
 #define LOG_TAG "LocSvc_APIClientBase"
 
 #include <loc_pla.h>
@@ -45,7 +45,7 @@
     pthread_mutex_init(&mMutex, nullptr);
 
     for (int i = 0; i < CTRL_REQUEST_MAX; i++) {
-        mRequestQueues[i].reset(0);
+        mRequestQueues[i].reset((uint32_t)0);
     }
 
     memset(&mConfig, 0, sizeof(GnssConfig));
@@ -75,7 +75,7 @@
     }
 
     for (int i = 0; i < CTRL_REQUEST_MAX; i++) {
-        mRequestQueues[i].reset(0);
+        mRequestQueues[i].reset((uint32_t)0);
     }
 
     pthread_mutex_unlock(&mMutex);
@@ -142,24 +142,43 @@
 uint32_t LocationAPIControlClient::locAPIGnssUpdateConfig(GnssConfig config)
 {
     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
-    if (memcmp(&mConfig, &config, sizeof(GnssConfig)) == 0) {
-        LOC_LOGV("%s:%d] GnssConfig is identical to previous call", __FUNCTION__, __LINE__);
-        retVal = LOCATION_ERROR_SUCCESS;
-        return retVal;
+
+    pthread_mutex_lock(&mMutex);
+    if (mLocationControlAPI) {
+        if (mConfig.equals(config)) {
+            LOC_LOGv("GnssConfig is identical to previous call");
+            retVal = LOCATION_ERROR_SUCCESS;
+        } else {
+            mConfig = config;
+            uint32_t* idArray = mLocationControlAPI->gnssUpdateConfig(config);
+            LOC_LOGv("gnssUpdateConfig return array: %p", idArray);
+            if (nullptr != idArray) {
+                if (nullptr != mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].getSessionArrayPtr()) {
+                    mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].reset(idArray);
+                }
+                mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].push(new GnssUpdateConfigRequest(*this));
+                retVal = LOCATION_ERROR_SUCCESS;
+            }
+        }
     }
+    pthread_mutex_unlock(&mMutex);
+    return retVal;
+}
+
+uint32_t LocationAPIControlClient::locAPIGnssGetConfig(GnssConfigFlagsMask mask)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
 
     pthread_mutex_lock(&mMutex);
     if (mLocationControlAPI) {
 
-        memcpy(&mConfig, &config, sizeof(GnssConfig));
-
-        uint32_t* idArray = mLocationControlAPI->gnssUpdateConfig(config);
-        LOC_LOGV("%s:%d] gnssUpdateConfig return array: %p", __FUNCTION__, __LINE__, idArray);
-        if (idArray != nullptr) {
-            if (mRequestQueues[CTRL_REQUEST_CONFIG].getSession() != CONFIG_SESSION_ID) {
-                mRequestQueues[CTRL_REQUEST_CONFIG].reset(CONFIG_SESSION_ID);
+        uint32_t* idArray = mLocationControlAPI->gnssGetConfig(mask);
+        LOC_LOGv("gnssGetConfig return array: %p", idArray);
+        if (nullptr != idArray) {
+            if (nullptr != mRequestQueues[CTRL_REQUEST_CONFIG_GET].getSessionArrayPtr()) {
+                mRequestQueues[CTRL_REQUEST_CONFIG_GET].reset(idArray);
             }
-            mRequestQueues[CTRL_REQUEST_CONFIG].push(new GnssUpdateConfigRequest(*this));
+            mRequestQueues[CTRL_REQUEST_CONFIG_GET].push(new GnssGetConfigRequest(*this));
             retVal = LOCATION_ERROR_SUCCESS;
         }
     }
@@ -191,12 +210,7 @@
             LOC_LOGV("%s:%d] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
         }
     }
-    LocationAPIRequest* request = nullptr;
-    pthread_mutex_lock(&mMutex);
-    if (mRequestQueues[CTRL_REQUEST_CONFIG].getSession() == CONFIG_SESSION_ID) {
-        request = mRequestQueues[CTRL_REQUEST_CONFIG].pop();
-    }
-    pthread_mutex_unlock(&mMutex);
+    LocationAPIRequest* request = getRequestBySessionArrayPtr(ids);
     if (request) {
         request->onCollectiveResponse(count, errors, ids);
         delete request;
@@ -207,13 +221,30 @@
 {
     pthread_mutex_lock(&mMutex);
     LocationAPIRequest* request = nullptr;
-    for (int i = 0; i < CTRL_REQUEST_MAX; i++) {
-        if (i != CTRL_REQUEST_CONFIG &&
-                mRequestQueues[i].getSession() == session) {
-            request = mRequestQueues[i].pop();
-            break;
-        }
+
+    if (mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].getSession() == session) {
+        request = mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].pop();
+    } else if (mRequestQueues[CTRL_REQUEST_CONTROL].getSession() == session) {
+        request = mRequestQueues[CTRL_REQUEST_CONTROL].pop();
     }
+
+    pthread_mutex_unlock(&mMutex);
+    return request;
+}
+
+LocationAPIRequest*
+LocationAPIControlClient::getRequestBySessionArrayPtr(
+        uint32_t* sessionArrayPtr)
+{
+    pthread_mutex_lock(&mMutex);
+    LocationAPIRequest* request = nullptr;
+
+    if (mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].getSessionArrayPtr() == sessionArrayPtr) {
+        request = mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].pop();
+    } else if (mRequestQueues[CTRL_REQUEST_CONFIG_GET].getSessionArrayPtr() == sessionArrayPtr) {
+        request = mRequestQueues[CTRL_REQUEST_CONFIG_GET].pop();
+    }
+
     pthread_mutex_unlock(&mMutex);
     return request;
 }
@@ -234,7 +265,7 @@
     pthread_mutex_init(&mMutex, &attr);
 
     for (int i = 0; i < REQUEST_MAX; i++) {
-        mRequestQueues[i].reset(0);
+        mRequestQueues[i].reset((uint32_t)0);
     }
 }
 
@@ -291,7 +322,7 @@
     }
 
     for (int i = 0; i < REQUEST_MAX; i++) {
-        mRequestQueues[i].reset(0);
+        mRequestQueues[i].reset((uint32_t)0);
     }
 
     pthread_mutex_unlock(&mMutex);
diff --git a/sdm845/location/LocationAPIClientBase.h b/sdm845/location/LocationAPIClientBase.h
index 4bd1466..4d48932 100644
--- a/sdm845/location/LocationAPIClientBase.h
+++ b/sdm845/location/LocationAPIClientBase.h
@@ -57,7 +57,8 @@
 enum CTRL_REQUEST_TYPE {
     CTRL_REQUEST_DELETEAIDINGDATA = 0,
     CTRL_REQUEST_CONTROL,
-    CTRL_REQUEST_CONFIG,
+    CTRL_REQUEST_CONFIG_UPDATE,
+    CTRL_REQUEST_CONFIG_GET,
     CTRL_REQUEST_MAX,
 };
 
@@ -74,12 +75,13 @@
 
 class RequestQueue {
 public:
-    RequestQueue(): mSession(0) {
+    RequestQueue(): mSession(0), mSessionArrayPtr(nullptr) {
     }
     virtual ~RequestQueue() {
-        reset(0);
+        reset((uint32_t)0);
     }
     void inline setSession(uint32_t session) { mSession = session; }
+    void inline setSessionArrayPtr(uint32_t* ptr) { mSessionArrayPtr = ptr; }
     void reset(uint32_t session) {
         LocationAPIRequest* request = nullptr;
         while (!mQueue.empty()) {
@@ -89,6 +91,10 @@
         }
         mSession = session;
     }
+    void reset(uint32_t* sessionArrayPtr) {
+        reset((uint32_t)0);
+        mSessionArrayPtr = sessionArrayPtr;
+    }
     void push(LocationAPIRequest* request) {
         mQueue.push(request);
     }
@@ -101,8 +107,10 @@
         return request;
     }
     uint32_t getSession() { return mSession; }
+    uint32_t* getSessionArrayPtr() { return mSessionArrayPtr; }
 private:
     uint32_t mSession;
+    uint32_t* mSessionArrayPtr;
     std::queue<LocationAPIRequest*> mQueue;
 };
 
@@ -114,12 +122,15 @@
     LocationAPIControlClient& operator=(const LocationAPIControlClient&) = delete;
 
     LocationAPIRequest* getRequestBySession(uint32_t session);
+    LocationAPIRequest* getRequestBySessionArrayPtr(uint32_t* sessionArrayPtr);
 
     // LocationControlAPI
     uint32_t locAPIGnssDeleteAidingData(GnssAidingData& data);
     uint32_t locAPIEnable(LocationTechnologyType techType);
     void locAPIDisable();
     uint32_t locAPIGnssUpdateConfig(GnssConfig config);
+    uint32_t locAPIGnssGetConfig(GnssConfigFlagsMask config);
+    inline LocationControlAPI* getControlAPI() { return mLocationControlAPI; }
 
     // callbacks
     void onCtrlResponseCb(LocationError error, uint32_t id);
@@ -130,6 +141,8 @@
     inline virtual void onDisableCb(LocationError /*error*/) {}
     inline virtual void onGnssUpdateConfigCb(
             size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
+    inline virtual void onGnssGetConfigCb(
+            size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
 
     class GnssDeleteAidingDataRequest : public LocationAPIRequest {
     public:
@@ -167,6 +180,15 @@
         LocationAPIControlClient& mAPI;
     };
 
+    class GnssGetConfigRequest : public LocationAPIRequest {
+    public:
+        GnssGetConfigRequest(LocationAPIControlClient& API) : mAPI(API) {}
+        inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* ids) {
+            mAPI.onGnssGetConfigCb(count, errors, ids);
+        }
+        LocationAPIControlClient& mAPI;
+    };
+
 private:
     pthread_mutex_t mMutex;
     LocationControlAPI* mLocationControlAPI;
diff --git a/sdm845/location/location_interface.h b/sdm845/location/location_interface.h
index 27589f7..f4f904d 100644
--- a/sdm845/location/location_interface.h
+++ b/sdm845/location/location_interface.h
@@ -47,6 +47,10 @@
     uint32_t (*enable)(LocationTechnologyType techType);
     void (*disable)(uint32_t id);
     uint32_t* (*gnssUpdateConfig)(GnssConfig config);
+    uint32_t* (*gnssGetConfig)(GnssConfigFlagsMask config);
+    void (*gnssUpdateSvTypeConfig)(GnssSvTypeConfig& config);
+    void (*gnssGetSvTypeConfig)(GnssSvTypeConfigCallback& callback);
+    void (*gnssResetSvTypeConfig)();
     uint32_t (*gnssDeleteAidingData)(GnssAidingData& data);
     void (*gnssUpdateXtraThrottle)(const bool enabled);
     void (*injectLocation)(double latitude, double longitude, float accuracy);
diff --git a/sdm845/utils/gps_extended_c.h b/sdm845/utils/gps_extended_c.h
index f6b49bf..892bb09 100644
--- a/sdm845/utils/gps_extended_c.h
+++ b/sdm845/utils/gps_extended_c.h
@@ -116,8 +116,9 @@
     LOC_SUPPORTED_FEATURE_ODCPI_2_V02 = 0, /**<  Support ODCPI version 2 feature  */
     LOC_SUPPORTED_FEATURE_WIFI_AP_DATA_INJECT_2_V02, /**<  Support Wifi AP data inject version 2 feature  */
     LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02, /**< Support debug NMEA feature */
-    LOC_SUPPORTED_FEATURE_GNSS_ONLY_POSITION_REPORT, /**< Support GNSS Only position reports */
-    LOC_SUPPORTED_FEATURE_FDCL /**< Support FDCL */
+    LOC_SUPPORTED_FEATURE_GNSS_ONLY_POSITION_REPORT_V02, /**<  Support the GNSS only position report feature  */
+    LOC_SUPPORTED_FEATURE_FDCL_V02, /**<  Support the FDCL feature  */
+    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02, /**<  Support the GNSS constellation enablement feature  */
 } loc_supported_feature_enum;
 
 typedef struct {
@@ -1281,6 +1282,32 @@
     Gnss_Srn_MacAddr_Type  macAddrType; /* SRN AP MAC Address type */
 } GnssSrnDataReq;
 
+/* Mask indicating enabled or disabled constellations */
+typedef uint64_t GnssSvTypesMask;
+typedef enum {
+    GNSS_SV_TYPES_MASK_GLO_BIT  = (1<<0),
+    GNSS_SV_TYPES_MASK_BDS_BIT  = (1<<1),
+    GNSS_SV_TYPES_MASK_QZSS_BIT = (1<<2),
+    GNSS_SV_TYPES_MASK_GAL_BIT  = (1<<3),
+} GnssSvTypesMaskBits;
+
+/* This SV Type config is injected directly to GNSS Adapter
+ * bypassing Location API */
+typedef struct {
+    size_t size; // set to sizeof(GnssSvTypeConfig)
+    // Enabled Constellations
+    GnssSvTypesMask enabledSvTypesMask;
+    // Disabled Constellations
+    GnssSvTypesMask blacklistedSvTypesMask;
+} GnssSvTypeConfig;
+
+/* Provides the current GNSS SV Type configuration to the client.
+ * This is fetched via direct call to GNSS Adapter bypassing
+ * Location API */
+typedef std::function<void(
+    const GnssSvTypeConfig& config
+)> GnssSvTypeConfigCallback;
+
 /*
  * Represents the status of AGNSS augmented to support IPv4.
  */