FP4: Import GPS HAL from LA.UM.9.12.r1-13800-SMxx50.0

Change-Id: Ia11d98eaa5191f923299950e8eb166d0e8fd67f8
diff --git a/gps/Android.bp b/gps/Android.bp
new file mode 100644
index 0000000..0681f67
--- /dev/null
+++ b/gps/Android.bp
@@ -0,0 +1,33 @@
+GNSS_CFLAGS = [
+    "-Werror",
+    "-Wno-error=unused-parameter",
+    "-Wno-error=macro-redefined",
+    "-Wno-error=reorder",
+    "-Wno-error=missing-braces",
+    "-Wno-error=self-assign",
+    "-Wno-error=enum-conversion",
+    "-Wno-error=logical-op-parentheses",
+    "-Wno-error=null-arithmetic",
+    "-Wno-error=null-conversion",
+    "-Wno-error=parentheses-equality",
+    "-Wno-error=undefined-bool-conversion",
+    "-Wno-error=tautological-compare",
+    "-Wno-error=switch",
+    "-Wno-error=date-time",
+]
+
+/* Activate the following for debug purposes only,
+   comment out for production */
+GNSS_SANITIZE_DIAG = {
+/*
+    diag: {
+        cfi: true,
+        misc_undefined: [
+            "bounds",
+            "null",
+            "unreachable",
+            "integer",
+        ],
+    },
+*/
+}
diff --git a/gps/Android.mk b/gps/Android.mk
new file mode 100644
index 0000000..88bb0f4
--- /dev/null
+++ b/gps/Android.mk
@@ -0,0 +1,41 @@
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+
+# Set required flags
+GNSS_CFLAGS := \
+    -Werror \
+    -Wno-error=unused-parameter \
+    -Wno-error=macro-redefined \
+    -Wno-error=reorder \
+    -Wno-error=missing-braces \
+    -Wno-error=self-assign \
+    -Wno-error=enum-conversion \
+    -Wno-error=logical-op-parentheses \
+    -Wno-error=null-arithmetic \
+    -Wno-error=null-conversion \
+    -Wno-error=parentheses-equality \
+    -Wno-error=undefined-bool-conversion \
+    -Wno-error=tautological-compare \
+    -Wno-error=switch \
+    -Wno-error=date-time
+
+GNSS_HIDL_VERSION = 2.1
+
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += msm8937
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += msm8953
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += msm8998
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += apq8098_latv
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += sdm710
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += qcs605
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += sdm845
+GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST += sdm660
+
+ifneq (,$(filter $(GNSS_HIDL_LEGACY_MEASURMENTS_TARGET_LIST),$(TARGET_BOARD_PLATFORM)))
+GNSS_HIDL_LEGACY_MEASURMENTS = true
+endif
+
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
+GNSS_SANITIZE_DIAG := cfi bounds null unreachable integer address
+
+endif # ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
diff --git a/gps/CleanSpec.mk b/gps/CleanSpec.mk
new file mode 100644
index 0000000..dd1849d
--- /dev/null
+++ b/gps/CleanSpec.mk
@@ -0,0 +1,50 @@
+# Copyright (C) 2007 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.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libloc_api*)
diff --git a/gps/Makefile.am b/gps/Makefile.am
new file mode 100644
index 0000000..cd4a731
--- /dev/null
+++ b/gps/Makefile.am
@@ -0,0 +1,10 @@
+# Makefile.am - Automake script for gps loc_api
+#
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = gnss
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = loc-hal.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/gps/android/1.0/AGnss.cpp b/gps/android/1.0/AGnss.cpp
new file mode 100644
index 0000000..79f665c
--- /dev/null
+++ b/gps/android/1.0/AGnss.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_AGnssInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "AGnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+static AGnss* spAGnss = nullptr;
+
+AGnss::AGnss(Gnss* gnss) : mGnss(gnss) {
+    spAGnss = this;
+}
+
+AGnss::~AGnss() {
+    spAGnss = nullptr;
+}
+
+void AGnss::agnssStatusIpV4Cb(AGnssExtStatusIpV4 status){
+    if (nullptr != spAGnss) {
+        spAGnss->statusIpV4Cb(status);
+    }
+}
+
+void AGnss::statusIpV4Cb(AGnssExtStatusIpV4 status) {
+    IAGnssCallback::AGnssStatusIpV4 st = {};
+
+    switch (status.type) {
+        case LOC_AGPS_TYPE_SUPL:
+            st.type = IAGnssCallback::AGnssType::TYPE_SUPL;
+            break;
+        case LOC_AGPS_TYPE_C2K:
+            st.type = IAGnssCallback::AGnssType::TYPE_C2K;
+            break;
+        default:
+            LOC_LOGE("invalid type: %d", status.type);
+            return;
+    }
+
+    switch (status.status) {
+        case LOC_GPS_REQUEST_AGPS_DATA_CONN:
+            st.status = IAGnssCallback::AGnssStatusValue::REQUEST_AGNSS_DATA_CONN;
+            break;
+        case LOC_GPS_RELEASE_AGPS_DATA_CONN:
+            st.status = IAGnssCallback::AGnssStatusValue::RELEASE_AGNSS_DATA_CONN;
+            break;
+        case LOC_GPS_AGPS_DATA_CONNECTED:
+            st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONNECTED;
+            break;
+        case LOC_GPS_AGPS_DATA_CONN_DONE:
+            st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_DONE;
+            break;
+        case LOC_GPS_AGPS_DATA_CONN_FAILED:
+            st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_FAILED;
+            break;
+        default:
+            LOC_LOGE("invalid status: %d", status.status);
+            return;
+    }
+    st.ipV4Addr = status.ipV4Addr;
+
+    if (mAGnssCbIface != nullptr) {
+        auto r = mAGnssCbIface->agnssStatusIpV4Cb(st);
+        if (!r.isOk()) {
+            LOC_LOGw("Error invoking AGNSS status cb %s", r.description().c_str());
+        }
+    } else {
+        LOC_LOGw("setCallback has not been called yet");
+    }
+}
+
+Return<void> AGnss::setCallback(const sp<IAGnssCallback>& callback) {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return Void();
+    }
+
+    // Save the interface
+    mAGnssCbIface = callback;
+
+    AgpsCbInfo cbInfo = {};
+    cbInfo.statusV4Cb = (void*)agnssStatusIpV4Cb;
+    cbInfo.atlType = AGPS_ATL_TYPE_SUPL | AGPS_ATL_TYPE_SUPL_ES;
+
+    mGnss->getGnssInterface()->agpsInit(cbInfo);
+    return Void();
+}
+
+Return<bool> AGnss::dataConnClosed() {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnClosed(LOC_AGPS_TYPE_SUPL);
+    return true;
+}
+
+Return<bool> AGnss::dataConnFailed() {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnFailed(LOC_AGPS_TYPE_SUPL);
+    return true;
+}
+
+Return<bool> AGnss::dataConnOpen(const hidl_string& apn,
+        IAGnss::ApnIpType apnIpType) {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    /* Validate */
+    if(apn.empty()){
+        LOC_LOGE("Invalid APN");
+        return false;
+    }
+
+    LOC_LOGD("dataConnOpen APN name = [%s]", apn.c_str());
+
+    AGpsBearerType bearerType;
+    switch (apnIpType) {
+        case IAGnss::ApnIpType::IPV4:
+            bearerType = AGPS_APN_BEARER_IPV4;
+            break;
+        case IAGnss::ApnIpType::IPV6:
+            bearerType = AGPS_APN_BEARER_IPV6;
+            break;
+        case IAGnss::ApnIpType::IPV4V6:
+            bearerType = AGPS_APN_BEARER_IPV4V6;
+            break;
+        default:
+            bearerType = AGPS_APN_BEARER_IPV4;
+            break;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnOpen(
+            LOC_AGPS_TYPE_SUPL, apn.c_str(), apn.size(), (int)bearerType);
+    return true;
+}
+
+Return<bool> AGnss::setServer(IAGnssCallback::AGnssType type,
+                              const hidl_string& hostname,
+                              int32_t port) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+    config.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+    if (type == IAGnssCallback::AGnssType::TYPE_SUPL) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL;
+    } else if (type == IAGnssCallback::AGnssType::TYPE_C2K) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_C2K;
+    } else {
+        LOC_LOGE("%s]: invalid AGnssType: %d", __FUNCTION__, static_cast<int>(type));
+        return false;
+    }
+    config.assistanceServer.hostName = strdup(hostname.c_str());
+    config.assistanceServer.port = port;
+    return mGnss->updateConfiguration(config);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/AGnss.h b/gps/android/1.0/AGnss.h
new file mode 100644
index 0000000..cdd5931
--- /dev/null
+++ b/gps/android/1.0/AGnss.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_AGNSS_H
+#define ANDROID_HARDWARE_GNSS_V1_0_AGNSS_H
+
+#include <android/hardware/gnss/1.0/IAGnss.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnss;
+using ::android::hardware::gnss::V1_0::IAGnssCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct AGnss : public IAGnss {
+
+    AGnss(Gnss* gnss);
+    ~AGnss();
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IAGnss interface follow.
+     * These declarations were generated from IAGnss.hal.
+     */
+    Return<void> setCallback(const sp<IAGnssCallback>& callback) override;
+
+    Return<bool> dataConnClosed() override;
+
+    Return<bool> dataConnFailed() override;
+
+    Return<bool> dataConnOpen(const hidl_string& apn,
+            IAGnss::ApnIpType apnIpType) override;
+
+    Return<bool> setServer(IAGnssCallback::AGnssType type,
+                         const hidl_string& hostname, int32_t port) override;
+
+    void statusIpV4Cb(AGnssExtStatusIpV4 status);
+
+    /* Data call setup callback passed down to GNSS HAL implementation */
+    static void agnssStatusIpV4Cb(AGnssExtStatusIpV4 status);
+
+ private:
+    Gnss* mGnss = nullptr;
+    sp<IAGnssCallback> mAGnssCbIface = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_AGNSS_H
diff --git a/gps/android/1.0/AGnssRil.cpp b/gps/android/1.0/AGnssRil.cpp
new file mode 100644
index 0000000..d7f30eb
--- /dev/null
+++ b/gps/android/1.0/AGnssRil.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc__AGnssRilInterface"
+
+#include <log_util.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sstream>
+#include <string>
+#include "Gnss.h"
+#include "AGnssRil.h"
+#include <DataItemConcreteTypesBase.h>
+
+typedef void* (getLocationInterface)();
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+
+AGnssRil::AGnssRil(Gnss* gnss) : mGnss(gnss) {
+    ENTRY_LOG_CALLFLOW();
+}
+
+AGnssRil::~AGnssRil() {
+    ENTRY_LOG_CALLFLOW();
+}
+
+Return<bool> AGnssRil::updateNetworkState(bool connected, NetworkType type, bool /*roaming*/) {
+    ENTRY_LOG_CALLFLOW();
+    // Extra NetworkTypes not available in IAgnssRil enums
+    const int NetworkType_BLUETOOTH = 7;
+    const int NetworkType_ETHERNET = 9;
+    const int NetworkType_PROXY = 16;
+    std::string apn("");
+
+    // for XTRA
+    if (nullptr != mGnss && ( nullptr != mGnss->getGnssInterface() )) {
+        int8_t typeout = loc_core::NetworkInfoDataItemBase::TYPE_UNKNOWN;
+        switch(type)
+        {
+            case IAGnssRil::NetworkType::MOBILE:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_MOBILE;
+                break;
+            case IAGnssRil::NetworkType::WIFI:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_WIFI;
+                break;
+            case IAGnssRil::NetworkType::MMS:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_MMS;
+                break;
+            case IAGnssRil::NetworkType::SUPL:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_SUPL;
+                break;
+            case IAGnssRil::NetworkType::DUN:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_DUN;
+                break;
+            case IAGnssRil::NetworkType::HIPRI:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_HIPRI;
+                break;
+            case IAGnssRil::NetworkType::WIMAX:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_WIMAX;
+                break;
+            default:
+                {
+                    int networkType = (int) type;
+                    // Handling network types not available in IAgnssRil
+                    switch(networkType)
+                    {
+                        case NetworkType_BLUETOOTH:
+                            typeout = loc_core::NetworkInfoDataItemBase::TYPE_BLUETOOTH;
+                            break;
+                        case NetworkType_ETHERNET:
+                            typeout = loc_core::NetworkInfoDataItemBase::TYPE_ETHERNET;
+                            break;
+                        case NetworkType_PROXY:
+                            typeout = loc_core::NetworkInfoDataItemBase::TYPE_PROXY;
+                            break;
+                        default:
+                            typeout = loc_core::NetworkInfoDataItemBase::TYPE_UNKNOWN;
+                    }
+                }
+                break;
+        }
+        mGnss->getGnssInterface()->updateConnectionStatus(connected, typeout, false, 0, apn);
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/AGnssRil.h b/gps/android/1.0/AGnssRil.h
new file mode 100644
index 0000000..7f18c57
--- /dev/null
+++ b/gps/android/1.0/AGnssRil.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
+#define ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
+
+#include <android/hardware/gnss/1.0/IAGnssRil.h>
+#include <hidl/Status.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnssRil;
+using ::android::hardware::gnss::V1_0::IAGnssRilCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+/*
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface Layer interface
+ * allows the GNSS chipset to request radio interface layer information from Android platform.
+ * Examples of such information are reference location, unique subscriber ID, phone number string
+ * and network availability changes. Also contains wrapper methods to allow methods from
+ * IAGnssiRilCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+struct AGnssRil : public IAGnssRil {
+    AGnssRil(Gnss* gnss);
+    ~AGnssRil();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow.
+     * These declarations were generated from IAGnssRil.hal.
+     */
+    Return<void> setCallback(const sp<IAGnssRilCallback>& /*callback*/) override {
+        return Void();
+    }
+    Return<void> setRefLocation(const IAGnssRil::AGnssRefLocation& /*agnssReflocation*/) override {
+        return Void();
+    }
+    Return<bool> setSetId(IAGnssRil::SetIDType /*type*/, const hidl_string& /*setid*/) override {
+        return false;
+    }
+    Return<bool> updateNetworkAvailability(bool /*available*/,
+                                    const hidl_string& /*apn*/) override {
+        return false;
+    }
+    Return<bool> updateNetworkState(bool connected, NetworkType type, bool roaming) override;
+
+ private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
diff --git a/gps/android/1.0/Android.mk b/gps/android/1.0/Android.mk
new file mode 100644
index 0000000..f63a948
--- /dev/null
+++ b/gps/android/1.0/Android.mk
@@ -0,0 +1,99 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.0-impl-qti
+
+# activate the following line for debug purposes only, comment out for production
+#LOCAL_SANITIZE_DIAG += $(GNSS_SANITIZE_DIAG)
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+    AGnss.cpp \
+    Gnss.cpp \
+    GnssBatching.cpp \
+    GnssGeofencing.cpp \
+    GnssMeasurement.cpp \
+    GnssNi.cpp \
+    GnssConfiguration.cpp \
+    GnssDebug.cpp \
+    AGnssRil.cpp
+
+LOCAL_SRC_FILES += \
+    location_api/LocationUtil.cpp \
+    location_api/GnssAPIClient.cpp \
+    location_api/GeofenceAPIClient.cpp \
+    location_api/BatchingAPIClient.cpp \
+    location_api/MeasurementAPIClient.cpp \
+
+LOCAL_C_INCLUDES:= \
+    $(LOCAL_PATH)/location_api
+LOCAL_HEADER_LIBRARIES := \
+    libgps.utils_headers \
+    libloc_core_headers \
+    libloc_pla_headers \
+    liblocation_api_headers \
+    liblocbatterylistener_headers
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libhidlbase \
+    libcutils \
+    libutils \
+    android.hardware.gnss@1.0 \
+    android.hardware.health@1.0 \
+    android.hardware.health@2.0 \
+    android.hardware.power@1.2 \
+    libbase
+
+LOCAL_SHARED_LIBRARIES += \
+    libloc_core \
+    libgps.utils \
+    libdl \
+    liblocation_api \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.0-service-qti
+
+# activate the following line for debug purposes only, comment out for production
+#LOCAL_SANITIZE_DIAG += $(GNSS_SANITIZE_DIAG)
+LOCAL_VINTF_FRAGMENTS := android.hardware.gnss@1.0-service-qti.xml
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_INIT_RC := android.hardware.gnss@1.0-service-qti.rc
+LOCAL_SRC_FILES := \
+    service.cpp \
+
+LOCAL_C_INCLUDES:= \
+    $(LOCAL_PATH)/location_api
+LOCAL_HEADER_LIBRARIES := \
+    libgps.utils_headers \
+    libloc_core_headers \
+    libloc_pla_headers \
+    liblocation_api_headers
+
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libcutils \
+    libdl \
+    libbase \
+    libutils \
+    libgps.utils \
+    libqti_vndfwk_detect \
+
+LOCAL_SHARED_LIBRARIES += \
+    libhidlbase \
+    android.hardware.gnss@1.0 \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+ifneq ($(LOC_HIDL_VERSION),)
+LOCAL_CFLAGS += -DLOC_HIDL_VERSION='"$(LOC_HIDL_VERSION)"'
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/gps/android/1.0/Gnss.cpp b/gps/android/1.0/Gnss.cpp
new file mode 100644
index 0000000..308cc7c
--- /dev/null
+++ b/gps/android/1.0/Gnss.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
+
+#include <fstream>
+#include <log_util.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "Gnss.h"
+#include <LocationUtil.h>
+#include "battery_listener.h"
+#include "loc_misc_utils.h"
+
+typedef const GnssInterface* (getLocationInterface)();
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+static sp<Gnss> sGnss;
+void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnss != nullptr) {
+        mGnss->getGnssInterface()->resetNetworkInfo();
+        mGnss->stop();
+        mGnss->cleanup();
+    }
+}
+
+void location_on_battery_status_changed(bool charging) {
+    LOC_LOGd("battery status changed to %s charging", charging ? "" : "not ");
+    if (sGnss != nullptr) {
+        sGnss->getGnssInterface()->updateBatteryStatus(charging);
+    }
+}
+Gnss::Gnss() {
+    ENTRY_LOG_CALLFLOW();
+    sGnss = this;
+    // initilize gnss interface at first in case needing notify battery status
+    sGnss->getGnssInterface()->initialize();
+    // register health client to listen on battery change
+    loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
+    // clear pending GnssConfig
+    memset(&mPendingConfig, 0, sizeof(GnssConfig));
+
+    mGnssDeathRecipient = new GnssDeathRecipient(this);
+}
+
+Gnss::~Gnss() {
+    ENTRY_LOG_CALLFLOW();
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+    sGnss = nullptr;
+}
+
+GnssAPIClient* Gnss::getApi() {
+    if (mApi == nullptr && (mGnssCbIface != nullptr || mGnssNiCbIface != nullptr)) {
+        mApi = new GnssAPIClient(mGnssCbIface, mGnssNiCbIface);
+        if (mApi == nullptr) {
+            LOC_LOGE("%s] faild to create GnssAPIClient", __FUNCTION__);
+            return mApi;
+        }
+
+        if (mPendingConfig.size == sizeof(GnssConfig)) {
+            // we have pending GnssConfig
+            mApi->gnssConfigurationUpdate(mPendingConfig);
+            // clear size to invalid mPendingConfig
+            mPendingConfig.size = 0;
+            if (mPendingConfig.assistanceServer.hostName != nullptr) {
+                free((void*)mPendingConfig.assistanceServer.hostName);
+            }
+        }
+    }
+    if (mApi == nullptr) {
+        LOC_LOGW("%s] GnssAPIClient is not ready", __FUNCTION__);
+    }
+    return mApi;
+}
+
+const GnssInterface* Gnss::getGnssInterface() {
+    static bool getGnssInterfaceFailed = false;
+    if (nullptr == mGnssInterface && !getGnssInterfaceFailed) {
+        void * libHandle = nullptr;
+        getLocationInterface* getter = (getLocationInterface*)
+                dlGetSymFromLib(libHandle, "libgnss.so", "getGnssInterface");
+
+        if (nullptr == getter) {
+            getGnssInterfaceFailed = true;
+        } else {
+            mGnssInterface = (const GnssInterface*)(*getter)();
+        }
+    }
+    return mGnssInterface;
+}
+
+Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback)  {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+    }
+    mGnssCbIface = callback;
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+    }
+
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+        api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
+    }
+    return true;
+}
+
+Return<bool> Gnss::setGnssNiCb(const sp<IGnssNiCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    mGnssNiCbIface = callback;
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+    }
+    return true;
+}
+
+Return<bool> Gnss::updateConfiguration(GnssConfig& gnssConfig) {
+    ENTRY_LOG_CALLFLOW();
+    GnssAPIClient* api = getApi();
+    if (api) {
+        api->gnssConfigurationUpdate(gnssConfig);
+    } else if (gnssConfig.flags != 0) {
+        // api is not ready yet, update mPendingConfig with gnssConfig
+        mPendingConfig.size = sizeof(GnssConfig);
+
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+            mPendingConfig.gpsLock = gnssConfig.gpsLock;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+            mPendingConfig.suplVersion = gnssConfig.suplVersion;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+            mPendingConfig.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+            mPendingConfig.assistanceServer.type = gnssConfig.assistanceServer.type;
+            if (mPendingConfig.assistanceServer.hostName != nullptr) {
+                free((void*)mPendingConfig.assistanceServer.hostName);
+                mPendingConfig.assistanceServer.hostName =
+                    strdup(gnssConfig.assistanceServer.hostName);
+            }
+            mPendingConfig.assistanceServer.port = gnssConfig.assistanceServer.port;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+            mPendingConfig.lppProfileMask = gnssConfig.lppProfileMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT;
+            mPendingConfig.lppeControlPlaneMask = gnssConfig.lppeControlPlaneMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT;
+            mPendingConfig.lppeUserPlaneMask = gnssConfig.lppeUserPlaneMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+            mPendingConfig.aGlonassPositionProtocolMask = gnssConfig.aGlonassPositionProtocolMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+            mPendingConfig.emergencyPdnForEmergencySupl = gnssConfig.emergencyPdnForEmergencySupl;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+            mPendingConfig.suplEmergencyServices = gnssConfig.suplEmergencyServices;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+            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;
+}
+
+Return<bool> Gnss::start()  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssStart();
+    }
+    return retVal;
+}
+
+Return<bool> Gnss::stop()  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssStop();
+    }
+    return retVal;
+}
+
+Return<void> Gnss::cleanup()  {
+    ENTRY_LOG_CALLFLOW();
+
+    if (mApi != nullptr) {
+        mApi->gnssDisable();
+    }
+
+    return Void();
+}
+
+Return<bool> Gnss::injectLocation(double latitudeDegrees,
+                                  double longitudeDegrees,
+                                  float accuracyMeters)  {
+    ENTRY_LOG_CALLFLOW();
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        gnssInterface->injectLocation(latitudeDegrees, longitudeDegrees, accuracyMeters);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs,
+                              int32_t uncertaintyMs) {
+    return true;
+}
+
+Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags)  {
+    ENTRY_LOG_CALLFLOW();
+    GnssAPIClient* api = getApi();
+    if (api) {
+        api->gnssDeleteAidingData(aidingDataFlags);
+    }
+    return Void();
+}
+
+Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                   V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                   uint32_t minIntervalMs,
+                                   uint32_t preferredAccuracyMeters,
+                                   uint32_t preferredTimeMs)  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+                preferredAccuracyMeters, preferredTimeMs);
+    }
+    return retVal;
+}
+
+Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss()  {
+    ENTRY_LOG_CALLFLOW();
+    mAGnssIface = new AGnss(this);
+    return mAGnssIface;
+}
+
+Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi()  {
+    ENTRY_LOG_CALLFLOW();
+    mGnssNi = new GnssNi(this);
+    return mGnssNi;
+}
+
+Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssMeasurement == nullptr)
+        mGnssMeasurement = new GnssMeasurement();
+    return mGnssMeasurement;
+}
+
+Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration()  {
+    ENTRY_LOG_CALLFLOW();
+    mGnssConfig = new GnssConfiguration(this);
+    return mGnssConfig;
+}
+
+Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing()  {
+    ENTRY_LOG_CALLFLOW();
+    mGnssGeofencingIface = new GnssGeofencing();
+    return mGnssGeofencingIface;
+}
+
+Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching()  {
+    mGnssBatching = new GnssBatching();
+    return mGnssBatching;
+}
+
+Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
+    ENTRY_LOG_CALLFLOW();
+    mGnssDebug = new GnssDebug(this);
+    return mGnssDebug;
+}
+
+Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
+    mGnssRil = new AGnssRil(this);
+    return mGnssRil;
+}
+
+IGnss* HIDL_FETCH_IGnss(const char* hal) {
+    ENTRY_LOG_CALLFLOW();
+    IGnss* iface = nullptr;
+    iface = new Gnss();
+    if (iface == nullptr) {
+        LOC_LOGE("%s]: failed to get %s", __FUNCTION__, hal);
+    }
+    return iface;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/Gnss.h b/gps/android/1.0/Gnss.h
new file mode 100644
index 0000000..900a510
--- /dev/null
+++ b/gps/android/1.0/Gnss.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSS_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSS_H
+
+#include <AGnss.h>
+#include <AGnssRil.h>
+#include <GnssBatching.h>
+#include <GnssConfiguration.h>
+#include <GnssGeofencing.h>
+#include <GnssMeasurement.h>
+#include <GnssNi.h>
+#include <GnssDebug.h>
+
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <GnssAPIClient.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+struct Gnss : public IGnss {
+    Gnss();
+    ~Gnss();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnss follow.
+     * These declarations were generated from Gnss.hal.
+     */
+    Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback)  override;
+    Return<bool> start()  override;
+    Return<bool> stop()  override;
+    Return<void> cleanup()  override;
+    Return<bool> injectLocation(double latitudeDegrees,
+                                double longitudeDegrees,
+                                float accuracyMeters)  override;
+    Return<bool> injectTime(int64_t timeMs,
+                            int64_t timeReferenceMs,
+                            int32_t uncertaintyMs) override;
+    Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags)  override;
+    Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                 V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                 uint32_t minIntervalMs,
+                                 uint32_t preferredAccuracyMeters,
+                                 uint32_t preferredTimeMs)  override;
+    Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+    Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+    Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+    Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+    Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+    Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+    Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+
+    inline Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override {
+        return nullptr;
+    }
+
+    inline Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override {
+        return nullptr;
+    }
+
+    Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+
+    // These methods are not part of the IGnss base class.
+    GnssAPIClient* getApi();
+    Return<bool> setGnssNiCb(const sp<IGnssNiCallback>& niCb);
+    Return<bool> updateConfiguration(GnssConfig& gnssConfig);
+    const GnssInterface* getGnssInterface();
+
+    // Callback for ODCPI request
+    void odcpiRequestCb(const OdcpiRequestInfo& request);
+
+ private:
+    struct GnssDeathRecipient : hidl_death_recipient {
+        GnssDeathRecipient(sp<Gnss> gnss) : mGnss(gnss) {
+        }
+        ~GnssDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<Gnss> mGnss;
+    };
+
+ private:
+    sp<GnssDeathRecipient> mGnssDeathRecipient = nullptr;
+
+    sp<AGnss> mAGnssIface = nullptr;
+    sp<GnssNi> mGnssNi = nullptr;
+    sp<GnssMeasurement> mGnssMeasurement = nullptr;
+    sp<GnssConfiguration> mGnssConfig = nullptr;
+    sp<GnssGeofencing> mGnssGeofencingIface = nullptr;
+    sp<GnssBatching> mGnssBatching = nullptr;
+    sp<IGnssDebug> mGnssDebug = nullptr;
+    sp<AGnssRil> mGnssRil = nullptr;
+
+    GnssAPIClient* mApi = nullptr;
+    sp<V1_0::IGnssCallback> mGnssCbIface = nullptr;
+    sp<V1_0::IGnssNiCallback> mGnssNiCbIface = nullptr;
+    GnssConfig mPendingConfig;
+    const GnssInterface* mGnssInterface = nullptr;
+};
+
+extern "C" IGnss* HIDL_FETCH_IGnss(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_GNSS_H
diff --git a/gps/android/1.0/GnssBatching.cpp b/gps/android/1.0/GnssBatching.cpp
new file mode 100644
index 0000000..f92697f
--- /dev/null
+++ b/gps/android/1.0/GnssBatching.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssBatchingInterface"
+
+#include <log_util.h>
+#include <BatchingAPIClient.h>
+#include "GnssBatching.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void GnssBatching::GnssBatchingDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssBatching != nullptr) {
+        mGnssBatching->stop();
+        mGnssBatching->cleanup();
+    }
+}
+
+GnssBatching::GnssBatching() : mApi(nullptr) {
+    mGnssBatchingDeathRecipient = new GnssBatchingDeathRecipient(this);
+}
+
+GnssBatching::~GnssBatching() {
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+Return<bool> GnssBatching::init(const sp<IGnssBatchingCallback>& callback) {
+    if (mApi != nullptr) {
+        LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+        mApi->destroy();
+        mApi = nullptr;
+    }
+
+    mApi = new BatchingAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+        return false;
+    }
+
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+    }
+    mGnssBatchingCbIface = callback;
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return true;
+}
+
+Return<uint16_t> GnssBatching::getBatchSize() {
+    uint16_t ret = 0;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->getBatchSize();
+    }
+    return ret;
+}
+
+Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
+    bool ret = false;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->startSession(options);
+    }
+    return ret;
+}
+
+Return<void> GnssBatching::flush() {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->flushBatchedLocations();
+    }
+    return Void();
+}
+
+Return<bool> GnssBatching::stop() {
+    bool ret = false;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->stopSession();
+    }
+    return ret;
+}
+
+Return<void> GnssBatching::cleanup() {
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/GnssBatching.h b/gps/android/1.0/GnssBatching.h
new file mode 100644
index 0000000..8fab857
--- /dev/null
+++ b/gps/android/1.0/GnssBatching.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
+
+#include <android/hardware/gnss/1.0/IGnssBatching.h>
+#include <hidl/Status.h>
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssBatching;
+using ::android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+class BatchingAPIClient;
+struct GnssBatching : public IGnssBatching {
+    GnssBatching();
+    ~GnssBatching();
+
+    // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+    Return<bool> init(const sp<IGnssBatchingCallback>& callback) override;
+    Return<uint16_t> getBatchSize() override;
+    Return<bool> start(const IGnssBatching::Options& options ) override;
+    Return<void> flush() override;
+    Return<bool> stop() override;
+    Return<void> cleanup() override;
+
+ private:
+    struct GnssBatchingDeathRecipient : hidl_death_recipient {
+        GnssBatchingDeathRecipient(sp<GnssBatching> gnssBatching) :
+            mGnssBatching(gnssBatching) {
+        }
+        ~GnssBatchingDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssBatching> mGnssBatching;
+    };
+
+ private:
+    sp<GnssBatchingDeathRecipient> mGnssBatchingDeathRecipient = nullptr;
+    sp<IGnssBatchingCallback> mGnssBatchingCbIface = nullptr;
+    BatchingAPIClient* mApi = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_GNSSBATCHING_H
diff --git a/gps/android/1.0/GnssConfiguration.cpp b/gps/android/1.0/GnssConfiguration.cpp
new file mode 100644
index 0000000..a7f64fa
--- /dev/null
+++ b/gps/android/1.0/GnssConfiguration.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssConfigurationInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssConfiguration.h"
+#include <android/hardware/gnss/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+
+GnssConfiguration::GnssConfiguration(Gnss* gnss) : mGnss(gnss) {
+}
+
+// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enabled)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+    config.suplEmergencyServices = (enabled ?
+            GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_YES :
+            GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO);
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t version)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+    switch (version) {
+        case 0x00020004:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_4;
+            break;
+        case 0x00020002:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_2;
+            break;
+        case 0x00020000:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_0;
+            break;
+        case 0x00010000:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_1_0_0;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid version: 0x%x.", __FUNCTION__, version);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplMode(uint8_t mode)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+    switch (mode) {
+        case 0:
+            config.suplModeMask = 0; // STANDALONE ONLY
+            break;
+        case 1:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT;
+            break;
+        case 2:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+            break;
+        case 3:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT | GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid mode: %d.", __FUNCTION__, mode);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfileMask) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config = {};
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+    config.lppProfileMask = GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE; //default
+
+    if (lppProfileMask & (1<<0)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_BIT;
+    }
+    if (lppProfileMask & (1<<1)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_BIT;
+    }
+    if (lppProfileMask & (1<<2)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_OVER_NR5G_SA_BIT;
+    }
+    if (lppProfileMask & (1<<3)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_OVER_NR5G_SA_BIT;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+
+    config.flags = GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+    if (protocol & (1<<0)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRC_CONTROL_PLANE_BIT;
+    }
+    if (protocol & (1<<1)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRLP_USER_PLANE_BIT;
+    }
+    if (protocol & (1<<2)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_USER_PLANE_BIT;
+    }
+    if (protocol & (1<<3)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_CONTROL_PLANE_BIT;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+    switch (lock) {
+        case 0:
+            config.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+            break;
+        case 1:
+            config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO;
+            break;
+        case 2:
+            config.gpsLock = GNSS_CONFIG_GPS_LOCK_NI;
+            break;
+        case 3:
+            config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid lock: %d.", __FUNCTION__, lock);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+    config.emergencyPdnForEmergencySupl = (enabled ?
+            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES :
+            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO);
+
+    return mGnss->updateConfiguration(config);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/GnssConfiguration.h b/gps/android/1.0/GnssConfiguration.h
new file mode 100644
index 0000000..d0e2ba8
--- /dev/null
+++ b/gps/android/1.0/GnssConfiguration.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+
+ /* Copyright (C) 2016 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.
+ */
+
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSCONFIGURATION_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSCONFIGURATION_H
+
+#include <android/hardware/gnss/1.0/IGnssConfiguration.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssConfiguration;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Interface for passing GNSS configuration info from platform to HAL.
+ */
+struct Gnss;
+struct GnssConfiguration : public IGnssConfiguration {
+    GnssConfiguration(Gnss* gnss);
+    ~GnssConfiguration() = default;
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+     * These declarations were generated from IGnssConfiguration.hal.
+     */
+    Return<bool> setSuplVersion(uint32_t version) override;
+    Return<bool> setSuplMode(uint8_t mode) override;
+    Return<bool> setSuplEs(bool enabled) override;
+    Return<bool> setLppProfile(uint8_t lppProfileMask) override;
+    Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override;
+    Return<bool> setEmergencySuplPdn(bool enable) override;
+    Return<bool> setGpsLock(uint8_t lock) override;
+
+ private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_GNSSCONFIGURATION_H
diff --git a/gps/android/1.0/GnssDebug.cpp b/gps/android/1.0/GnssDebug.cpp
new file mode 100644
index 0000000..ead72e1
--- /dev/null
+++ b/gps/android/1.0/GnssDebug.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssDebugInterface"
+
+#include <log/log.h>
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssDebug.h"
+#include "LocationUtil.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+
+#define GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS (20000000)
+#define GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS   (20000)
+#define GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC     (500)
+#define GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG       (180)
+
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME            (1483228800000LL) // 1/1/2017 00:00 GMT
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC        (1.57783680E17) // 5 years in ns
+#define GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC (2.0e5)  // ppm
+
+GnssDebug::GnssDebug(Gnss* gnss) : mGnss(gnss)
+{
+}
+
+/*
+ * This methods requests position, time and satellite ephemeris debug information
+ * from the HAL.
+ *
+ * @return void
+*/
+Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    DebugData data = { };
+
+    if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+        LOC_LOGE("GnssDebug - Null GNSS interface");
+        _hidl_cb(data);
+        return Void();
+    }
+
+    // get debug report snapshot via hal interface
+    GnssDebugReport reports = { };
+    mGnss->getGnssInterface()->getDebugReport(reports);
+
+    // location block
+    if (reports.mLocation.mValid) {
+        data.position.valid = true;
+        data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+        data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+        data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+        data.position.speedMetersPerSec =
+            (double)(reports.mLocation.mLocation.speed);
+        data.position.bearingDegrees =
+            (double)(reports.mLocation.mLocation.bearing);
+        data.position.horizontalAccuracyMeters =
+            (double)(reports.mLocation.mLocation.accuracy);
+        data.position.verticalAccuracyMeters =
+            reports.mLocation.verticalAccuracyMeters;
+        data.position.speedAccuracyMetersPerSecond =
+            reports.mLocation.speedAccuracyMetersPerSecond;
+        data.position.bearingAccuracyDegrees =
+            reports.mLocation.bearingAccuracyDegrees;
+
+        timeval tv_now, tv_report;
+        tv_report.tv_sec  = reports.mLocation.mUtcReported.tv_sec;
+        tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+        gettimeofday(&tv_now, NULL);
+        data.position.ageSeconds =
+            (tv_now.tv_sec - tv_report.tv_sec) +
+            (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+    }
+    else {
+        data.position.valid = false;
+    }
+
+    if (data.position.horizontalAccuracyMeters <= 0 ||
+        data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+        data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+    }
+    if (data.position.verticalAccuracyMeters <= 0 ||
+        data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+        data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+    }
+    if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+        data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+        data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+    }
+    if (data.position.bearingAccuracyDegrees <= 0 ||
+        data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+        data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+    }
+
+    // time block
+    if (reports.mTime.mValid) {
+        data.time.timeEstimate = reports.mTime.timeEstimate;
+        data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+        data.time.frequencyUncertaintyNsPerSec =
+            reports.mTime.frequencyUncertaintyNsPerSec;
+    }
+
+    if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+        data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+    }
+    if (data.time.timeUncertaintyNs <= 0 ||
+        data.time.timeUncertaintyNs > (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC;
+    }
+    if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+        data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+        data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+    }
+
+    // satellite data block
+    SatelliteData s = { };
+    std::vector<SatelliteData> s_array = { };
+
+    for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+        memset(&s, 0, sizeof(s));
+        s.svid = reports.mSatelliteInfo[i].svid;
+        convertGnssConstellationType(
+            reports.mSatelliteInfo[i].constellation, s.constellation);
+        convertGnssEphemerisType(
+            reports.mSatelliteInfo[i].mEphemerisType, s.ephemerisType);
+        convertGnssEphemerisSource(
+            reports.mSatelliteInfo[i].mEphemerisSource, s.ephemerisSource);
+        convertGnssEphemerisHealth(
+            reports.mSatelliteInfo[i].mEphemerisHealth, s.ephemerisHealth);
+
+        s.ephemerisAgeSeconds =
+            reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+        s.serverPredictionIsAvailable =
+            reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+        s.serverPredictionAgeSeconds =
+            reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+        s_array.push_back(s);
+    }
+    data.satelliteDataArray = s_array;
+
+    // callback HIDL with collected debug data
+    _hidl_cb(data);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/GnssDebug.h b/gps/android/1.0/GnssDebug.h
new file mode 100644
index 0000000..a7116cb
--- /dev/null
+++ b/gps/android/1.0/GnssDebug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSDEBUG_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSDEBUG_H
+
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssDebug;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/* Interface for GNSS Debug support. */
+struct Gnss;
+struct GnssDebug : public IGnssDebug {
+    GnssDebug(Gnss* gnss);
+    ~GnssDebug() {};
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+     * These declarations were generated from IGnssDebug.hal.
+     */
+    Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
+
+private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_GNSSDEBUG_H
diff --git a/gps/android/1.0/GnssGeofencing.cpp b/gps/android/1.0/GnssGeofencing.cpp
new file mode 100644
index 0000000..4be6d8a
--- /dev/null
+++ b/gps/android/1.0/GnssGeofencing.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "GnssHal_GnssGeofencing"
+
+#include <log_util.h>
+#include <GeofenceAPIClient.h>
+#include "GnssGeofencing.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void GnssGeofencing::GnssGeofencingDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssGeofencing != nullptr) {
+        mGnssGeofencing->removeAllGeofences();
+    }
+}
+
+GnssGeofencing::GnssGeofencing() : mApi(nullptr) {
+    mGnssGeofencingDeathRecipient = new GnssGeofencingDeathRecipient(this);
+}
+
+GnssGeofencing::~GnssGeofencing() {
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback)  {
+    if (mApi != nullptr) {
+        LOC_LOGE("%s]: mApi is NOT nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    mApi = new GeofenceAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+    }
+
+    if (mGnssGeofencingCbIface != nullptr) {
+        mGnssGeofencingCbIface->unlinkToDeath(mGnssGeofencingDeathRecipient);
+    }
+    mGnssGeofencingCbIface = callback;
+    if (mGnssGeofencingCbIface != nullptr) {
+        mGnssGeofencingCbIface->linkToDeath(mGnssGeofencingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return Void();
+}
+
+Return<void> GnssGeofencing::addGeofence(
+        int32_t geofenceId,
+        double latitudeDegrees,
+        double longitudeDegrees,
+        double radiusMeters,
+        IGnssGeofenceCallback::GeofenceTransition lastTransition,
+        int32_t monitorTransitions,
+        uint32_t notificationResponsivenessMs,
+        uint32_t unknownTimerMs)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceAdd(
+                geofenceId,
+                latitudeDegrees,
+                longitudeDegrees,
+                radiusMeters,
+                static_cast<int32_t>(lastTransition),
+                monitorTransitions,
+                notificationResponsivenessMs,
+                unknownTimerMs);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofencePause(geofenceId);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceResume(geofenceId, monitorTransitions);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceRemove(geofenceId);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::removeAllGeofences()  {
+    if (mApi == nullptr) {
+        LOC_LOGD("%s]: mApi is nullptr, do nothing", __FUNCTION__);
+    } else {
+        mApi->geofenceRemoveAll();
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/GnssGeofencing.h b/gps/android/1.0/GnssGeofencing.h
new file mode 100644
index 0000000..db5f9d2
--- /dev/null
+++ b/gps/android/1.0/GnssGeofencing.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSGEOFENCING_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSGEOFENCING_H
+
+#include <android/hardware/gnss/1.0/IGnssGeofencing.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::IGnssGeofencing;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class GeofenceAPIClient;
+struct GnssGeofencing : public IGnssGeofencing {
+    GnssGeofencing();
+    ~GnssGeofencing();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+     * These declarations were generated from IGnssGeofencing.hal.
+     */
+    Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback)  override;
+    Return<void> addGeofence(int32_t geofenceId,
+                             double latitudeDegrees,
+                             double longitudeDegrees,
+                             double radiusMeters,
+                             IGnssGeofenceCallback::GeofenceTransition lastTransition,
+                             int32_t monitorTransitions,
+                             uint32_t notificationResponsivenessMs,
+                             uint32_t unknownTimerMs)  override;
+
+    Return<void> pauseGeofence(int32_t geofenceId)  override;
+    Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  override;
+    Return<void> removeGeofence(int32_t geofenceId)  override;
+
+ private:
+    // This method is not part of the IGnss base class.
+    // It is called by GnssGeofencingDeathRecipient to remove all geofences added so far.
+    Return<void> removeAllGeofences();
+
+ private:
+    struct GnssGeofencingDeathRecipient : hidl_death_recipient {
+        GnssGeofencingDeathRecipient(sp<GnssGeofencing> gnssGeofencing) :
+            mGnssGeofencing(gnssGeofencing) {
+        }
+        ~GnssGeofencingDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssGeofencing> mGnssGeofencing;
+    };
+
+ private:
+    sp<GnssGeofencingDeathRecipient> mGnssGeofencingDeathRecipient = nullptr;
+    sp<IGnssGeofenceCallback> mGnssGeofencingCbIface = nullptr;
+    GeofenceAPIClient* mApi = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_GNSSGEOFENCING_H
diff --git a/gps/android/1.0/GnssMeasurement.cpp b/gps/android/1.0/GnssMeasurement.cpp
new file mode 100644
index 0000000..7af9e27
--- /dev/null
+++ b/gps/android/1.0/GnssMeasurement.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssMeasurementInterface"
+
+#include <log_util.h>
+#include <MeasurementAPIClient.h>
+#include "GnssMeasurement.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void GnssMeasurement::GnssMeasurementDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssMeasurement != nullptr) {
+        mGnssMeasurement->close();
+    }
+}
+
+GnssMeasurement::GnssMeasurement() {
+    mGnssMeasurementDeathRecipient = new GnssMeasurementDeathRecipient(this);
+    mApi = new MeasurementAPIClient();
+}
+
+GnssMeasurement::~GnssMeasurement() {
+    if (mApi) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+
+Return<IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+        const sp<V1_0::IGnssMeasurementCallback>& callback)  {
+
+    Return<IGnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    mGnssMeasurementCbIface = callback;
+    mGnssMeasurementCbIface->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    return mApi->measurementSetCallback(callback);
+
+}
+
+Return<void> GnssMeasurement::close()  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    if (mGnssMeasurementCbIface != nullptr) {
+        mGnssMeasurementCbIface->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface = nullptr;
+    }
+    mApi->measurementClose();
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/GnssMeasurement.h b/gps/android/1.0/GnssMeasurement.h
new file mode 100644
index 0000000..4247dbf
--- /dev/null
+++ b/gps/android/1.0/GnssMeasurement.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSMEASUREMENT_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSMEASUREMENT_H
+
+#include <android/hardware/gnss/1.0/IGnssMeasurement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class MeasurementAPIClient;
+struct GnssMeasurement : public IGnssMeasurement {
+    GnssMeasurement();
+    ~GnssMeasurement();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+     * These declarations were generated from IGnssMeasurement.hal.
+     */
+    Return<GnssMeasurement::GnssMeasurementStatus> setCallback(
+        const sp<V1_0::IGnssMeasurementCallback>& callback) override;
+    Return<void> close() override;
+
+ private:
+    struct GnssMeasurementDeathRecipient : hidl_death_recipient {
+        GnssMeasurementDeathRecipient(sp<GnssMeasurement> gnssMeasurement) :
+            mGnssMeasurement(gnssMeasurement) {
+        }
+        ~GnssMeasurementDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssMeasurement> mGnssMeasurement;
+    };
+
+ private:
+    sp<GnssMeasurementDeathRecipient> mGnssMeasurementDeathRecipient = nullptr;
+    sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface = nullptr;
+    MeasurementAPIClient* mApi;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_GNSSMEASUREMENT_H
diff --git a/gps/android/1.0/GnssNi.cpp b/gps/android/1.0/GnssNi.cpp
new file mode 100644
index 0000000..d06cc20
--- /dev/null
+++ b/gps/android/1.0/GnssNi.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssNiInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssNi.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void GnssNi::GnssNiDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    // we do nothing here
+    // Gnss::GnssDeathRecipient will stop the session
+}
+
+GnssNi::GnssNi(Gnss* gnss) : mGnss(gnss) {
+    mGnssNiDeathRecipient = new GnssNiDeathRecipient(this);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    mGnss->setGnssNiCb(callback);
+
+    if (mGnssNiCbIface != nullptr) {
+        mGnssNiCbIface->unlinkToDeath(mGnssNiDeathRecipient);
+    }
+    mGnssNiCbIface = callback;
+    if (mGnssNiCbIface != nullptr) {
+        mGnssNiCbIface->linkToDeath(mGnssNiDeathRecipient, 0 /*cookie*/);
+    }
+
+    return Void();
+}
+
+Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    GnssAPIClient* api = mGnss->getApi();
+    if (api == nullptr) {
+        LOC_LOGE("%s]: api is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    api->gnssNiRespond(notifId, userResponse);
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/GnssNi.h b/gps/android/1.0/GnssNi.h
new file mode 100644
index 0000000..90f62d5
--- /dev/null
+++ b/gps/android/1.0/GnssNi.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GNSSNI_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GNSSNI_H
+
+#include <android/hardware/gnss/1.0/IGnssNi.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssNi;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct GnssNi : public IGnssNi {
+    GnssNi(Gnss* gnss);
+    ~GnssNi() = default;
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+     * These declarations were generated from IGnssNi.hal.
+     */
+    Return<void> setCallback(const sp<IGnssNiCallback>& callback) override;
+    Return<void> respond(int32_t notifId,
+                         IGnssNiCallback::GnssUserResponseType userResponse) override;
+
+ private:
+    struct GnssNiDeathRecipient : hidl_death_recipient {
+        GnssNiDeathRecipient(sp<GnssNi> gnssNi) : mGnssNi(gnssNi) {
+        }
+        ~GnssNiDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssNi> mGnssNi;
+    };
+
+ private:
+    sp<GnssNiDeathRecipient> mGnssNiDeathRecipient = nullptr;
+    sp<IGnssNiCallback> mGnssNiCbIface = nullptr;
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_GNSSNI_H
diff --git a/gps/android/1.0/android.hardware.gnss@1.0-service-qti.rc b/gps/android/1.0/android.hardware.gnss@1.0-service-qti.rc
new file mode 100644
index 0000000..1fbd893
--- /dev/null
+++ b/gps/android/1.0/android.hardware.gnss@1.0-service-qti.rc
@@ -0,0 +1,4 @@
+service gnss_service /vendor/bin/hw/android.hardware.gnss@1.0-service-qti
+    class hal
+    user gps
+    group system gps radio vendor_qti_diag
diff --git a/gps/android/1.0/android.hardware.gnss@1.0-service-qti.xml b/gps/android/1.0/android.hardware.gnss@1.0-service-qti.xml
new file mode 100644
index 0000000..46bcffb
--- /dev/null
+++ b/gps/android/1.0/android.hardware.gnss@1.0-service-qti.xml
@@ -0,0 +1,35 @@
+<!-- Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.gnss</name>
+        <transport>hwbinder</transport>
+        <fqname>@1.0::IGnss/default</fqname>
+    </hal>
+</manifest>
+
diff --git a/gps/android/1.0/location_api/BatchingAPIClient.cpp b/gps/android/1.0/location_api/BatchingAPIClient.cpp
new file mode 100644
index 0000000..94a234d
--- /dev/null
+++ b/gps/android/1.0/location_api/BatchingAPIClient.cpp
@@ -0,0 +1,197 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_BatchingAPIClient"
+
+#include <inttypes.h>
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "BatchingAPIClient.h"
+
+#include "limits.h"
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssBatching;
+using ::android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+        LocationCapabilitiesMask mask);
+
+BatchingAPIClient::BatchingAPIClient(const sp<IGnssBatchingCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssBatchingCbIface(callback),
+    mDefaultId(UINT_MAX),
+    mLocationCapabilitiesMask(0)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+    if (mGnssBatchingCbIface != nullptr) {
+        locationCallbacks.batchingCb = [this](size_t count, Location* location,
+            BatchingOptions batchOptions) {
+            onBatchingCb(count, location, batchOptions);
+        };
+    }
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+BatchingAPIClient::~BatchingAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+int BatchingAPIClient::getBatchSize()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    return locAPIGetBatchSize();
+}
+
+int BatchingAPIClient::startSession(const IGnssBatching::Options& opts)
+{
+    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+    int retVal = -1;
+    LocationOptions options;
+    convertBatchOption(opts, options, mLocationCapabilitiesMask);
+    uint32_t mode = 0;
+    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+        mode = SESSION_MODE_ON_FULL;
+    }
+    if (locAPIStartSession(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+int BatchingAPIClient::updateSessionOptions(const IGnssBatching::Options& opts)
+{
+    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+    int retVal = -1;
+    LocationOptions options;
+    convertBatchOption(opts, options, mLocationCapabilitiesMask);
+
+    uint32_t mode = 0;
+    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+        mode = SESSION_MODE_ON_FULL;
+    }
+    if (locAPIUpdateSessionOptions(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+int BatchingAPIClient::stopSession()
+{
+    LOC_LOGD("%s]: ", __FUNCTION__);
+    int retVal = -1;
+    if (locAPIStopSession(mDefaultId) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+void BatchingAPIClient::getBatchedLocation(int last_n_locations)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, last_n_locations);
+    locAPIGetBatchedLocations(mDefaultId, last_n_locations);
+}
+
+void BatchingAPIClient::flushBatchedLocations()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
+}
+
+void BatchingAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+    LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
+    mLocationCapabilitiesMask = capabilitiesMask;
+}
+
+void BatchingAPIClient::onBatchingCb(size_t count, Location* location,
+        BatchingOptions /*batchOptions*/)
+{
+    LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, count);
+    if (mGnssBatchingCbIface != nullptr && count > 0) {
+        hidl_vec<GnssLocation> locationVec;
+        locationVec.resize(count);
+        for (size_t i = 0; i < count; i++) {
+            convertGnssLocation(location[i], locationVec[i]);
+        }
+        auto r = mGnssBatchingCbIface->gnssLocationBatchCb(locationVec);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationBatchCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+        LocationCapabilitiesMask mask)
+{
+    memset(&out, 0, sizeof(LocationOptions));
+    out.size = sizeof(LocationOptions);
+    out.minInterval = (uint32_t)(in.periodNanos / 1000000L);
+    out.minDistance = 0;
+    out.mode = GNSS_SUPL_MODE_STANDALONE;
+    if (mask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+        out.mode = GNSS_SUPL_MODE_MSA;
+    if (mask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+        out.mode = GNSS_SUPL_MODE_MSB;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/location_api/BatchingAPIClient.h b/gps/android/1.0/location_api/BatchingAPIClient.h
new file mode 100644
index 0000000..c3b0a7b
--- /dev/null
+++ b/gps/android/1.0/location_api/BatchingAPIClient.h
@@ -0,0 +1,75 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef BATCHING_API_CLINET_H
+#define BATCHING_API_CLINET_H
+
+#include <android/hardware/gnss/1.0/IGnssBatching.h>
+#include <android/hardware/gnss/1.0/IGnssBatchingCallback.h>
+#include <pthread.h>
+
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+class BatchingAPIClient : public LocationAPIClientBase
+{
+public:
+    BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback);
+    int getBatchSize();
+    int startSession(const V1_0::IGnssBatching::Options& options);
+    int updateSessionOptions(const V1_0::IGnssBatching::Options& options);
+    int stopSession();
+    void getBatchedLocation(int last_n_locations);
+    void flushBatchedLocations();
+
+    inline LocationCapabilitiesMask getCapabilities() { return mLocationCapabilitiesMask; }
+
+    // callbacks
+    void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+    void onBatchingCb(size_t count, Location* location, BatchingOptions batchOptions) final;
+
+private:
+    ~BatchingAPIClient();
+
+    sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface;
+    uint32_t mDefaultId;
+    LocationCapabilitiesMask mLocationCapabilitiesMask;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // BATCHING_API_CLINET_H
diff --git a/gps/android/1.0/location_api/GeofenceAPIClient.cpp b/gps/android/1.0/location_api/GeofenceAPIClient.cpp
new file mode 100644
index 0000000..774a049
--- /dev/null
+++ b/gps/android/1.0/location_api/GeofenceAPIClient.cpp
@@ -0,0 +1,275 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_GeofenceApiClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GeofenceAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+GeofenceAPIClient::GeofenceAPIClient(const sp<IGnssGeofenceCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssGeofencingCbIface(callback)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+
+    locationCallbacks.geofenceBreachCb = nullptr;
+    if (mGnssGeofencingCbIface != nullptr) {
+        locationCallbacks.geofenceBreachCb =
+            [this](GeofenceBreachNotification geofenceBreachNotification) {
+                onGeofenceBreachCb(geofenceBreachNotification);
+            };
+
+        locationCallbacks.geofenceStatusCb =
+            [this](GeofenceStatusNotification geofenceStatusNotification) {
+                onGeofenceStatusCb(geofenceStatusNotification);
+            };
+    }
+
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+void GeofenceAPIClient::geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+        double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+        uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms)
+{
+    LOC_LOGD("%s]: (%d %f %f %f %d %d %d %d)", __FUNCTION__,
+            geofence_id, latitude, longitude, radius_meters,
+            last_transition, monitor_transitions, notification_responsiveness_ms, unknown_timer_ms);
+
+    GeofenceOption options;
+    memset(&options, 0, sizeof(GeofenceOption));
+    options.size = sizeof(GeofenceOption);
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+        options.breachTypeMask |= GEOFENCE_BREACH_ENTER_BIT;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+        options.breachTypeMask |=  GEOFENCE_BREACH_EXIT_BIT;
+    options.responsiveness = notification_responsiveness_ms;
+
+    GeofenceInfo data;
+    data.size = sizeof(GeofenceInfo);
+    data.latitude = latitude;
+    data.longitude = longitude;
+    data.radius = radius_meters;
+
+    LocationError err = (LocationError)locAPIAddGeofences(1, &geofence_id, &options, &data);
+    if (LOCATION_ERROR_SUCCESS != err) {
+        onAddGeofencesCb(1, &err, &geofence_id);
+    }
+}
+
+void GeofenceAPIClient::geofencePause(uint32_t geofence_id)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+    locAPIPauseGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceResume(uint32_t geofence_id, int32_t monitor_transitions)
+{
+    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, geofence_id, monitor_transitions);
+    GeofenceBreachTypeMask mask = 0;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+        mask |= GEOFENCE_BREACH_ENTER_BIT;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+        mask |=  GEOFENCE_BREACH_EXIT_BIT;
+    locAPIResumeGeofences(1, &geofence_id, &mask);
+}
+
+void GeofenceAPIClient::geofenceRemove(uint32_t geofence_id)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+    locAPIRemoveGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceRemoveAll()
+{
+    LOC_LOGD("%s]", __FUNCTION__);
+    // TODO locAPIRemoveAllGeofences();
+}
+
+// callbacks
+void GeofenceAPIClient::onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, geofenceBreachNotification.count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < geofenceBreachNotification.count; i++) {
+            GnssLocation gnssLocation;
+            convertGnssLocation(geofenceBreachNotification.location, gnssLocation);
+
+            IGnssGeofenceCallback::GeofenceTransition transition;
+            if (geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER)
+                transition = IGnssGeofenceCallback::GeofenceTransition::ENTERED;
+            else if (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT)
+                transition = IGnssGeofenceCallback::GeofenceTransition::EXITED;
+            else {
+                // continue with other breach if transition is
+                // nether GPS_GEOFENCE_ENTERED nor GPS_GEOFENCE_EXITED
+                continue;
+            }
+
+            auto r = mGnssGeofencingCbIface->gnssGeofenceTransitionCb(
+                    geofenceBreachNotification.ids[i], gnssLocation, transition,
+                    static_cast<V1_0::GnssUtcTime>(geofenceBreachNotification.timestamp));
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceTransitionCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceStatusNotification.available);
+    if (mGnssGeofencingCbIface != nullptr) {
+        IGnssGeofenceCallback::GeofenceAvailability status =
+            IGnssGeofenceCallback::GeofenceAvailability::UNAVAILABLE;
+        if (geofenceStatusNotification.available == GEOFENCE_STATUS_AVAILABILE_YES) {
+            status = IGnssGeofenceCallback::GeofenceAvailability::AVAILABLE;
+        }
+        GnssLocation gnssLocation;
+        memset(&gnssLocation, 0, sizeof(GnssLocation));
+        auto r = mGnssGeofencingCbIface->gnssGeofenceStatusCb(status, gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssGeofenceStatusCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GeofenceAPIClient::onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_EXISTS)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_EXISTS;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceAddCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceAddCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceRemoveCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceRemoveCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofencePauseCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofencePauseCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceResumeCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceResumeCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/location_api/GeofenceAPIClient.h b/gps/android/1.0/location_api/GeofenceAPIClient.h
new file mode 100644
index 0000000..b6a009b
--- /dev/null
+++ b/gps/android/1.0/location_api/GeofenceAPIClient.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GEOFENCE_API_CLINET_H
+#define GEOFENCE_API_CLINET_H
+
+
+#include <android/hardware/gnss/1.0/IGnssGeofenceCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class GeofenceAPIClient : public LocationAPIClientBase
+{
+public:
+    GeofenceAPIClient(const sp<V1_0::IGnssGeofenceCallback>& callback);
+
+    void geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+            double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+            uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms);
+    void geofencePause(uint32_t geofence_id);
+    void geofenceResume(uint32_t geofence_id, int32_t monitor_transitions);
+    void geofenceRemove(uint32_t geofence_id);
+    void geofenceRemoveAll();
+
+    // callbacks
+    void onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification) final;
+    void onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification) final;
+    void onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+
+private:
+    virtual ~GeofenceAPIClient() = default;
+
+    sp<V1_0::IGnssGeofenceCallback> mGnssGeofencingCbIface;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // GEOFENCE_API_CLINET_H
diff --git a/gps/android/1.0/location_api/GnssAPIClient.cpp b/gps/android/1.0/location_api/GnssAPIClient.cpp
new file mode 100644
index 0000000..4247258
--- /dev/null
+++ b/gps/android/1.0/location_api/GnssAPIClient.cpp
@@ -0,0 +1,565 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_GnssAPIClient"
+#define SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC (590 * 60 * 60 * 1000) // 590 hours
+
+#include <inttypes.h>
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GnssAPIClient.h"
+#include <LocContext.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnss;
+using ::android::hardware::gnss::V1_0::IGnssCallback;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out);
+
+GnssAPIClient::GnssAPIClient(const sp<IGnssCallback>& gpsCb,
+    const sp<IGnssNiCallback>& niCb) :
+    LocationAPIClientBase(),
+    mGnssCbIface(nullptr),
+    mGnssNiCbIface(nullptr),
+    mControlClient(new LocationAPIControlClient()),
+    mLocationCapabilitiesMask(0),
+    mLocationCapabilitiesCached(false)
+{
+    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+    // set default LocationOptions.
+    memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+    mTrackingOptions.size = sizeof(TrackingOptions);
+    mTrackingOptions.minInterval = 1000;
+    mTrackingOptions.minDistance = 0;
+    mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+
+    gnssUpdateCallbacks(gpsCb, niCb);
+}
+
+GnssAPIClient::~GnssAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    if (mControlClient) {
+        delete mControlClient;
+        mControlClient = nullptr;
+    }
+}
+
+// for GpsInterface
+void GnssAPIClient::gnssUpdateCallbacks(const sp<IGnssCallback>& gpsCb,
+    const sp<IGnssNiCallback>& niCb)
+{
+    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+    mMutex.lock();
+    mGnssCbIface = gpsCb;
+    mGnssNiCbIface = niCb;
+    mMutex.unlock();
+
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    if (mGnssCbIface != nullptr) {
+        locationCallbacks.trackingCb = [this](Location location) {
+            onTrackingCb(location);
+        };
+    }
+
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+
+    locationCallbacks.gnssNiCb = nullptr;
+    loc_core::ContextBase* context =
+            loc_core::LocContext::getLocContext(loc_core::LocContext::mLocationHalName);
+    if (mGnssNiCbIface != nullptr && !context->hasAgpsExtendedCapabilities()) {
+        LOC_LOGD("Registering NI CB");
+        locationCallbacks.gnssNiCb = [this](uint32_t id, GnssNiNotification gnssNiNotification) {
+            onGnssNiCb(id, gnssNiNotification);
+        };
+    }
+
+    locationCallbacks.gnssSvCb = nullptr;
+    if (mGnssCbIface != nullptr) {
+        locationCallbacks.gnssSvCb = [this](GnssSvNotification gnssSvNotification) {
+            onGnssSvCb(gnssSvNotification);
+        };
+    }
+
+    locationCallbacks.gnssNmeaCb = nullptr;
+    if (mGnssCbIface != nullptr) {
+        locationCallbacks.gnssNmeaCb = [this](GnssNmeaNotification gnssNmeaNotification) {
+            onGnssNmeaCb(gnssNmeaNotification);
+        };
+    }
+
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+bool GnssAPIClient::gnssStart()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    bool retVal = true;
+    locAPIStartTracking(mTrackingOptions);
+    return retVal;
+}
+
+bool GnssAPIClient::gnssStop()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    bool retVal = true;
+    locAPIStopTracking();
+    return retVal;
+}
+
+bool GnssAPIClient::gnssSetPositionMode(IGnss::GnssPositionMode mode,
+        IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs,
+        uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs,
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LOC_LOGD("%s]: (%d %d %d %d %d %d %d)", __FUNCTION__,
+            (int)mode, recurrence, minIntervalMs, preferredAccuracyMeters,
+            preferredTimeMs, (int)powerMode, timeBetweenMeasurement);
+    bool retVal = true;
+    memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+    mTrackingOptions.size = sizeof(TrackingOptions);
+    mTrackingOptions.minInterval = minIntervalMs;
+    if (IGnss::GnssPositionMode::MS_ASSISTED == mode ||
+            IGnss::GnssPositionRecurrence::RECURRENCE_SINGLE == recurrence) {
+        // We set a very large interval to simulate SINGLE mode. Once we report a fix,
+        // the caller should take the responsibility to stop the session.
+        // For MSA, we always treat it as SINGLE mode.
+        mTrackingOptions.minInterval = SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC;
+    }
+    if (mode == IGnss::GnssPositionMode::STANDALONE)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+    else if (mode == IGnss::GnssPositionMode::MS_BASED)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_MSB;
+    else if (mode ==  IGnss::GnssPositionMode::MS_ASSISTED)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_MSA;
+    else {
+        LOC_LOGD("%s]: invalid GnssPositionMode: %d", __FUNCTION__, (int)mode);
+        retVal = false;
+    }
+    if (GNSS_POWER_MODE_INVALID != powerMode) {
+        mTrackingOptions.powerMode = powerMode;
+        mTrackingOptions.tbm = timeBetweenMeasurement;
+    }
+    locAPIUpdateTrackingOptions(mTrackingOptions);
+    return retVal;
+}
+
+// for GpsNiInterface
+void GnssAPIClient::gnssNiRespond(int32_t notifId,
+        IGnssNiCallback::GnssUserResponseType userResponse)
+{
+    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, notifId, static_cast<int>(userResponse));
+    GnssNiResponse data;
+    switch (userResponse) {
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT:
+        data = GNSS_NI_RESPONSE_ACCEPT;
+        break;
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY:
+        data = GNSS_NI_RESPONSE_DENY;
+        break;
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP:
+        data = GNSS_NI_RESPONSE_NO_RESPONSE;
+        break;
+    default:
+        data = GNSS_NI_RESPONSE_IGNORE;
+        break;
+    }
+
+    locAPIGnssNiResponse(notifId, data);
+}
+
+// these apis using LocationAPIControlClient
+void GnssAPIClient::gnssDeleteAidingData(IGnss::GnssAidingData aidingDataFlags)
+{
+    LOC_LOGD("%s]: (%02hx)", __FUNCTION__, aidingDataFlags);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    GnssAidingData data;
+    memset(&data, 0, sizeof (GnssAidingData));
+    data.sv.svTypeMask = GNSS_AIDING_DATA_SV_TYPE_GPS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT;
+    data.posEngineMask = STANDARD_POSITIONING_ENGINE;
+
+    if (aidingDataFlags == IGnss::GnssAidingData::DELETE_ALL)
+        data.deleteAll = true;
+    else {
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_EPHEMERIS)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_EPHEMERIS_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_ALMANAC)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_ALMANAC_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_POSITION)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_POSITION_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_TIME)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_TIME_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_IONO)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_IONOSPHERE_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_UTC)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_UTC_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_HEALTH)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_HEALTH_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVDIR)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_DIRECTION_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVSTEER)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_STEER_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SADATA)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_SA_DATA_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_RTI)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_RTI_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_CELLDB_INFO)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_CELLDB_BIT;
+    }
+    mControlClient->locAPIGnssDeleteAidingData(data);
+}
+
+void GnssAPIClient::gnssEnable(LocationTechnologyType techType)
+{
+    LOC_LOGD("%s]: (%0d)", __FUNCTION__, techType);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIEnable(techType);
+}
+
+void GnssAPIClient::gnssDisable()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIDisable();
+}
+
+void GnssAPIClient::gnssConfigurationUpdate(const GnssConfig& gnssConfig)
+{
+    LOC_LOGD("%s]: (%02x)", __FUNCTION__, gnssConfig.flags);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIGnssUpdateConfig(gnssConfig);
+}
+
+void GnssAPIClient::requestCapabilities() {
+    // only send capablities if it's already cached, otherwise the first time LocationAPI
+    // is initialized, capabilities will be sent by LocationAPI
+    if (mLocationCapabilitiesCached) {
+        onCapabilitiesCb(mLocationCapabilitiesMask);
+    }
+}
+
+// callbacks
+void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+    LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
+    mLocationCapabilitiesMask = capabilitiesMask;
+    mLocationCapabilitiesCached = true;
+
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr) {
+        uint32_t data = 0;
+        if ((capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT))
+            data |= IGnssCallback::Capabilities::SCHEDULING;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GEOFENCE_BIT)
+            data |= IGnssCallback::Capabilities::GEOFENCING;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT)
+            data |= IGnssCallback::Capabilities::MEASUREMENTS;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+            data |= IGnssCallback::Capabilities::MSB;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+            data |= IGnssCallback::Capabilities::MSA;
+        auto r = gnssCbIface->gnssSetCapabilitesCb(data);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSetCapabilitesCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+    if (gnssCbIface != nullptr) {
+        IGnssCallback::GnssSystemInfo gnssInfo = { .yearOfHw = 2015 };
+
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT) {
+            gnssInfo.yearOfHw++; // 2016
+            if (capabilitiesMask & LOCATION_CAPABILITIES_DEBUG_NMEA_BIT) {
+                gnssInfo.yearOfHw++; // 2017
+                if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT ||
+                    capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT) {
+                    gnssInfo.yearOfHw++; // 2018
+                }
+            }
+        }
+        LOC_LOGV("%s:%d] set_system_info_cb (%d)", __FUNCTION__, __LINE__, gnssInfo.yearOfHw);
+        auto r = gnssCbIface->gnssSetSystemInfoCb(gnssInfo);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onTrackingCb(Location location)
+{
+    LOC_LOGD("%s]: (flags: %02x)", __FUNCTION__, location.flags);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr) {
+        GnssLocation gnssLocation;
+        convertGnssLocation(location, gnssLocation);
+        auto r = gnssCbIface->gnssLocationCb(gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification)
+{
+    LOC_LOGD("%s]: (id: %d)", __FUNCTION__, id);
+    mMutex.lock();
+    auto gnssNiCbIface(mGnssNiCbIface);
+    mMutex.unlock();
+
+    if (gnssNiCbIface == nullptr) {
+        LOC_LOGE("%s]: mGnssNiCbIface is nullptr", __FUNCTION__);
+        return;
+    }
+
+    IGnssNiCallback::GnssNiNotification notificationGnss = {};
+
+    notificationGnss.notificationId = id;
+
+    if (gnssNiNotification.type == GNSS_NI_TYPE_VOICE)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::VOICE;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_SUPL)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_SUPL;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_CONTROL_PLANE)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_CTRL_PLANE;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_EMERGENCY_SUPL)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::EMERGENCY_SUPL;
+
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_NOTIFICATION_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_NOTIFY;
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_VERIFICATION_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_VERIFY;
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::PRIVACY_OVERRIDE;
+
+    notificationGnss.timeoutSec = gnssNiNotification.timeout;
+
+    if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_ACCEPT)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT;
+    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_DENY)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY;
+    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_NO_RESPONSE ||
+            gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_IGNORE)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP;
+
+    notificationGnss.requestorId = gnssNiNotification.requestor;
+
+    notificationGnss.notificationMessage = gnssNiNotification.message;
+
+    if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+    if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+    gnssNiCbIface->niNotifyCb(notificationGnss);
+}
+
+void GnssAPIClient::onGnssSvCb(GnssSvNotification gnssSvNotification)
+{
+    LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, gnssSvNotification.count);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr) {
+        IGnssCallback::GnssSvStatus svStatus;
+        convertGnssSvStatus(gnssSvNotification, svStatus);
+        auto r = gnssCbIface->gnssSvStatusCb(svStatus);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSvStatusCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
+{
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr) {
+        const std::string s(gnssNmeaNotification.nmea);
+        std::stringstream ss(s);
+        std::string each;
+        while(std::getline(ss, each, '\n')) {
+            each += '\n';
+            android::hardware::hidl_string nmeaString;
+            nmeaString.setToExternal(each.c_str(), each.length());
+            auto r = gnssCbIface->gnssNmeaCb(
+                    static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%zu description=%s", __func__,
+                            gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+                            r.description().c_str());
+            }
+        }
+    }
+}
+
+void GnssAPIClient::onStartTrackingCb(LocationError error)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (error == LOCATION_ERROR_SUCCESS && gnssCbIface != nullptr) {
+        auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssStatusCb ENGINE_ON description=%s",
+                __func__, r.description().c_str());
+        }
+        r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssStatusCb SESSION_BEGIN description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onStopTrackingCb(LocationError error)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (error == LOCATION_ERROR_SUCCESS && gnssCbIface != nullptr) {
+        auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssStatusCb SESSION_END description=%s",
+                __func__, r.description().c_str());
+        }
+        r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssStatusCb ENGINE_OFF description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out)
+{
+    memset(&out, 0, sizeof(IGnssCallback::GnssSvStatus));
+    out.numSvs = in.count;
+    if (out.numSvs > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+        LOC_LOGW("%s]: Too many satellites %u. Clamps to %d.",
+                __FUNCTION__,  out.numSvs, V1_0::GnssMax::SVS_COUNT);
+        out.numSvs = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+    }
+    for (size_t i = 0; i < out.numSvs; i++) {
+        IGnssCallback::GnssSvInfo& info = out.gnssSvList[i];
+        convertGnssSvid(in.gnssSvs[i], info.svid);
+        convertGnssConstellationType(in.gnssSvs[i].type, info.constellation);
+        info.cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+        info.elevationDegrees = in.gnssSvs[i].elevation;
+        info.azimuthDegrees = in.gnssSvs[i].azimuth;
+        info.carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+        info.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+            info.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+            info.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+            info.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+            info.svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/location_api/GnssAPIClient.h b/gps/android/1.0/location_api/GnssAPIClient.h
new file mode 100644
index 0000000..427b0db
--- /dev/null
+++ b/gps/android/1.0/location_api/GnssAPIClient.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GNSS_API_CLINET_H
+#define GNSS_API_CLINET_H
+
+
+#include <mutex>
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/1.0/IGnssCallback.h>
+#include <android/hardware/gnss/1.0/IGnssNiCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class GnssAPIClient : public LocationAPIClientBase
+{
+public:
+    GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+            const sp<V1_0::IGnssNiCallback>& niCb);
+    GnssAPIClient(const GnssAPIClient&) = delete;
+    GnssAPIClient& operator=(const GnssAPIClient&) = delete;
+
+    // for GpsInterface
+    void gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+            const sp<V1_0::IGnssNiCallback>& niCb);
+    bool gnssStart();
+    bool gnssStop();
+    bool gnssSetPositionMode(V1_0::IGnss::GnssPositionMode mode,
+            V1_0::IGnss::GnssPositionRecurrence recurrence,
+            uint32_t minIntervalMs,
+            uint32_t preferredAccuracyMeters,
+            uint32_t preferredTimeMs,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = 0);
+
+    // for GpsNiInterface
+    void gnssNiRespond(int32_t notifId, V1_0::IGnssNiCallback::GnssUserResponseType userResponse);
+
+    // these apis using LocationAPIControlClient
+    void gnssDeleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags);
+    void gnssEnable(LocationTechnologyType techType);
+    void gnssDisable();
+    void gnssConfigurationUpdate(const GnssConfig& gnssConfig);
+
+    inline LocationCapabilitiesMask gnssGetCapabilities() const {
+        return mLocationCapabilitiesMask;
+    }
+    void requestCapabilities();
+
+    // callbacks we are interested in
+    void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+    void onTrackingCb(Location location) final;
+    void onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification) final;
+    void onGnssSvCb(GnssSvNotification gnssSvNotification) final;
+    void onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification) final;
+
+    void onStartTrackingCb(LocationError error) final;
+    void onStopTrackingCb(LocationError error) final;
+
+private:
+    virtual ~GnssAPIClient();
+
+    sp<V1_0::IGnssCallback> mGnssCbIface;
+    sp<V1_0::IGnssNiCallback> mGnssNiCbIface;
+    std::mutex mMutex;
+    LocationAPIControlClient* mControlClient;
+    LocationCapabilitiesMask mLocationCapabilitiesMask;
+    bool mLocationCapabilitiesCached;
+    TrackingOptions mTrackingOptions;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // GNSS_API_CLINET_H
diff --git a/gps/android/1.0/location_api/LocationUtil.cpp b/gps/android/1.0/location_api/LocationUtil.cpp
new file mode 100644
index 0000000..870a8aa
--- /dev/null
+++ b/gps/android/1.0/location_api/LocationUtil.cpp
@@ -0,0 +1,274 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <LocationUtil.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+using ::android::hardware::gnss::V1_0::GnssLocationFlags;
+
+void convertGnssLocation(Location& in, GnssLocation& out)
+{
+    memset(&out, 0, sizeof(GnssLocation));
+    if (in.flags & LOCATION_HAS_LAT_LONG_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_LAT_LONG;
+        out.latitudeDegrees = in.latitude;
+        out.longitudeDegrees = in.longitude;
+    }
+    if (in.flags & LOCATION_HAS_ALTITUDE_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE;
+        out.altitudeMeters = in.altitude;
+    }
+    if (in.flags & LOCATION_HAS_SPEED_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
+        out.speedMetersPerSec = in.speed;
+    }
+    if (in.flags & LOCATION_HAS_BEARING_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
+        out.bearingDegrees = in.bearing;
+    }
+    if (in.flags & LOCATION_HAS_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
+        out.horizontalAccuracyMeters = in.accuracy;
+    }
+    if (in.flags & LOCATION_HAS_VERTICAL_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
+        out.verticalAccuracyMeters = in.verticalAccuracy;
+    }
+    if (in.flags & LOCATION_HAS_SPEED_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
+        out.speedAccuracyMetersPerSecond = in.speedAccuracy;
+    }
+    if (in.flags & LOCATION_HAS_BEARING_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
+        out.bearingAccuracyDegrees = in.bearingAccuracy;
+    }
+
+    out.timestamp = static_cast<V1_0::GnssUtcTime>(in.timestamp);
+}
+
+void convertGnssLocation(const GnssLocation& in, Location& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG) {
+        out.flags |= LOCATION_HAS_LAT_LONG_BIT;
+        out.latitude = in.latitudeDegrees;
+        out.longitude = in.longitudeDegrees;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE) {
+        out.flags |= LOCATION_HAS_ALTITUDE_BIT;
+        out.altitude = in.altitudeMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED) {
+        out.flags |= LOCATION_HAS_SPEED_BIT;
+        out.speed = in.speedMetersPerSec;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+        out.flags |= LOCATION_HAS_BEARING_BIT;
+        out.bearing = in.bearingDegrees;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+        out.flags |= LOCATION_HAS_ACCURACY_BIT;
+        out.accuracy = in.horizontalAccuracyMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+        out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+        out.verticalAccuracy = in.verticalAccuracyMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+        out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+        out.speedAccuracy = in.speedAccuracyMetersPerSecond;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+        out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+        out.bearingAccuracy = in.bearingAccuracyDegrees;
+    }
+
+    out.timestamp = static_cast<uint64_t>(in.timestamp);
+}
+
+void convertGnssConstellationType(GnssSvType& in, GnssConstellationType& out)
+{
+    switch(in) {
+        case GNSS_SV_TYPE_GPS:
+            out = GnssConstellationType::GPS;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = GnssConstellationType::SBAS;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            out = GnssConstellationType::GLONASS;
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = GnssConstellationType::QZSS;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = GnssConstellationType::BEIDOU;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = GnssConstellationType::GALILEO;
+            break;
+        case GNSS_SV_TYPE_UNKNOWN:
+        default:
+            out = GnssConstellationType::UNKNOWN;
+            break;
+    }
+}
+
+void convertGnssSvid(GnssSv& in, int16_t& out)
+{
+    switch(in.type){
+        case GNSS_SV_TYPE_GPS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            if (!isGloSlotUnknown(in.svId)) { // OSN is known
+                out = in.svId - GLO_SV_PRN_MIN + 1;
+            } else { // OSN is not known, report FCN
+                out = in.gloFrequency + 92;
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = in.svId - BDS_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = in.svId - GAL_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = in.svId - NAVIC_SV_PRN_MIN + 1;
+            break;
+        default:
+            out = in.svId;
+            break;
+    }
+}
+
+void convertGnssSvid(GnssMeasurementsData& in, int16_t& out)
+{
+    switch (in.svType) {
+        case GNSS_SV_TYPE_GPS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            if (!isGloSlotUnknown(in.svId)) { // OSN is known
+                out = in.svId - GLO_SV_PRN_MIN + 1;
+            } else { // OSN is not known, report FCN
+                out = in.gloFrequency + 92;
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = in.svId - BDS_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = in.svId - GAL_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = in.svId - NAVIC_SV_PRN_MIN + 1;
+            break;
+        default:
+            out = in.svId;
+            break;
+    }
+}
+
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out)
+{
+    switch(in) {
+        case GNSS_EPH_TYPE_EPHEMERIS:
+            out = GnssDebug::SatelliteEphemerisType::EPHEMERIS;
+            break;
+        case GNSS_EPH_TYPE_ALMANAC:
+            out = GnssDebug::SatelliteEphemerisType::ALMANAC_ONLY;
+            break;
+        case GNSS_EPH_TYPE_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisType::NOT_AVAILABLE;
+            break;
+    }
+}
+
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out)
+{
+    switch(in) {
+        case GNSS_EPH_SOURCE_DEMODULATED:
+            out = GnssDebug::SatelliteEphemerisSource::DEMODULATED;
+            break;
+        case GNSS_EPH_SOURCE_SUPL_PROVIDED:
+            out = GnssDebug::SatelliteEphemerisSource::SUPL_PROVIDED;
+            break;
+        case GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED:
+            out = GnssDebug::SatelliteEphemerisSource::OTHER_SERVER_PROVIDED;
+            break;
+        case GNSS_EPH_SOURCE_LOCAL:
+        case GNSS_EPH_SOURCE_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisSource::OTHER;
+            break;
+    }
+}
+
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out)
+{
+    switch(in) {
+        case GNSS_EPH_HEALTH_GOOD:
+            out = GnssDebug::SatelliteEphemerisHealth::GOOD;
+            break;
+        case GNSS_EPH_HEALTH_BAD:
+            out = GnssDebug::SatelliteEphemerisHealth::BAD;
+            break;
+        case GNSS_EPH_HEALTH_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisHealth::UNKNOWN;
+            break;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/location_api/LocationUtil.h b/gps/android/1.0/location_api/LocationUtil.h
new file mode 100644
index 0000000..f6760e5
--- /dev/null
+++ b/gps/android/1.0/location_api/LocationUtil.h
@@ -0,0 +1,57 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOCATION_UTIL_H
+#define LOCATION_UTIL_H
+
+#include <android/hardware/gnss/1.0/types.h>
+#include <LocationAPI.h>
+#include <GnssDebug.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out);
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out);
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out);
+void convertGnssSvid(GnssSv& in, int16_t& out);
+void convertGnssSvid(GnssMeasurementsData& in, int16_t& out);
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out);
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out);
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // LOCATION_UTIL_H
diff --git a/gps/android/1.0/location_api/MeasurementAPIClient.cpp b/gps/android/1.0/location_api/MeasurementAPIClient.cpp
new file mode 100644
index 0000000..9b23308
--- /dev/null
+++ b/gps/android/1.0/location_api/MeasurementAPIClient.cpp
@@ -0,0 +1,276 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_MeasurementAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "MeasurementAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V1_0::IGnssMeasurementCallback;
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+        V1_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+        V1_0::IGnssMeasurementCallback::GnssMeasurement& out);
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out);
+
+MeasurementAPIClient::MeasurementAPIClient() :
+    mGnssMeasurementCbIface(nullptr),
+    mTracking(false)
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+MeasurementAPIClient::~MeasurementAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+// for GpsInterface
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback(const sp<V1_0::IGnssMeasurementCallback>& callback)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    mMutex.lock();
+    mGnssMeasurementCbIface = callback;
+    mMutex.unlock();
+
+    return startTracking();
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::startTracking()
+{
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+    if (mGnssMeasurementCbIface != nullptr) {
+        locationCallbacks.gnssMeasurementsCb =
+            [this](GnssMeasurementsNotification gnssMeasurementsNotification) {
+                onGnssMeasurementsCb(gnssMeasurementsNotification);
+            };
+    }
+
+    locAPISetCallbacks(locationCallbacks);
+
+    TrackingOptions options = {};
+    memset(&options, 0, sizeof(TrackingOptions));
+    options.size = sizeof(TrackingOptions);
+    options.minInterval = 1000;
+    options.mode = GNSS_SUPL_MODE_STANDALONE;
+
+    mTracking = true;
+    LOC_LOGD("%s]: start tracking session", __FUNCTION__);
+    locAPIStartTracking(options);
+    return IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+// for GpsMeasurementInterface
+void MeasurementAPIClient::measurementClose() {
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    mTracking = false;
+    locAPIStopTracking();
+}
+
+// callbacks
+void MeasurementAPIClient::onGnssMeasurementsCb(
+        GnssMeasurementsNotification gnssMeasurementsNotification)
+{
+    LOC_LOGD("%s]: (count: %zu active: %d)",
+            __FUNCTION__, gnssMeasurementsNotification.count, mTracking);
+    if (mTracking) {
+        mMutex.lock();
+        sp<V1_0::IGnssMeasurementCallback> gnssMeasurementCbIface = nullptr;
+        if (mGnssMeasurementCbIface != nullptr) {
+            gnssMeasurementCbIface = mGnssMeasurementCbIface;
+        }
+        mMutex.unlock();
+
+        if (gnssMeasurementCbIface != nullptr) {
+            V1_0::IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface->GnssMeasurementCb(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from GnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+        V1_0::IGnssMeasurementCallback::GnssMeasurement& out)
+{
+    memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssMeasurement));
+    if (in.flags & GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SNR;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_FREQUENCY;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_CYCLES;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL;
+    convertGnssSvid(in, out.svid);
+    convertGnssConstellationType(in.svType, out.constellation);
+    out.timeOffsetNs = in.timeOffsetNs;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+    if (in.stateMask &  GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+    out.receivedSvTimeInNs = in.receivedSvTimeNs;
+    out.receivedSvTimeUncertaintyInNs = in.receivedSvTimeUncertaintyNs;
+    out.cN0DbHz = in.carrierToNoiseDbHz;
+    out.pseudorangeRateMps = in.pseudorangeRateMps;
+    out.pseudorangeRateUncertaintyMps = in.pseudorangeRateUncertaintyMps;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+    out.accumulatedDeltaRangeM = in.adrMeters;
+    out.accumulatedDeltaRangeUncertaintyM = in.adrUncertaintyMeters;
+    out.carrierFrequencyHz = in.carrierFrequencyHz;
+    out.carrierCycles = in.carrierCycles;
+    out.carrierPhase = in.carrierPhase;
+    out.carrierPhaseUncertainty = in.carrierPhaseUncertainty;
+    uint8_t indicator =
+        static_cast<uint8_t>(IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN);
+    if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_PRESENT)
+        indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_PRESENT;
+    if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_NOT_PRESENT)
+        indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATIOR_NOT_PRESENT;
+    out.multipathIndicator =
+        static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>(indicator);
+    out.snrDb = in.signalToNoiseRatioDb;
+    out.agcLevelDb = in.agcLevelDb;
+}
+
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out)
+{
+    memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssClock));
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_LEAP_SECOND_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_LEAP_SECOND;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_TIME_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_FULL_BIAS_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_FULL_BIAS;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT_UNCERTAINTY;
+    out.leapSecond = in.leapSecond;
+    out.timeNs = in.timeNs;
+    out.timeUncertaintyNs = in.timeUncertaintyNs;
+    out.fullBiasNs = in.fullBiasNs;
+    out.biasNs = in.biasNs;
+    out.biasUncertaintyNs = in.biasUncertaintyNs;
+    out.driftNsps = in.driftNsps;
+    out.driftUncertaintyNsps = in.driftUncertaintyNsps;
+    out.hwClockDiscontinuityCount = in.hwClockDiscontinuityCount;
+}
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+        V1_0::IGnssMeasurementCallback::GnssData& out)
+{
+    out.measurementCount = in.count;
+    if (out.measurementCount > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+        LOC_LOGW("%s]: Too many measurement %u. Clamps to %d.",
+                __FUNCTION__,  out.measurementCount, V1_0::GnssMax::SVS_COUNT);
+        out.measurementCount = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+    }
+    for (size_t i = 0; i < out.measurementCount; i++) {
+        convertGnssMeasurement(in.measurements[i], out.measurements[i]);
+    }
+    convertGnssClock(in.clock, out.clock);
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.0/location_api/MeasurementAPIClient.h b/gps/android/1.0/location_api/MeasurementAPIClient.h
new file mode 100644
index 0000000..225deac
--- /dev/null
+++ b/gps/android/1.0/location_api/MeasurementAPIClient.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MEASUREMENT_API_CLINET_H
+#define MEASUREMENT_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/1.0/IGnssMeasurement.h>
+#include <android/hardware/gnss/1.0/IGnssMeasurementCallback.h>
+#include <LocationAPIClientBase.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class MeasurementAPIClient : public LocationAPIClientBase
+{
+public:
+    MeasurementAPIClient();
+    MeasurementAPIClient(const MeasurementAPIClient&) = delete;
+    MeasurementAPIClient& operator=(const MeasurementAPIClient&) = delete;
+
+    // for GpsMeasurementInterface
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback(
+            const sp<V1_0::IGnssMeasurementCallback>& callback);
+    void measurementClose();
+    Return<IGnssMeasurement::GnssMeasurementStatus> startTracking();
+
+    // callbacks we are interested in
+    void onGnssMeasurementsCb(GnssMeasurementsNotification gnssMeasurementsNotification) final;
+
+private:
+    virtual ~MeasurementAPIClient();
+
+    std::mutex mMutex;
+    sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface;
+
+    bool mTracking;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // MEASUREMENT_API_CLINET_H
diff --git a/gps/android/1.0/service.cpp b/gps/android/1.0/service.cpp
new file mode 100644
index 0000000..2a6f60f
--- /dev/null
+++ b/gps/android/1.0/service.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "android.hardware.gnss@1.0-service-qti"
+
+#include <android/hardware/gnss/1.0/IGnss.h>
+#include <hidl/LegacySupport.h>
+#include "loc_cfg.h"
+#include "loc_misc_utils.h"
+
+extern "C" {
+#include "vndfwk-detect.h"
+}
+
+#ifdef ARCH_ARM_32
+#define DEFAULT_HW_BINDER_MEM_SIZE 65536
+#endif
+
+using android::hardware::gnss::V1_0::IGnss;
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::registerPassthroughServiceImplementation;
+using android::hardware::joinRpcThreadpool;
+
+using android::status_t;
+using android::OK;
+
+typedef int vendorEnhancedServiceMain(int /* argc */, char* /* argv */ []);
+
+int main() {
+
+    ALOGI("%s", __FUNCTION__);
+
+    int vendorInfo = getVendorEnhancedInfo();
+    bool vendorEnhanced = ( 1 == vendorInfo || 3 == vendorInfo );
+    setVendorEnhanced(vendorEnhanced);
+
+#ifdef ARCH_ARM_32
+    android::hardware::ProcessState::initWithMmapSize((size_t)(DEFAULT_HW_BINDER_MEM_SIZE));
+#endif
+    configureRpcThreadpool(1, true);
+    status_t status;
+
+    status = registerPassthroughServiceImplementation<IGnss>();
+    if (status == OK) {
+        if (vendorEnhanced) {
+    #ifdef LOC_HIDL_VERSION
+            #define VENDOR_ENHANCED_LIB "vendor.qti.gnss@" LOC_HIDL_VERSION "-service.so"
+
+            void* libHandle = NULL;
+            vendorEnhancedServiceMain* vendorEnhancedMainMethod = (vendorEnhancedServiceMain*)
+                    dlGetSymFromLib(libHandle, VENDOR_ENHANCED_LIB, "main");
+            if (NULL != vendorEnhancedMainMethod) {
+                (*vendorEnhancedMainMethod)(0, NULL);
+            }
+    #else
+            ALOGE("LOC_HIDL_VERSION not defined.");
+    #endif
+        }
+
+        joinRpcThreadpool();
+
+    } else {
+        ALOGE("Error while registering IGnss 1.0 service: %d", status);
+    }
+
+    return 0;
+}
diff --git a/gps/android/1.1/AGnss.cpp b/gps/android/1.1/AGnss.cpp
new file mode 100644
index 0000000..d8f9706
--- /dev/null
+++ b/gps/android/1.1/AGnss.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_AGnssInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "AGnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+static AGnss* spAGnss = nullptr;
+
+AGnss::AGnss(Gnss* gnss) : mGnss(gnss) {
+    spAGnss = this;
+}
+
+AGnss::~AGnss() {
+    spAGnss = nullptr;
+}
+
+void AGnss::agnssStatusIpV4Cb(AGnssExtStatusIpV4 status){
+    if (nullptr != spAGnss) {
+        spAGnss->statusIpV4Cb(status);
+    }
+}
+
+void AGnss::statusIpV4Cb(AGnssExtStatusIpV4 status) {
+    IAGnssCallback::AGnssStatusIpV4 st = {};
+
+    switch (status.type) {
+        case LOC_AGPS_TYPE_SUPL:
+            st.type = IAGnssCallback::AGnssType::TYPE_SUPL;
+            break;
+        case LOC_AGPS_TYPE_C2K:
+            st.type = IAGnssCallback::AGnssType::TYPE_C2K;
+            break;
+        default:
+            LOC_LOGE("invalid type: %d", status.type);
+            return;
+    }
+
+    switch (status.status) {
+        case LOC_GPS_REQUEST_AGPS_DATA_CONN:
+            st.status = IAGnssCallback::AGnssStatusValue::REQUEST_AGNSS_DATA_CONN;
+            break;
+        case LOC_GPS_RELEASE_AGPS_DATA_CONN:
+            st.status = IAGnssCallback::AGnssStatusValue::RELEASE_AGNSS_DATA_CONN;
+            break;
+        case LOC_GPS_AGPS_DATA_CONNECTED:
+            st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONNECTED;
+            break;
+        case LOC_GPS_AGPS_DATA_CONN_DONE:
+            st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_DONE;
+            break;
+        case LOC_GPS_AGPS_DATA_CONN_FAILED:
+            st.status = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_FAILED;
+            break;
+        default:
+            LOC_LOGE("invalid status: %d", status.status);
+            return;
+    }
+    st.ipV4Addr = status.ipV4Addr;
+
+    if (mAGnssCbIface != nullptr) {
+        auto r = mAGnssCbIface->agnssStatusIpV4Cb(st);
+        if (!r.isOk()) {
+            LOC_LOGw("Error invoking AGNSS status cb %s", r.description().c_str());
+        }
+    } else {
+        LOC_LOGw("setCallback has not been called yet");
+    }
+}
+
+Return<void> AGnss::setCallback(const sp<IAGnssCallback>& callback) {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return Void();
+    }
+
+    // Save the interface
+    mAGnssCbIface = callback;
+
+    AgpsCbInfo cbInfo = {};
+    cbInfo.statusV4Cb = (void*)agnssStatusIpV4Cb;
+    cbInfo.atlType = AGPS_ATL_TYPE_SUPL | AGPS_ATL_TYPE_SUPL_ES;
+
+    mGnss->getGnssInterface()->agpsInit(cbInfo);
+    return Void();
+}
+
+Return<bool> AGnss::dataConnClosed() {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnClosed(LOC_AGPS_TYPE_SUPL);
+    return true;
+}
+
+Return<bool> AGnss::dataConnFailed() {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnFailed(LOC_AGPS_TYPE_SUPL);
+    return true;
+}
+
+Return<bool> AGnss::dataConnOpen(const hidl_string& apn,
+        IAGnss::ApnIpType apnIpType) {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    /* Validate */
+    if(apn.empty()){
+        LOC_LOGE("Invalid APN");
+        return false;
+    }
+
+    LOC_LOGD("dataConnOpen APN name = [%s]", apn.c_str());
+
+    AGpsBearerType bearerType;
+    switch (apnIpType) {
+        case IAGnss::ApnIpType::IPV4:
+            bearerType = AGPS_APN_BEARER_IPV4;
+            break;
+        case IAGnss::ApnIpType::IPV6:
+            bearerType = AGPS_APN_BEARER_IPV6;
+            break;
+        case IAGnss::ApnIpType::IPV4V6:
+            bearerType = AGPS_APN_BEARER_IPV4V6;
+            break;
+        default:
+            bearerType = AGPS_APN_BEARER_IPV4;
+            break;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnOpen(
+            LOC_AGPS_TYPE_SUPL, apn.c_str(), apn.size(), (int)bearerType);
+    return true;
+}
+
+Return<bool> AGnss::setServer(IAGnssCallback::AGnssType type,
+                              const hidl_string& hostname,
+                              int32_t port) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+    config.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+    if (type == IAGnssCallback::AGnssType::TYPE_SUPL) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL;
+    } else if (type == IAGnssCallback::AGnssType::TYPE_C2K) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_C2K;
+    } else {
+        LOC_LOGE("%s]: invalid AGnssType: %d", __FUNCTION__, static_cast<int>(type));
+        return false;
+    }
+    config.assistanceServer.hostName = strdup(hostname.c_str());
+    config.assistanceServer.port = port;
+    return mGnss->updateConfiguration(config);
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/AGnss.h b/gps/android/1.1/AGnss.h
new file mode 100644
index 0000000..4b599b9
--- /dev/null
+++ b/gps/android/1.1/AGnss.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_AGNSS_H
+#define ANDROID_HARDWARE_GNSS_V1_1_AGNSS_H
+
+#include <android/hardware/gnss/1.0/IAGnss.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnss;
+using ::android::hardware::gnss::V1_0::IAGnssCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct AGnss : public IAGnss {
+
+    AGnss(Gnss* gnss);
+    ~AGnss();
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IAGnss interface follow.
+     * These declarations were generated from IAGnss.hal.
+     */
+    Return<void> setCallback(const sp<IAGnssCallback>& callback) override;
+
+    Return<bool> dataConnClosed() override;
+
+    Return<bool> dataConnFailed() override;
+
+    Return<bool> dataConnOpen(const hidl_string& apn,
+            IAGnss::ApnIpType apnIpType) override;
+
+    Return<bool> setServer(IAGnssCallback::AGnssType type,
+                         const hidl_string& hostname, int32_t port) override;
+
+    void statusIpV4Cb(AGnssExtStatusIpV4 status);
+
+    /* Data call setup callback passed down to GNSS HAL implementation */
+    static void agnssStatusIpV4Cb(AGnssExtStatusIpV4 status);
+
+ private:
+    Gnss* mGnss = nullptr;
+    sp<IAGnssCallback> mAGnssCbIface = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_AGNSS_H
diff --git a/gps/android/1.1/AGnssRil.cpp b/gps/android/1.1/AGnssRil.cpp
new file mode 100644
index 0000000..95c8d63
--- /dev/null
+++ b/gps/android/1.1/AGnssRil.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc__AGnssRilInterface"
+
+#include <log_util.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sstream>
+#include <string>
+#include "Gnss.h"
+#include "AGnssRil.h"
+#include <DataItemConcreteTypesBase.h>
+
+typedef void* (getLocationInterface)();
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+
+AGnssRil::AGnssRil(Gnss* gnss) : mGnss(gnss) {
+    ENTRY_LOG_CALLFLOW();
+}
+
+AGnssRil::~AGnssRil() {
+    ENTRY_LOG_CALLFLOW();
+}
+
+Return<bool> AGnssRil::updateNetworkState(bool connected, NetworkType type, bool /*roaming*/) {
+    ENTRY_LOG_CALLFLOW();
+    // Extra NetworkTypes not available in IAgnssRil enums
+    const int NetworkType_BLUETOOTH = 7;
+    const int NetworkType_ETHERNET = 9;
+    const int NetworkType_PROXY = 16;
+    std::string apn("");
+
+    // for XTRA
+    if (nullptr != mGnss && ( nullptr != mGnss->getGnssInterface() )) {
+        int8_t typeout = loc_core::NetworkInfoDataItemBase::TYPE_UNKNOWN;
+        switch(type)
+        {
+            case IAGnssRil::NetworkType::MOBILE:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_MOBILE;
+                break;
+            case IAGnssRil::NetworkType::WIFI:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_WIFI;
+                break;
+            case IAGnssRil::NetworkType::MMS:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_MMS;
+                break;
+            case IAGnssRil::NetworkType::SUPL:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_SUPL;
+                break;
+            case IAGnssRil::NetworkType::DUN:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_DUN;
+                break;
+            case IAGnssRil::NetworkType::HIPRI:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_HIPRI;
+                break;
+            case IAGnssRil::NetworkType::WIMAX:
+                typeout = loc_core::NetworkInfoDataItemBase::TYPE_WIMAX;
+                break;
+            default:
+                {
+                    int networkType = (int) type;
+                    // Handling network types not available in IAgnssRil
+                    switch(networkType)
+                    {
+                        case NetworkType_BLUETOOTH:
+                            typeout = loc_core::NetworkInfoDataItemBase::TYPE_BLUETOOTH;
+                            break;
+                        case NetworkType_ETHERNET:
+                            typeout = loc_core::NetworkInfoDataItemBase::TYPE_ETHERNET;
+                            break;
+                        case NetworkType_PROXY:
+                            typeout = loc_core::NetworkInfoDataItemBase::TYPE_PROXY;
+                            break;
+                        default:
+                            typeout = loc_core::NetworkInfoDataItemBase::TYPE_UNKNOWN;
+                    }
+                }
+                break;
+        }
+        mGnss->getGnssInterface()->updateConnectionStatus(connected, typeout, false, 0, apn);
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/AGnssRil.h b/gps/android/1.1/AGnssRil.h
new file mode 100644
index 0000000..5c9298a
--- /dev/null
+++ b/gps/android/1.1/AGnssRil.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
+#define ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
+
+#include <android/hardware/gnss/1.0/IAGnssRil.h>
+#include <hidl/Status.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IAGnssRil;
+using ::android::hardware::gnss::V1_0::IAGnssRilCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+/*
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface Layer interface
+ * allows the GNSS chipset to request radio interface layer information from Android platform.
+ * Examples of such information are reference location, unique subscriber ID, phone number string
+ * and network availability changes. Also contains wrapper methods to allow methods from
+ * IAGnssiRilCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+struct AGnssRil : public IAGnssRil {
+    AGnssRil(Gnss* gnss);
+    ~AGnssRil();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow.
+     * These declarations were generated from IAGnssRil.hal.
+     */
+    Return<void> setCallback(const sp<IAGnssRilCallback>& /*callback*/) override {
+        return Void();
+    }
+    Return<void> setRefLocation(const IAGnssRil::AGnssRefLocation& /*agnssReflocation*/) override {
+        return Void();
+    }
+    Return<bool> setSetId(IAGnssRil::SetIDType /*type*/, const hidl_string& /*setid*/) override {
+        return false;
+    }
+    Return<bool> updateNetworkAvailability(bool /*available*/,
+                                    const hidl_string& /*apn*/) override {
+        return false;
+    }
+    Return<bool> updateNetworkState(bool connected, NetworkType type, bool roaming) override;
+
+ private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_AGNSSRIL_H_
diff --git a/gps/android/1.1/Android.mk b/gps/android/1.1/Android.mk
new file mode 100644
index 0000000..edf8547
--- /dev/null
+++ b/gps/android/1.1/Android.mk
@@ -0,0 +1,101 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.1-impl-qti
+
+# activate the following line for debug purposes only, comment out for production
+#LOCAL_SANITIZE_DIAG += $(GNSS_SANITIZE_DIAG)
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+    AGnss.cpp \
+    Gnss.cpp \
+    GnssBatching.cpp \
+    GnssGeofencing.cpp \
+    GnssMeasurement.cpp \
+    GnssNi.cpp \
+    GnssConfiguration.cpp \
+    GnssDebug.cpp \
+    AGnssRil.cpp
+
+LOCAL_SRC_FILES += \
+    location_api/LocationUtil.cpp \
+    location_api/GnssAPIClient.cpp \
+    location_api/GeofenceAPIClient.cpp \
+    location_api/BatchingAPIClient.cpp \
+    location_api/MeasurementAPIClient.cpp \
+
+LOCAL_C_INCLUDES:= \
+    $(LOCAL_PATH)/location_api
+LOCAL_HEADER_LIBRARIES := \
+    libgps.utils_headers \
+    libloc_core_headers \
+    libloc_pla_headers \
+    liblocation_api_headers \
+    liblocbatterylistener_headers
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libhidlbase \
+    libcutils \
+    libutils \
+    android.hardware.gnss@1.0 \
+    android.hardware.gnss@1.1 \
+    android.hardware.health@1.0 \
+    android.hardware.health@2.0 \
+    android.hardware.power@1.2 \
+    libbase
+
+LOCAL_SHARED_LIBRARIES += \
+    libloc_core \
+    libgps.utils \
+    libdl \
+    liblocation_api \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@1.1-service-qti
+
+# activate the following line for debug purposes only, comment out for production
+#LOCAL_SANITIZE_DIAG += $(GNSS_SANITIZE_DIAG)
+LOCAL_VINTF_FRAGMENTS := android.hardware.gnss@1.1-service-qti.xml
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_INIT_RC := android.hardware.gnss@1.1-service-qti.rc
+LOCAL_SRC_FILES := \
+    service.cpp \
+
+LOCAL_C_INCLUDES:= \
+    $(LOCAL_PATH)/location_api
+LOCAL_HEADER_LIBRARIES := \
+    libgps.utils_headers \
+    libloc_core_headers \
+    libloc_pla_headers \
+    liblocation_api_headers
+
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libcutils \
+    libdl \
+    libbase \
+    libutils \
+    libgps.utils \
+    libqti_vndfwk_detect \
+
+LOCAL_SHARED_LIBRARIES += \
+    libhidlbase \
+    android.hardware.gnss@1.0 \
+    android.hardware.gnss@1.1 \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+ifneq ($(LOC_HIDL_VERSION),)
+LOCAL_CFLAGS += -DLOC_HIDL_VERSION='"$(LOC_HIDL_VERSION)"'
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/gps/android/1.1/Gnss.cpp b/gps/android/1.1/Gnss.cpp
new file mode 100644
index 0000000..537f6a6
--- /dev/null
+++ b/gps/android/1.1/Gnss.cpp
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
+
+#include <fstream>
+#include <log_util.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "Gnss.h"
+#include <LocationUtil.h>
+
+#include "battery_listener.h"
+#include "loc_misc_utils.h"
+
+typedef const GnssInterface* (getLocationInterface)();
+
+#define IMAGES_INFO_FILE "/sys/devices/soc0/images"
+#define DELIMITER ";"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+static sp<Gnss> sGnss;
+static std::string getVersionString() {
+    static std::string version;
+    if (!version.empty())
+        return version;
+
+    char value[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware", value, "unknown");
+    version.append(value).append(DELIMITER);
+
+    std::ifstream in(IMAGES_INFO_FILE);
+    std::string s;
+    while(getline(in, s)) {
+        std::size_t found = s.find("CRM:");
+        if (std::string::npos == found) {
+            continue;
+        }
+
+        // skip over space characters after "CRM:"
+        const char* substr = s.c_str();
+        found += 4;
+        while (0 != substr[found] && isspace(substr[found])) {
+            found++;
+        }
+        if (s.find("11:") != found) {
+            continue;
+        }
+        s.erase(0, found + 3);
+
+        found = s.find_first_of("\r\n");
+        if (std::string::npos != found) {
+            s.erase(s.begin() + found, s.end());
+        }
+        version.append(s).append(DELIMITER);
+    }
+    return version;
+}
+
+void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnss != nullptr) {
+        mGnss->getGnssInterface()->resetNetworkInfo();
+        mGnss->stop();
+        mGnss->cleanup();
+    }
+}
+
+void location_on_battery_status_changed(bool charging) {
+    LOC_LOGd("battery status changed to %s charging", charging ? "" : "not");
+    if (sGnss != nullptr) {
+        sGnss->getGnssInterface()->updateBatteryStatus(charging);
+    }
+}
+Gnss::Gnss() {
+    ENTRY_LOG_CALLFLOW();
+    sGnss = this;
+    // initilize gnss interface at first in case needing notify battery status
+    sGnss->getGnssInterface()->initialize();
+    // register health client to listen on battery change
+    loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
+    // clear pending GnssConfig
+    memset(&mPendingConfig, 0, sizeof(GnssConfig));
+
+    mGnssDeathRecipient = new GnssDeathRecipient(this);
+}
+
+Gnss::~Gnss() {
+    ENTRY_LOG_CALLFLOW();
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+    sGnss = nullptr;
+}
+
+GnssAPIClient* Gnss::getApi() {
+    if (mApi == nullptr && (mGnssCbIface != nullptr || mGnssNiCbIface != nullptr)) {
+        mApi = new GnssAPIClient(mGnssCbIface, mGnssNiCbIface);
+        if (mApi == nullptr) {
+            LOC_LOGE("%s] faild to create GnssAPIClient", __FUNCTION__);
+            return mApi;
+        }
+
+        if (mPendingConfig.size == sizeof(GnssConfig)) {
+            // we have pending GnssConfig
+            mApi->gnssConfigurationUpdate(mPendingConfig);
+            // clear size to invalid mPendingConfig
+            mPendingConfig.size = 0;
+            if (mPendingConfig.assistanceServer.hostName != nullptr) {
+                free((void*)mPendingConfig.assistanceServer.hostName);
+            }
+        }
+    }
+    if (mApi == nullptr) {
+        LOC_LOGW("%s] GnssAPIClient is not ready", __FUNCTION__);
+    }
+    return mApi;
+}
+
+const GnssInterface* Gnss::getGnssInterface() {
+    static bool getGnssInterfaceFailed = false;
+    if (nullptr == mGnssInterface && !getGnssInterfaceFailed) {
+        void * libHandle = nullptr;
+        getLocationInterface* getter = (getLocationInterface*)
+                dlGetSymFromLib(libHandle, "libgnss.so", "getGnssInterface");
+
+        if (nullptr == getter) {
+            getGnssInterfaceFailed = true;
+        } else {
+            mGnssInterface = (const GnssInterface*)(*getter)();
+        }
+    }
+    return mGnssInterface;
+}
+
+Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback)  {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+    }
+    mGnssCbIface = callback;
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+    }
+
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+        api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
+    }
+    return true;
+}
+
+Return<bool> Gnss::setGnssNiCb(const sp<IGnssNiCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    mGnssNiCbIface = callback;
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+    }
+    return true;
+}
+
+Return<bool> Gnss::updateConfiguration(GnssConfig& gnssConfig) {
+    ENTRY_LOG_CALLFLOW();
+    GnssAPIClient* api = getApi();
+    if (api) {
+        api->gnssConfigurationUpdate(gnssConfig);
+    } else if (gnssConfig.flags != 0) {
+        // api is not ready yet, update mPendingConfig with gnssConfig
+        mPendingConfig.size = sizeof(GnssConfig);
+
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+            mPendingConfig.gpsLock = gnssConfig.gpsLock;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+            mPendingConfig.suplVersion = gnssConfig.suplVersion;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+            mPendingConfig.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+            mPendingConfig.assistanceServer.type = gnssConfig.assistanceServer.type;
+            if (mPendingConfig.assistanceServer.hostName != nullptr) {
+                free((void*)mPendingConfig.assistanceServer.hostName);
+                mPendingConfig.assistanceServer.hostName =
+                    strdup(gnssConfig.assistanceServer.hostName);
+            }
+            mPendingConfig.assistanceServer.port = gnssConfig.assistanceServer.port;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+            mPendingConfig.lppProfileMask = gnssConfig.lppProfileMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT;
+            mPendingConfig.lppeControlPlaneMask = gnssConfig.lppeControlPlaneMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT;
+            mPendingConfig.lppeUserPlaneMask = gnssConfig.lppeUserPlaneMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+            mPendingConfig.aGlonassPositionProtocolMask = gnssConfig.aGlonassPositionProtocolMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+            mPendingConfig.emergencyPdnForEmergencySupl = gnssConfig.emergencyPdnForEmergencySupl;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+            mPendingConfig.suplEmergencyServices = gnssConfig.suplEmergencyServices;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+            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;
+}
+
+Return<bool> Gnss::start()  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssStart();
+    }
+    return retVal;
+}
+
+Return<bool> Gnss::stop()  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssStop();
+    }
+    return retVal;
+}
+
+Return<void> Gnss::cleanup()  {
+    ENTRY_LOG_CALLFLOW();
+
+    if (mApi != nullptr) {
+        mApi->gnssDisable();
+    }
+
+    return Void();
+}
+
+Return<bool> Gnss::injectLocation(double latitudeDegrees,
+                                  double longitudeDegrees,
+                                  float accuracyMeters)  {
+    ENTRY_LOG_CALLFLOW();
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        gnssInterface->injectLocation(latitudeDegrees, longitudeDegrees, accuracyMeters);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs,
+                              int32_t uncertaintyMs) {
+    return true;
+}
+
+Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags)  {
+    ENTRY_LOG_CALLFLOW();
+    GnssAPIClient* api = getApi();
+    if (api) {
+        api->gnssDeleteAidingData(aidingDataFlags);
+    }
+    return Void();
+}
+
+Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                   V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                   uint32_t minIntervalMs,
+                                   uint32_t preferredAccuracyMeters,
+                                   uint32_t preferredTimeMs)  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+                preferredAccuracyMeters, preferredTimeMs);
+    }
+    return retVal;
+}
+
+Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss()  {
+    ENTRY_LOG_CALLFLOW();
+    mAGnssIface = new AGnss(this);
+    return mAGnssIface;
+}
+
+Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi()  {
+    ENTRY_LOG_CALLFLOW();
+    mGnssNi = new GnssNi(this);
+    return mGnssNi;
+}
+
+Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssMeasurement == nullptr)
+        mGnssMeasurement = new GnssMeasurement();
+    return mGnssMeasurement;
+}
+
+Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration()  {
+    ENTRY_LOG_CALLFLOW();
+    mGnssConfig = new GnssConfiguration(this);
+    return mGnssConfig;
+}
+
+Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing()  {
+    ENTRY_LOG_CALLFLOW();
+    mGnssGeofencingIface = new GnssGeofencing();
+    return mGnssGeofencingIface;
+}
+
+Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching()  {
+    mGnssBatching = new GnssBatching();
+    return mGnssBatching;
+}
+
+Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
+    ENTRY_LOG_CALLFLOW();
+    mGnssDebug = new GnssDebug(this);
+    return mGnssDebug;
+}
+
+Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
+    mGnssRil = new AGnssRil(this);
+    return mGnssRil;
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    callback->gnssNameCb(getVersionString());
+    mGnssCbIface_1_1 = callback;
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        OdcpiRequestCallback cb = [this](const OdcpiRequestInfo& odcpiRequest) {
+            odcpiRequestCb(odcpiRequest);
+        };
+        gnssInterface->odcpiInit(cb, OdcpiPrioritytype::ODCPI_HANDLER_PRIORITY_LOW);
+    }
+    return setCallback(callback);
+}
+
+Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+        V1_0::IGnss::GnssPositionRecurrence recurrence,
+        uint32_t minIntervalMs,
+        uint32_t preferredAccuracyMeters,
+        uint32_t preferredTimeMs,
+        bool lowPowerMode) {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        GnssPowerMode powerMode = lowPowerMode?
+                GNSS_POWER_MODE_M4 : GNSS_POWER_MODE_M2;
+        retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+                preferredAccuracyMeters, preferredTimeMs, powerMode, minIntervalMs);
+    }
+    return retVal;
+}
+
+Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssMeasurement == nullptr)
+        mGnssMeasurement = new GnssMeasurement();
+    return mGnssMeasurement;
+}
+
+Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssConfig == nullptr)
+        mGnssConfig = new GnssConfiguration(this);
+    return mGnssConfig;
+}
+
+Return<bool> Gnss::injectBestLocation(const GnssLocation& gnssLocation) {
+    ENTRY_LOG_CALLFLOW();
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        Location location = {};
+        convertGnssLocation(gnssLocation, location);
+        gnssInterface->odcpiInject(location);
+    }
+    return true;
+}
+
+void Gnss::odcpiRequestCb(const OdcpiRequestInfo& request) {
+    ENTRY_LOG_CALLFLOW();
+    if (ODCPI_REQUEST_TYPE_STOP == request.type) {
+        return;
+    }
+    if (mGnssCbIface_1_1 != nullptr) {
+        // For emergency mode, request DBH (Device based hybrid) location
+        // Mark Independent from GNSS flag to false.
+        if (ODCPI_REQUEST_TYPE_START == request.type) {
+            auto r = mGnssCbIface_1_1->gnssRequestLocationCb(!request.isEmergencyMode);
+            if (!r.isOk()) {
+                LOC_LOGe("Error invoking gnssRequestLocationCb %s", r.description().c_str());
+            }
+        } else {
+            LOC_LOGv("Unsupported ODCPI request type: %d", request.type);
+        }
+    } else {
+        LOC_LOGe("ODCPI request not supported.");
+    }
+}
+
+V1_0::IGnss* HIDL_FETCH_IGnss(const char* hal) {
+    ENTRY_LOG_CALLFLOW();
+    V1_0::IGnss* iface = nullptr;
+    iface = new Gnss();
+    if (iface == nullptr) {
+        LOC_LOGE("%s]: failed to get %s", __FUNCTION__, hal);
+    }
+    return iface;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/Gnss.h b/gps/android/1.1/Gnss.h
new file mode 100644
index 0000000..15645eb
--- /dev/null
+++ b/gps/android/1.1/Gnss.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2017-2018-2018-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSS_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSS_H
+
+#include <AGnss.h>
+#include <AGnssRil.h>
+#include <GnssBatching.h>
+#include <GnssConfiguration.h>
+#include <GnssGeofencing.h>
+#include <GnssMeasurement.h>
+#include <GnssNi.h>
+#include <GnssDebug.h>
+
+#include <android/hardware/gnss/1.1/IGnss.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <GnssAPIClient.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+struct Gnss : public IGnss {
+    Gnss();
+    ~Gnss();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnss follow.
+     * These declarations were generated from Gnss.hal.
+     */
+    Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback)  override;
+    Return<bool> start()  override;
+    Return<bool> stop()  override;
+    Return<void> cleanup()  override;
+    Return<bool> injectLocation(double latitudeDegrees,
+                                double longitudeDegrees,
+                                float accuracyMeters)  override;
+    Return<bool> injectTime(int64_t timeMs,
+                            int64_t timeReferenceMs,
+                            int32_t uncertaintyMs) override;
+    Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags)  override;
+    Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                 V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                 uint32_t minIntervalMs,
+                                 uint32_t preferredAccuracyMeters,
+                                 uint32_t preferredTimeMs)  override;
+    Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+    Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+    Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+    Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+    Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+    Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+    Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+
+    inline Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override {
+        return nullptr;
+    }
+
+    inline Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override {
+        return nullptr;
+    }
+
+    Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+    Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
+    Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+            V1_0::IGnss::GnssPositionRecurrence recurrence,
+            uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+            uint32_t preferredTimeMs, bool lowPowerMode) override;
+    Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+    Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+    Return<bool> injectBestLocation(const GnssLocation& location) override;
+
+    // These methods are not part of the IGnss base class.
+    GnssAPIClient* getApi();
+    Return<bool> setGnssNiCb(const sp<IGnssNiCallback>& niCb);
+    Return<bool> updateConfiguration(GnssConfig& gnssConfig);
+    const GnssInterface* getGnssInterface();
+
+    // Callback for ODCPI request
+    void odcpiRequestCb(const OdcpiRequestInfo& request);
+
+ private:
+    struct GnssDeathRecipient : hidl_death_recipient {
+        GnssDeathRecipient(sp<Gnss> gnss) : mGnss(gnss) {
+        }
+        ~GnssDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<Gnss> mGnss;
+    };
+
+ private:
+    sp<GnssDeathRecipient> mGnssDeathRecipient = nullptr;
+
+    sp<AGnss> mAGnssIface = nullptr;
+    sp<GnssNi> mGnssNi = nullptr;
+    sp<GnssMeasurement> mGnssMeasurement = nullptr;
+    sp<GnssConfiguration> mGnssConfig = nullptr;
+    sp<GnssGeofencing> mGnssGeofencingIface = nullptr;
+    sp<GnssBatching> mGnssBatching = nullptr;
+    sp<IGnssDebug> mGnssDebug = nullptr;
+    sp<AGnssRil> mGnssRil = nullptr;
+
+    GnssAPIClient* mApi = nullptr;
+    sp<V1_0::IGnssCallback> mGnssCbIface = nullptr;
+    sp<V1_1::IGnssCallback> mGnssCbIface_1_1 = nullptr;
+    sp<V1_0::IGnssNiCallback> mGnssNiCbIface = nullptr;
+    GnssConfig mPendingConfig;
+    const GnssInterface* mGnssInterface = nullptr;
+};
+
+extern "C" V1_0::IGnss* HIDL_FETCH_IGnss(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_GNSS_H
diff --git a/gps/android/1.1/GnssBatching.cpp b/gps/android/1.1/GnssBatching.cpp
new file mode 100644
index 0000000..8ab264d
--- /dev/null
+++ b/gps/android/1.1/GnssBatching.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssBatchingInterface"
+
+#include <log_util.h>
+#include <BatchingAPIClient.h>
+#include "GnssBatching.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void GnssBatching::GnssBatchingDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssBatching != nullptr) {
+        mGnssBatching->stop();
+        mGnssBatching->cleanup();
+    }
+}
+
+GnssBatching::GnssBatching() : mApi(nullptr) {
+    mGnssBatchingDeathRecipient = new GnssBatchingDeathRecipient(this);
+}
+
+GnssBatching::~GnssBatching() {
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+Return<bool> GnssBatching::init(const sp<IGnssBatchingCallback>& callback) {
+    if (mApi != nullptr) {
+        LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+        mApi->destroy();
+        mApi = nullptr;
+    }
+
+    mApi = new BatchingAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+        return false;
+    }
+
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+    }
+    mGnssBatchingCbIface = callback;
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return true;
+}
+
+Return<uint16_t> GnssBatching::getBatchSize() {
+    uint16_t ret = 0;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->getBatchSize();
+    }
+    return ret;
+}
+
+Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
+    bool ret = false;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->startSession(options);
+    }
+    return ret;
+}
+
+Return<void> GnssBatching::flush() {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->flushBatchedLocations();
+    }
+    return Void();
+}
+
+Return<bool> GnssBatching::stop() {
+    bool ret = false;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->stopSession();
+    }
+    return ret;
+}
+
+Return<void> GnssBatching::cleanup() {
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/GnssBatching.h b/gps/android/1.1/GnssBatching.h
new file mode 100644
index 0000000..8e235d8
--- /dev/null
+++ b/gps/android/1.1/GnssBatching.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSBATCHING_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSBATCHING_H
+
+#include <android/hardware/gnss/1.0/IGnssBatching.h>
+#include <hidl/Status.h>
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssBatching;
+using ::android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+class BatchingAPIClient;
+struct GnssBatching : public IGnssBatching {
+    GnssBatching();
+    ~GnssBatching();
+
+    // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+    Return<bool> init(const sp<IGnssBatchingCallback>& callback) override;
+    Return<uint16_t> getBatchSize() override;
+    Return<bool> start(const IGnssBatching::Options& options ) override;
+    Return<void> flush() override;
+    Return<bool> stop() override;
+    Return<void> cleanup() override;
+
+ private:
+    struct GnssBatchingDeathRecipient : hidl_death_recipient {
+        GnssBatchingDeathRecipient(sp<GnssBatching> gnssBatching) :
+            mGnssBatching(gnssBatching) {
+        }
+        ~GnssBatchingDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssBatching> mGnssBatching;
+    };
+
+ private:
+    sp<GnssBatchingDeathRecipient> mGnssBatchingDeathRecipient = nullptr;
+    sp<IGnssBatchingCallback> mGnssBatchingCbIface = nullptr;
+    BatchingAPIClient* mApi = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_GNSSBATCHING_H
diff --git a/gps/android/1.1/GnssConfiguration.cpp b/gps/android/1.1/GnssConfiguration.cpp
new file mode 100644
index 0000000..ad255d1
--- /dev/null
+++ b/gps/android/1.1/GnssConfiguration.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssConfigurationInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssConfiguration.h"
+#include <android/hardware/gnss/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+
+GnssConfiguration::GnssConfiguration(Gnss* gnss) : mGnss(gnss) {
+}
+
+// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enabled)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+    config.suplEmergencyServices = (enabled ?
+            GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_YES :
+            GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO);
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t version)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+    switch (version) {
+        case 0x00020004:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_4;
+            break;
+        case 0x00020002:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_2;
+            break;
+        case 0x00020000:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_0;
+            break;
+        case 0x00010000:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_1_0_0;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid version: 0x%x.", __FUNCTION__, version);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplMode(uint8_t mode)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+    switch (mode) {
+        case 0:
+            config.suplModeMask = 0; // STANDALONE ONLY
+            break;
+        case 1:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT;
+            break;
+        case 2:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+            break;
+        case 3:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT | GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid mode: %d.", __FUNCTION__, mode);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfileMask) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config = {};
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+    config.lppProfileMask = GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE; //default
+
+    if (lppProfileMask & (1<<0)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_BIT;
+    }
+    if (lppProfileMask & (1<<1)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_BIT;
+    }
+    if (lppProfileMask & (1<<2)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_OVER_NR5G_SA_BIT;
+    }
+    if (lppProfileMask & (1<<3)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_OVER_NR5G_SA_BIT;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+
+    config.flags = GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+    if (protocol & (1<<0)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRC_CONTROL_PLANE_BIT;
+    }
+    if (protocol & (1<<1)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRLP_USER_PLANE_BIT;
+    }
+    if (protocol & (1<<2)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_USER_PLANE_BIT;
+    }
+    if (protocol & (1<<3)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_CONTROL_PLANE_BIT;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+    switch (lock) {
+        case 0:
+            config.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+            break;
+        case 1:
+            config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO;
+            break;
+        case 2:
+            config.gpsLock = GNSS_CONFIG_GPS_LOCK_NI;
+            break;
+        case 3:
+            config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid lock: %d.", __FUNCTION__, lock);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+    config.emergencyPdnForEmergencySupl = (enabled ?
+            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES :
+            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO);
+
+    return mGnss->updateConfiguration(config);
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist(
+            const hidl_vec<GnssConfiguration::BlacklistedSource>& blacklist) {
+
+    ENTRY_LOG_CALLFLOW();
+    if (nullptr == mGnss) {
+        LOC_LOGe("mGnss is null");
+        return false;
+    }
+
+    // blValid is true if blacklist is empty, i.e. clearing the BL;
+    // if blacklist is not empty, blValid is initialied to false, and later
+    // updated in the for loop to become true only if there is at least
+    // one {constellation, svid} in the list that is valid.
+    bool blValid = (0 == blacklist.size());
+    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++) {
+        // Set blValid true if any one source is valid
+        blValid = setBlacklistedSource(source, blacklist[idx]) || blValid;
+        config.blacklistedSvIds.push_back(source);
+    }
+
+    // Update configuration only if blValid is true
+    // i.e. only if atleast one source is valid for blacklisting
+    return (blValid && mGnss->updateConfiguration(config));
+}
+
+bool GnssConfiguration::setBlacklistedSource(
+        GnssSvIdSource& copyToSource,
+        const GnssConfiguration::BlacklistedSource& copyFromSource) {
+
+    bool retVal = true;
+    uint16_t svIdOffset = 0;
+    copyToSource.size = sizeof(GnssSvIdSource);
+    copyToSource.svId = copyFromSource.svid;
+
+    switch(copyFromSource.constellation) {
+    case GnssConstellationType::GPS:
+        copyToSource.constellation = GNSS_SV_TYPE_GPS;
+        LOC_LOGe("GPS SVs can't be blacklisted.");
+        retVal = false;
+        break;
+    case GnssConstellationType::SBAS:
+        copyToSource.constellation = GNSS_SV_TYPE_SBAS;
+        LOC_LOGe("SBAS SVs can't be blacklisted.");
+        retVal = false;
+        break;
+    case GnssConstellationType::GLONASS:
+        copyToSource.constellation = GNSS_SV_TYPE_GLONASS;
+        svIdOffset = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::QZSS:
+        copyToSource.constellation = GNSS_SV_TYPE_QZSS;
+        svIdOffset = 0;
+        break;
+    case GnssConstellationType::BEIDOU:
+        copyToSource.constellation = GNSS_SV_TYPE_BEIDOU;
+        svIdOffset = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::GALILEO:
+        copyToSource.constellation = GNSS_SV_TYPE_GALILEO;
+        svIdOffset = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID - 1;
+        break;
+    default:
+        copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
+        LOC_LOGe("Invalid constellation %d", copyFromSource.constellation);
+        retVal = false;
+        break;
+    }
+
+    if (copyToSource.svId > 0 && svIdOffset > 0) {
+        copyToSource.svId += svIdOffset;
+    }
+
+    return retVal;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/GnssConfiguration.h b/gps/android/1.1/GnssConfiguration.h
new file mode 100644
index 0000000..daea159
--- /dev/null
+++ b/gps/android/1.1/GnssConfiguration.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+
+ /* Copyright (C) 2016 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.
+ */
+
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSCONFIGURATION_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSCONFIGURATION_H
+
+#include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_1::IGnssConfiguration;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Interface for passing GNSS configuration info from platform to HAL.
+ */
+struct Gnss;
+struct GnssConfiguration : public IGnssConfiguration {
+    GnssConfiguration(Gnss* gnss);
+    ~GnssConfiguration() = default;
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+     * These declarations were generated from IGnssConfiguration.hal.
+     */
+    Return<bool> setSuplVersion(uint32_t version) override;
+    Return<bool> setSuplMode(uint8_t mode) override;
+    Return<bool> setSuplEs(bool enabled) override;
+    Return<bool> setLppProfile(uint8_t lppProfileMask) override;
+    Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override;
+    Return<bool> setEmergencySuplPdn(bool enable) override;
+    Return<bool> setGpsLock(uint8_t lock) override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+    Return<bool> setBlacklist(
+            const hidl_vec<GnssConfiguration::BlacklistedSource>& blacklist) override;
+
+ private:
+    Gnss* mGnss = nullptr;
+    bool setBlacklistedSource(
+            GnssSvIdSource& copyToSource,
+            const GnssConfiguration::BlacklistedSource& copyFromSource);
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_GNSSCONFIGURATION_H
diff --git a/gps/android/1.1/GnssDebug.cpp b/gps/android/1.1/GnssDebug.cpp
new file mode 100644
index 0000000..f164c54
--- /dev/null
+++ b/gps/android/1.1/GnssDebug.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssDebugInterface"
+
+#include <log/log.h>
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssDebug.h"
+#include "LocationUtil.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+
+#define GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS (20000000)
+#define GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS   (20000)
+#define GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC     (500)
+#define GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG       (180)
+
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME            (1483228800000LL) // 1/1/2017 00:00 GMT
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN    (999) // 999 ns
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX    (1.57783680E17) // 5 years in ns
+#define GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC (2.0e5)  // ppm
+
+GnssDebug::GnssDebug(Gnss* gnss) : mGnss(gnss)
+{
+}
+
+/*
+ * This methods requests position, time and satellite ephemeris debug information
+ * from the HAL.
+ *
+ * @return void
+*/
+Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    DebugData data = { };
+
+    if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+        LOC_LOGE("GnssDebug - Null GNSS interface");
+        _hidl_cb(data);
+        return Void();
+    }
+
+    // get debug report snapshot via hal interface
+    GnssDebugReport reports = { };
+    mGnss->getGnssInterface()->getDebugReport(reports);
+
+    // location block
+    if (reports.mLocation.mValid) {
+        data.position.valid = true;
+        data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+        data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+        data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+        data.position.speedMetersPerSec =
+            (double)(reports.mLocation.mLocation.speed);
+        data.position.bearingDegrees =
+            (double)(reports.mLocation.mLocation.bearing);
+        data.position.horizontalAccuracyMeters =
+            (double)(reports.mLocation.mLocation.accuracy);
+        data.position.verticalAccuracyMeters =
+            reports.mLocation.verticalAccuracyMeters;
+        data.position.speedAccuracyMetersPerSecond =
+            reports.mLocation.speedAccuracyMetersPerSecond;
+        data.position.bearingAccuracyDegrees =
+            reports.mLocation.bearingAccuracyDegrees;
+
+        timeval tv_now, tv_report;
+        tv_report.tv_sec  = reports.mLocation.mUtcReported.tv_sec;
+        tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+        gettimeofday(&tv_now, NULL);
+        data.position.ageSeconds =
+            (tv_now.tv_sec - tv_report.tv_sec) +
+            (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+    }
+    else {
+        data.position.valid = false;
+    }
+
+    if (data.position.horizontalAccuracyMeters <= 0 ||
+        data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+        data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+    }
+    if (data.position.verticalAccuracyMeters <= 0 ||
+        data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+        data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+    }
+    if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+        data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+        data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+    }
+    if (data.position.bearingAccuracyDegrees <= 0 ||
+        data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+        data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+    }
+
+    // time block
+    if (reports.mTime.mValid) {
+        data.time.timeEstimate = reports.mTime.timeEstimate;
+        data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+        data.time.frequencyUncertaintyNsPerSec =
+            reports.mTime.frequencyUncertaintyNsPerSec;
+    }
+
+    if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+        data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+    }
+    if (data.time.timeUncertaintyNs <= 0) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
+    } else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
+    }
+    if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+        data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+        data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+    }
+
+    // satellite data block
+    SatelliteData s = { };
+    std::vector<SatelliteData> s_array = { };
+
+    for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+        memset(&s, 0, sizeof(s));
+        s.svid = reports.mSatelliteInfo[i].svid;
+        convertGnssConstellationType(
+            reports.mSatelliteInfo[i].constellation, s.constellation);
+        convertGnssEphemerisType(
+            reports.mSatelliteInfo[i].mEphemerisType, s.ephemerisType);
+        convertGnssEphemerisSource(
+            reports.mSatelliteInfo[i].mEphemerisSource, s.ephemerisSource);
+        convertGnssEphemerisHealth(
+            reports.mSatelliteInfo[i].mEphemerisHealth, s.ephemerisHealth);
+
+        s.ephemerisAgeSeconds =
+            reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+        s.serverPredictionIsAvailable =
+            reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+        s.serverPredictionAgeSeconds =
+            reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+        s_array.push_back(s);
+    }
+    data.satelliteDataArray = s_array;
+
+    // callback HIDL with collected debug data
+    _hidl_cb(data);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/GnssDebug.h b/gps/android/1.1/GnssDebug.h
new file mode 100644
index 0000000..cb818ac
--- /dev/null
+++ b/gps/android/1.1/GnssDebug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSDEBUG_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSDEBUG_H
+
+
+#include <android/hardware/gnss/1.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssDebug;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/* Interface for GNSS Debug support. */
+struct Gnss;
+struct GnssDebug : public IGnssDebug {
+    GnssDebug(Gnss* gnss);
+    ~GnssDebug() {};
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow.
+     * These declarations were generated from IGnssDebug.hal.
+     */
+    Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
+
+private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_GNSSDEBUG_H
diff --git a/gps/android/1.1/GnssGeofencing.cpp b/gps/android/1.1/GnssGeofencing.cpp
new file mode 100644
index 0000000..a4aaf88
--- /dev/null
+++ b/gps/android/1.1/GnssGeofencing.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "GnssHal_GnssGeofencing"
+
+#include <log_util.h>
+#include <GeofenceAPIClient.h>
+#include "GnssGeofencing.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void GnssGeofencing::GnssGeofencingDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssGeofencing != nullptr) {
+        mGnssGeofencing->removeAllGeofences();
+    }
+}
+
+GnssGeofencing::GnssGeofencing() : mApi(nullptr) {
+    mGnssGeofencingDeathRecipient = new GnssGeofencingDeathRecipient(this);
+}
+
+GnssGeofencing::~GnssGeofencing() {
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback)  {
+    if (mApi != nullptr) {
+        LOC_LOGd("mApi is NOT nullptr");
+        return Void();
+    }
+
+    mApi = new GeofenceAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+    }
+
+    if (mGnssGeofencingCbIface != nullptr) {
+        mGnssGeofencingCbIface->unlinkToDeath(mGnssGeofencingDeathRecipient);
+    }
+    mGnssGeofencingCbIface = callback;
+    if (mGnssGeofencingCbIface != nullptr) {
+        mGnssGeofencingCbIface->linkToDeath(mGnssGeofencingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return Void();
+}
+
+Return<void> GnssGeofencing::addGeofence(
+        int32_t geofenceId,
+        double latitudeDegrees,
+        double longitudeDegrees,
+        double radiusMeters,
+        IGnssGeofenceCallback::GeofenceTransition lastTransition,
+        int32_t monitorTransitions,
+        uint32_t notificationResponsivenessMs,
+        uint32_t unknownTimerMs)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceAdd(
+                geofenceId,
+                latitudeDegrees,
+                longitudeDegrees,
+                radiusMeters,
+                static_cast<int32_t>(lastTransition),
+                monitorTransitions,
+                notificationResponsivenessMs,
+                unknownTimerMs);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofencePause(geofenceId);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceResume(geofenceId, monitorTransitions);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceRemove(geofenceId);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::removeAllGeofences()  {
+    if (mApi == nullptr) {
+        LOC_LOGD("%s]: mApi is nullptr, do nothing", __FUNCTION__);
+    } else {
+        mApi->geofenceRemoveAll();
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/GnssGeofencing.h b/gps/android/1.1/GnssGeofencing.h
new file mode 100644
index 0000000..94a73de
--- /dev/null
+++ b/gps/android/1.1/GnssGeofencing.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSGEOFENCING_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSGEOFENCING_H
+
+#include <android/hardware/gnss/1.0/IGnssGeofencing.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::IGnssGeofencing;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class GeofenceAPIClient;
+struct GnssGeofencing : public IGnssGeofencing {
+    GnssGeofencing();
+    ~GnssGeofencing();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+     * These declarations were generated from IGnssGeofencing.hal.
+     */
+    Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback)  override;
+    Return<void> addGeofence(int32_t geofenceId,
+                             double latitudeDegrees,
+                             double longitudeDegrees,
+                             double radiusMeters,
+                             IGnssGeofenceCallback::GeofenceTransition lastTransition,
+                             int32_t monitorTransitions,
+                             uint32_t notificationResponsivenessMs,
+                             uint32_t unknownTimerMs)  override;
+
+    Return<void> pauseGeofence(int32_t geofenceId)  override;
+    Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  override;
+    Return<void> removeGeofence(int32_t geofenceId)  override;
+
+ private:
+    // This method is not part of the IGnss base class.
+    // It is called by GnssGeofencingDeathRecipient to remove all geofences added so far.
+    Return<void> removeAllGeofences();
+
+ private:
+    struct GnssGeofencingDeathRecipient : hidl_death_recipient {
+        GnssGeofencingDeathRecipient(sp<GnssGeofencing> gnssGeofencing) :
+            mGnssGeofencing(gnssGeofencing) {
+        }
+        ~GnssGeofencingDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssGeofencing> mGnssGeofencing;
+    };
+
+ private:
+    sp<GnssGeofencingDeathRecipient> mGnssGeofencingDeathRecipient = nullptr;
+    sp<IGnssGeofenceCallback> mGnssGeofencingCbIface = nullptr;
+    GeofenceAPIClient* mApi = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_GNSSGEOFENCING_H
diff --git a/gps/android/1.1/GnssMeasurement.cpp b/gps/android/1.1/GnssMeasurement.cpp
new file mode 100644
index 0000000..6f8c14d
--- /dev/null
+++ b/gps/android/1.1/GnssMeasurement.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssMeasurementInterface"
+
+#include <log_util.h>
+#include <MeasurementAPIClient.h>
+#include "GnssMeasurement.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void GnssMeasurement::GnssMeasurementDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssMeasurement != nullptr) {
+        mGnssMeasurement->close();
+    }
+}
+
+GnssMeasurement::GnssMeasurement() {
+    mGnssMeasurementDeathRecipient = new GnssMeasurementDeathRecipient(this);
+    mApi = new MeasurementAPIClient();
+}
+
+GnssMeasurement::~GnssMeasurement() {
+    if (mApi) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+
+Return<IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+        const sp<V1_0::IGnssMeasurementCallback>& callback)  {
+
+    Return<IGnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    mGnssMeasurementCbIface = callback;
+    mGnssMeasurementCbIface->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    return mApi->measurementSetCallback(callback);
+
+}
+
+Return<void> GnssMeasurement::close()  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    if (mGnssMeasurementCbIface != nullptr) {
+        mGnssMeasurementCbIface->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface = nullptr;
+    }
+    if (mGnssMeasurementCbIface_1_1 != nullptr) {
+        mGnssMeasurementCbIface_1_1->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface_1_1 = nullptr;
+    }
+    mApi->measurementClose();
+
+    return Void();
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_1_1(
+        const sp<IGnssMeasurementCallback>& callback, bool enableFullTracking) {
+
+    Return<IGnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface_1_1 != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (nullptr == mApi) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    mGnssMeasurementCbIface_1_1 = callback;
+    mGnssMeasurementCbIface_1_1->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    GnssPowerMode powerMode = enableFullTracking?
+            GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;
+
+    return mApi->measurementSetCallback_1_1(callback, powerMode);
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/GnssMeasurement.h b/gps/android/1.1/GnssMeasurement.h
new file mode 100644
index 0000000..373f0d0
--- /dev/null
+++ b/gps/android/1.1/GnssMeasurement.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSMEASUREMENT_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSMEASUREMENT_H
+
+#include <android/hardware/gnss/1.1/IGnssMeasurement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_1::IGnssMeasurement;
+using ::android::hardware::gnss::V1_1::IGnssMeasurementCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class MeasurementAPIClient;
+struct GnssMeasurement : public IGnssMeasurement {
+    GnssMeasurement();
+    ~GnssMeasurement();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+     * These declarations were generated from IGnssMeasurement.hal.
+     */
+    Return<GnssMeasurement::GnssMeasurementStatus> setCallback(
+        const sp<V1_0::IGnssMeasurementCallback>& callback) override;
+    Return<void> close() override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+    Return<GnssMeasurement::GnssMeasurementStatus> setCallback_1_1(
+            const sp<IGnssMeasurementCallback>& callback,
+            bool enableFullTracking) override;
+
+ private:
+    struct GnssMeasurementDeathRecipient : hidl_death_recipient {
+        GnssMeasurementDeathRecipient(sp<GnssMeasurement> gnssMeasurement) :
+            mGnssMeasurement(gnssMeasurement) {
+        }
+        ~GnssMeasurementDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssMeasurement> mGnssMeasurement;
+    };
+
+ private:
+    sp<GnssMeasurementDeathRecipient> mGnssMeasurementDeathRecipient = nullptr;
+    sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface = nullptr;
+    sp<IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1 = nullptr;
+    MeasurementAPIClient* mApi;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_GNSSMEASUREMENT_H
diff --git a/gps/android/1.1/GnssNi.cpp b/gps/android/1.1/GnssNi.cpp
new file mode 100644
index 0000000..5ce9569
--- /dev/null
+++ b/gps/android/1.1/GnssNi.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssNiInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssNi.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void GnssNi::GnssNiDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    // we do nothing here
+    // Gnss::GnssDeathRecipient will stop the session
+}
+
+GnssNi::GnssNi(Gnss* gnss) : mGnss(gnss) {
+    mGnssNiDeathRecipient = new GnssNiDeathRecipient(this);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    mGnss->setGnssNiCb(callback);
+
+    if (mGnssNiCbIface != nullptr) {
+        mGnssNiCbIface->unlinkToDeath(mGnssNiDeathRecipient);
+    }
+    mGnssNiCbIface = callback;
+    if (mGnssNiCbIface != nullptr) {
+        mGnssNiCbIface->linkToDeath(mGnssNiDeathRecipient, 0 /*cookie*/);
+    }
+
+    return Void();
+}
+
+Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    GnssAPIClient* api = mGnss->getApi();
+    if (api == nullptr) {
+        LOC_LOGE("%s]: api is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    api->gnssNiRespond(notifId, userResponse);
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/GnssNi.h b/gps/android/1.1/GnssNi.h
new file mode 100644
index 0000000..6733e5b
--- /dev/null
+++ b/gps/android/1.1/GnssNi.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_GNSSNI_H
+#define ANDROID_HARDWARE_GNSS_V1_1_GNSSNI_H
+
+#include <android/hardware/gnss/1.0/IGnssNi.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssNi;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct GnssNi : public IGnssNi {
+    GnssNi(Gnss* gnss);
+    ~GnssNi() = default;
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+     * These declarations were generated from IGnssNi.hal.
+     */
+    Return<void> setCallback(const sp<IGnssNiCallback>& callback) override;
+    Return<void> respond(int32_t notifId,
+                         IGnssNiCallback::GnssUserResponseType userResponse) override;
+
+ private:
+    struct GnssNiDeathRecipient : hidl_death_recipient {
+        GnssNiDeathRecipient(sp<GnssNi> gnssNi) : mGnssNi(gnssNi) {
+        }
+        ~GnssNiDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssNi> mGnssNi;
+    };
+
+ private:
+    sp<GnssNiDeathRecipient> mGnssNiDeathRecipient = nullptr;
+    sp<IGnssNiCallback> mGnssNiCbIface = nullptr;
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_GNSSNI_H
diff --git a/gps/android/1.1/android.hardware.gnss@1.1-service-qti.rc b/gps/android/1.1/android.hardware.gnss@1.1-service-qti.rc
new file mode 100644
index 0000000..bd65584
--- /dev/null
+++ b/gps/android/1.1/android.hardware.gnss@1.1-service-qti.rc
@@ -0,0 +1,4 @@
+service gnss_service /vendor/bin/hw/android.hardware.gnss@1.1-service-qti
+    class hal
+    user gps
+    group system gps radio vendor_qti_diag
diff --git a/gps/android/1.1/android.hardware.gnss@1.1-service-qti.xml b/gps/android/1.1/android.hardware.gnss@1.1-service-qti.xml
new file mode 100644
index 0000000..c9c83fb
--- /dev/null
+++ b/gps/android/1.1/android.hardware.gnss@1.1-service-qti.xml
@@ -0,0 +1,35 @@
+<!-- Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.gnss</name>
+        <transport>hwbinder</transport>
+        <fqname>@1.1::IGnss/default</fqname>
+    </hal>
+</manifest>
+
diff --git a/gps/android/1.1/location_api/BatchingAPIClient.cpp b/gps/android/1.1/location_api/BatchingAPIClient.cpp
new file mode 100644
index 0000000..6ec27a9
--- /dev/null
+++ b/gps/android/1.1/location_api/BatchingAPIClient.cpp
@@ -0,0 +1,197 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_BatchingAPIClient"
+
+#include <inttypes.h>
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "BatchingAPIClient.h"
+
+#include "limits.h"
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssBatching;
+using ::android::hardware::gnss::V1_0::IGnssBatchingCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+        LocationCapabilitiesMask mask);
+
+BatchingAPIClient::BatchingAPIClient(const sp<IGnssBatchingCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssBatchingCbIface(callback),
+    mDefaultId(UINT_MAX),
+    mLocationCapabilitiesMask(0)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+    if (mGnssBatchingCbIface != nullptr) {
+        locationCallbacks.batchingCb = [this](size_t count, Location* location,
+            BatchingOptions batchOptions) {
+            onBatchingCb(count, location, batchOptions);
+        };
+    }
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+BatchingAPIClient::~BatchingAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+int BatchingAPIClient::getBatchSize()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    return locAPIGetBatchSize();
+}
+
+int BatchingAPIClient::startSession(const IGnssBatching::Options& opts)
+{
+    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+    int retVal = -1;
+    LocationOptions options;
+    convertBatchOption(opts, options, mLocationCapabilitiesMask);
+    uint32_t mode = 0;
+    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+        mode = SESSION_MODE_ON_FULL;
+    }
+    if (locAPIStartSession(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+int BatchingAPIClient::updateSessionOptions(const IGnssBatching::Options& opts)
+{
+    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+    int retVal = -1;
+    LocationOptions options;
+    convertBatchOption(opts, options, mLocationCapabilitiesMask);
+
+    uint32_t mode = 0;
+    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+        mode = SESSION_MODE_ON_FULL;
+    }
+    if (locAPIUpdateSessionOptions(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+int BatchingAPIClient::stopSession()
+{
+    LOC_LOGD("%s]: ", __FUNCTION__);
+    int retVal = -1;
+    if (locAPIStopSession(mDefaultId) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+void BatchingAPIClient::getBatchedLocation(int last_n_locations)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, last_n_locations);
+    locAPIGetBatchedLocations(mDefaultId, last_n_locations);
+}
+
+void BatchingAPIClient::flushBatchedLocations()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
+}
+
+void BatchingAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+    LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
+    mLocationCapabilitiesMask = capabilitiesMask;
+}
+
+void BatchingAPIClient::onBatchingCb(size_t count, Location* location,
+        BatchingOptions /*batchOptions*/)
+{
+    LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, count);
+    if (mGnssBatchingCbIface != nullptr && count > 0) {
+        hidl_vec<GnssLocation> locationVec;
+        locationVec.resize(count);
+        for (size_t i = 0; i < count; i++) {
+            convertGnssLocation(location[i], locationVec[i]);
+        }
+        auto r = mGnssBatchingCbIface->gnssLocationBatchCb(locationVec);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationBatchCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+        LocationCapabilitiesMask mask)
+{
+    memset(&out, 0, sizeof(LocationOptions));
+    out.size = sizeof(LocationOptions);
+    out.minInterval = (uint32_t)(in.periodNanos / 1000000L);
+    out.minDistance = 0;
+    out.mode = GNSS_SUPL_MODE_STANDALONE;
+    if (mask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+        out.mode = GNSS_SUPL_MODE_MSA;
+    if (mask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+        out.mode = GNSS_SUPL_MODE_MSB;
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/location_api/BatchingAPIClient.h b/gps/android/1.1/location_api/BatchingAPIClient.h
new file mode 100644
index 0000000..4c90626
--- /dev/null
+++ b/gps/android/1.1/location_api/BatchingAPIClient.h
@@ -0,0 +1,75 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef BATCHING_API_CLINET_H
+#define BATCHING_API_CLINET_H
+
+#include <android/hardware/gnss/1.0/IGnssBatching.h>
+#include <android/hardware/gnss/1.0/IGnssBatchingCallback.h>
+#include <pthread.h>
+
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+class BatchingAPIClient : public LocationAPIClientBase
+{
+public:
+    BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback);
+    int getBatchSize();
+    int startSession(const V1_0::IGnssBatching::Options& options);
+    int updateSessionOptions(const V1_0::IGnssBatching::Options& options);
+    int stopSession();
+    void getBatchedLocation(int last_n_locations);
+    void flushBatchedLocations();
+
+    inline LocationCapabilitiesMask getCapabilities() { return mLocationCapabilitiesMask; }
+
+    // callbacks
+    void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+    void onBatchingCb(size_t count, Location* location, BatchingOptions batchOptions) final;
+
+private:
+    ~BatchingAPIClient();
+
+    sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface;
+    uint32_t mDefaultId;
+    LocationCapabilitiesMask mLocationCapabilitiesMask;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // BATCHING_API_CLINET_H
diff --git a/gps/android/1.1/location_api/GeofenceAPIClient.cpp b/gps/android/1.1/location_api/GeofenceAPIClient.cpp
new file mode 100644
index 0000000..93d175e
--- /dev/null
+++ b/gps/android/1.1/location_api/GeofenceAPIClient.cpp
@@ -0,0 +1,275 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_GeofenceApiClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GeofenceAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+GeofenceAPIClient::GeofenceAPIClient(const sp<IGnssGeofenceCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssGeofencingCbIface(callback)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+
+    locationCallbacks.geofenceBreachCb = nullptr;
+    if (mGnssGeofencingCbIface != nullptr) {
+        locationCallbacks.geofenceBreachCb =
+            [this](GeofenceBreachNotification geofenceBreachNotification) {
+                onGeofenceBreachCb(geofenceBreachNotification);
+            };
+
+        locationCallbacks.geofenceStatusCb =
+            [this](GeofenceStatusNotification geofenceStatusNotification) {
+                onGeofenceStatusCb(geofenceStatusNotification);
+            };
+    }
+
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+void GeofenceAPIClient::geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+        double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+        uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms)
+{
+    LOC_LOGD("%s]: (%d %f %f %f %d %d %d %d)", __FUNCTION__,
+            geofence_id, latitude, longitude, radius_meters,
+            last_transition, monitor_transitions, notification_responsiveness_ms, unknown_timer_ms);
+
+    GeofenceOption options;
+    memset(&options, 0, sizeof(GeofenceOption));
+    options.size = sizeof(GeofenceOption);
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+        options.breachTypeMask |= GEOFENCE_BREACH_ENTER_BIT;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+        options.breachTypeMask |=  GEOFENCE_BREACH_EXIT_BIT;
+    options.responsiveness = notification_responsiveness_ms;
+
+    GeofenceInfo data;
+    data.size = sizeof(GeofenceInfo);
+    data.latitude = latitude;
+    data.longitude = longitude;
+    data.radius = radius_meters;
+
+    LocationError err = (LocationError)locAPIAddGeofences(1, &geofence_id, &options, &data);
+    if (LOCATION_ERROR_SUCCESS != err) {
+        onAddGeofencesCb(1, &err, &geofence_id);
+    }
+}
+
+void GeofenceAPIClient::geofencePause(uint32_t geofence_id)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+    locAPIPauseGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceResume(uint32_t geofence_id, int32_t monitor_transitions)
+{
+    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, geofence_id, monitor_transitions);
+    GeofenceBreachTypeMask mask = 0;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+        mask |= GEOFENCE_BREACH_ENTER_BIT;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+        mask |=  GEOFENCE_BREACH_EXIT_BIT;
+    locAPIResumeGeofences(1, &geofence_id, &mask);
+}
+
+void GeofenceAPIClient::geofenceRemove(uint32_t geofence_id)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+    locAPIRemoveGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceRemoveAll()
+{
+    LOC_LOGD("%s]", __FUNCTION__);
+    // TODO locAPIRemoveAllGeofences();
+}
+
+// callbacks
+void GeofenceAPIClient::onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, geofenceBreachNotification.count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < geofenceBreachNotification.count; i++) {
+            GnssLocation gnssLocation;
+            convertGnssLocation(geofenceBreachNotification.location, gnssLocation);
+
+            IGnssGeofenceCallback::GeofenceTransition transition;
+            if (geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER)
+                transition = IGnssGeofenceCallback::GeofenceTransition::ENTERED;
+            else if (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT)
+                transition = IGnssGeofenceCallback::GeofenceTransition::EXITED;
+            else {
+                // continue with other breach if transition is
+                // nether GPS_GEOFENCE_ENTERED nor GPS_GEOFENCE_EXITED
+                continue;
+            }
+
+            auto r = mGnssGeofencingCbIface->gnssGeofenceTransitionCb(
+                    geofenceBreachNotification.ids[i], gnssLocation, transition,
+                    static_cast<V1_0::GnssUtcTime>(geofenceBreachNotification.timestamp));
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceTransitionCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceStatusNotification.available);
+    if (mGnssGeofencingCbIface != nullptr) {
+        IGnssGeofenceCallback::GeofenceAvailability status =
+            IGnssGeofenceCallback::GeofenceAvailability::UNAVAILABLE;
+        if (geofenceStatusNotification.available == GEOFENCE_STATUS_AVAILABILE_YES) {
+            status = IGnssGeofenceCallback::GeofenceAvailability::AVAILABLE;
+        }
+        GnssLocation gnssLocation;
+        memset(&gnssLocation, 0, sizeof(GnssLocation));
+        auto r = mGnssGeofencingCbIface->gnssGeofenceStatusCb(status, gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssGeofenceStatusCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GeofenceAPIClient::onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_EXISTS)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_EXISTS;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceAddCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceAddCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceRemoveCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceRemoveCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofencePauseCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofencePauseCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceResumeCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceResumeCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/location_api/GeofenceAPIClient.h b/gps/android/1.1/location_api/GeofenceAPIClient.h
new file mode 100644
index 0000000..0ffff91
--- /dev/null
+++ b/gps/android/1.1/location_api/GeofenceAPIClient.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GEOFENCE_API_CLINET_H
+#define GEOFENCE_API_CLINET_H
+
+
+#include <android/hardware/gnss/1.0/IGnssGeofenceCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+
+class GeofenceAPIClient : public LocationAPIClientBase
+{
+public:
+    GeofenceAPIClient(const sp<V1_0::IGnssGeofenceCallback>& callback);
+
+    void geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+            double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+            uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms);
+    void geofencePause(uint32_t geofence_id);
+    void geofenceResume(uint32_t geofence_id, int32_t monitor_transitions);
+    void geofenceRemove(uint32_t geofence_id);
+    void geofenceRemoveAll();
+
+    // callbacks
+    void onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification) final;
+    void onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification) final;
+    void onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+
+private:
+    virtual ~GeofenceAPIClient() = default;
+
+    sp<V1_0::IGnssGeofenceCallback> mGnssGeofencingCbIface;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // GEOFENCE_API_CLINET_H
diff --git a/gps/android/1.1/location_api/GnssAPIClient.cpp b/gps/android/1.1/location_api/GnssAPIClient.cpp
new file mode 100644
index 0000000..a2c4eec
--- /dev/null
+++ b/gps/android/1.1/location_api/GnssAPIClient.cpp
@@ -0,0 +1,565 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_GnssAPIClient"
+#define SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC (590 * 60 * 60 * 1000) // 590 hours
+
+#include <inttypes.h>
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GnssAPIClient.h"
+#include <LocContext.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnss;
+using ::android::hardware::gnss::V1_0::IGnssCallback;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out);
+
+GnssAPIClient::GnssAPIClient(const sp<IGnssCallback>& gpsCb,
+    const sp<IGnssNiCallback>& niCb) :
+    LocationAPIClientBase(),
+    mGnssCbIface(nullptr),
+    mGnssNiCbIface(nullptr),
+    mControlClient(new LocationAPIControlClient()),
+    mLocationCapabilitiesMask(0),
+    mLocationCapabilitiesCached(false)
+{
+    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+    // set default LocationOptions.
+    memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+    mTrackingOptions.size = sizeof(TrackingOptions);
+    mTrackingOptions.minInterval = 1000;
+    mTrackingOptions.minDistance = 0;
+    mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+
+    gnssUpdateCallbacks(gpsCb, niCb);
+}
+
+GnssAPIClient::~GnssAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    if (mControlClient) {
+        delete mControlClient;
+        mControlClient = nullptr;
+    }
+}
+
+// for GpsInterface
+void GnssAPIClient::gnssUpdateCallbacks(const sp<IGnssCallback>& gpsCb,
+    const sp<IGnssNiCallback>& niCb)
+{
+    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+    mMutex.lock();
+    mGnssCbIface = gpsCb;
+    mGnssNiCbIface = niCb;
+    mMutex.unlock();
+
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    if (mGnssCbIface != nullptr) {
+        locationCallbacks.trackingCb = [this](Location location) {
+            onTrackingCb(location);
+        };
+    }
+
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+
+    locationCallbacks.gnssNiCb = nullptr;
+    loc_core::ContextBase* context =
+            loc_core::LocContext::getLocContext(loc_core::LocContext::mLocationHalName);
+    if (mGnssNiCbIface != nullptr && !context->hasAgpsExtendedCapabilities()) {
+        LOC_LOGD("Registering NI CB");
+        locationCallbacks.gnssNiCb = [this](uint32_t id, GnssNiNotification gnssNiNotification) {
+            onGnssNiCb(id, gnssNiNotification);
+        };
+    }
+
+    locationCallbacks.gnssSvCb = nullptr;
+    if (mGnssCbIface != nullptr) {
+        locationCallbacks.gnssSvCb = [this](GnssSvNotification gnssSvNotification) {
+            onGnssSvCb(gnssSvNotification);
+        };
+    }
+
+    locationCallbacks.gnssNmeaCb = nullptr;
+    if (mGnssCbIface != nullptr) {
+        locationCallbacks.gnssNmeaCb = [this](GnssNmeaNotification gnssNmeaNotification) {
+            onGnssNmeaCb(gnssNmeaNotification);
+        };
+    }
+
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+bool GnssAPIClient::gnssStart()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    bool retVal = true;
+    locAPIStartTracking(mTrackingOptions);
+    return retVal;
+}
+
+bool GnssAPIClient::gnssStop()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    bool retVal = true;
+    locAPIStopTracking();
+    return retVal;
+}
+
+bool GnssAPIClient::gnssSetPositionMode(IGnss::GnssPositionMode mode,
+        IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs,
+        uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs,
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LOC_LOGD("%s]: (%d %d %d %d %d %d %d)", __FUNCTION__,
+            (int)mode, recurrence, minIntervalMs, preferredAccuracyMeters,
+            preferredTimeMs, (int)powerMode, timeBetweenMeasurement);
+    bool retVal = true;
+    memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+    mTrackingOptions.size = sizeof(TrackingOptions);
+    mTrackingOptions.minInterval = minIntervalMs;
+    if (IGnss::GnssPositionMode::MS_ASSISTED == mode ||
+            IGnss::GnssPositionRecurrence::RECURRENCE_SINGLE == recurrence) {
+        // We set a very large interval to simulate SINGLE mode. Once we report a fix,
+        // the caller should take the responsibility to stop the session.
+        // For MSA, we always treat it as SINGLE mode.
+        mTrackingOptions.minInterval = SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC;
+    }
+    if (mode == IGnss::GnssPositionMode::STANDALONE)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+    else if (mode == IGnss::GnssPositionMode::MS_BASED)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_MSB;
+    else if (mode ==  IGnss::GnssPositionMode::MS_ASSISTED)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_MSA;
+    else {
+        LOC_LOGD("%s]: invalid GnssPositionMode: %d", __FUNCTION__, (int)mode);
+        retVal = false;
+    }
+    if (GNSS_POWER_MODE_INVALID != powerMode) {
+        mTrackingOptions.powerMode = powerMode;
+        mTrackingOptions.tbm = timeBetweenMeasurement;
+    }
+    locAPIUpdateTrackingOptions(mTrackingOptions);
+    return retVal;
+}
+
+// for GpsNiInterface
+void GnssAPIClient::gnssNiRespond(int32_t notifId,
+        IGnssNiCallback::GnssUserResponseType userResponse)
+{
+    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, notifId, static_cast<int>(userResponse));
+    GnssNiResponse data;
+    switch (userResponse) {
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT:
+        data = GNSS_NI_RESPONSE_ACCEPT;
+        break;
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY:
+        data = GNSS_NI_RESPONSE_DENY;
+        break;
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP:
+        data = GNSS_NI_RESPONSE_NO_RESPONSE;
+        break;
+    default:
+        data = GNSS_NI_RESPONSE_IGNORE;
+        break;
+    }
+
+    locAPIGnssNiResponse(notifId, data);
+}
+
+// these apis using LocationAPIControlClient
+void GnssAPIClient::gnssDeleteAidingData(IGnss::GnssAidingData aidingDataFlags)
+{
+    LOC_LOGD("%s]: (%02hx)", __FUNCTION__, aidingDataFlags);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    GnssAidingData data;
+    memset(&data, 0, sizeof (GnssAidingData));
+    data.sv.svTypeMask = GNSS_AIDING_DATA_SV_TYPE_GPS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT;
+    data.posEngineMask = STANDARD_POSITIONING_ENGINE;
+
+    if (aidingDataFlags == IGnss::GnssAidingData::DELETE_ALL)
+        data.deleteAll = true;
+    else {
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_EPHEMERIS)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_EPHEMERIS_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_ALMANAC)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_ALMANAC_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_POSITION)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_POSITION_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_TIME)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_TIME_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_IONO)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_IONOSPHERE_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_UTC)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_UTC_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_HEALTH)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_HEALTH_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVDIR)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_DIRECTION_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVSTEER)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_STEER_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SADATA)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_SA_DATA_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_RTI)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_RTI_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_CELLDB_INFO)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_CELLDB_BIT;
+    }
+    mControlClient->locAPIGnssDeleteAidingData(data);
+}
+
+void GnssAPIClient::gnssEnable(LocationTechnologyType techType)
+{
+    LOC_LOGD("%s]: (%0d)", __FUNCTION__, techType);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIEnable(techType);
+}
+
+void GnssAPIClient::gnssDisable()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIDisable();
+}
+
+void GnssAPIClient::gnssConfigurationUpdate(const GnssConfig& gnssConfig)
+{
+    LOC_LOGD("%s]: (%02x)", __FUNCTION__, gnssConfig.flags);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIGnssUpdateConfig(gnssConfig);
+}
+
+void GnssAPIClient::requestCapabilities() {
+    // only send capablities if it's already cached, otherwise the first time LocationAPI
+    // is initialized, capabilities will be sent by LocationAPI
+    if (mLocationCapabilitiesCached) {
+        onCapabilitiesCb(mLocationCapabilitiesMask);
+    }
+}
+
+// callbacks
+void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+    LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
+    mLocationCapabilitiesMask = capabilitiesMask;
+    mLocationCapabilitiesCached = true;
+
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr) {
+        uint32_t data = 0;
+        if ((capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT))
+            data |= IGnssCallback::Capabilities::SCHEDULING;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GEOFENCE_BIT)
+            data |= IGnssCallback::Capabilities::GEOFENCING;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT)
+            data |= IGnssCallback::Capabilities::MEASUREMENTS;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+            data |= IGnssCallback::Capabilities::MSB;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+            data |= IGnssCallback::Capabilities::MSA;
+        auto r = gnssCbIface->gnssSetCapabilitesCb(data);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSetCapabilitesCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+    if (gnssCbIface != nullptr) {
+        IGnssCallback::GnssSystemInfo gnssInfo = { .yearOfHw = 2015 };
+
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT) {
+            gnssInfo.yearOfHw++; // 2016
+            if (capabilitiesMask & LOCATION_CAPABILITIES_DEBUG_NMEA_BIT) {
+                gnssInfo.yearOfHw++; // 2017
+                if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT ||
+                    capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT) {
+                    gnssInfo.yearOfHw++; // 2018
+                }
+            }
+        }
+        LOC_LOGV("%s:%d] set_system_info_cb (%d)", __FUNCTION__, __LINE__, gnssInfo.yearOfHw);
+        auto r = gnssCbIface->gnssSetSystemInfoCb(gnssInfo);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onTrackingCb(Location location)
+{
+    LOC_LOGD("%s]: (flags: %02x)", __FUNCTION__, location.flags);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr) {
+        GnssLocation gnssLocation;
+        convertGnssLocation(location, gnssLocation);
+        auto r = gnssCbIface->gnssLocationCb(gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification)
+{
+    LOC_LOGD("%s]: (id: %d)", __FUNCTION__, id);
+    mMutex.lock();
+    auto gnssNiCbIface(mGnssNiCbIface);
+    mMutex.unlock();
+
+    if (gnssNiCbIface == nullptr) {
+        LOC_LOGE("%s]: mGnssNiCbIface is nullptr", __FUNCTION__);
+        return;
+    }
+
+    IGnssNiCallback::GnssNiNotification notificationGnss = {};
+
+    notificationGnss.notificationId = id;
+
+    if (gnssNiNotification.type == GNSS_NI_TYPE_VOICE)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::VOICE;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_SUPL)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_SUPL;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_CONTROL_PLANE)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_CTRL_PLANE;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_EMERGENCY_SUPL)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::EMERGENCY_SUPL;
+
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_NOTIFICATION_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_NOTIFY;
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_VERIFICATION_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_VERIFY;
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::PRIVACY_OVERRIDE;
+
+    notificationGnss.timeoutSec = gnssNiNotification.timeout;
+
+    if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_ACCEPT)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT;
+    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_DENY)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY;
+    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_NO_RESPONSE ||
+            gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_IGNORE)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP;
+
+    notificationGnss.requestorId = gnssNiNotification.requestor;
+
+    notificationGnss.notificationMessage = gnssNiNotification.message;
+
+    if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+    if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+    gnssNiCbIface->niNotifyCb(notificationGnss);
+}
+
+void GnssAPIClient::onGnssSvCb(GnssSvNotification gnssSvNotification)
+{
+    LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, gnssSvNotification.count);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr) {
+        IGnssCallback::GnssSvStatus svStatus;
+        convertGnssSvStatus(gnssSvNotification, svStatus);
+        auto r = gnssCbIface->gnssSvStatusCb(svStatus);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSvStatusCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
+{
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr) {
+        const std::string s(gnssNmeaNotification.nmea);
+        std::stringstream ss(s);
+        std::string each;
+        while(std::getline(ss, each, '\n')) {
+            each += '\n';
+            android::hardware::hidl_string nmeaString;
+            nmeaString.setToExternal(each.c_str(), each.length());
+            auto r = gnssCbIface->gnssNmeaCb(
+                    static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%zu description=%s", __func__,
+                            gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+                            r.description().c_str());
+            }
+        }
+    }
+}
+
+void GnssAPIClient::onStartTrackingCb(LocationError error)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (error == LOCATION_ERROR_SUCCESS && gnssCbIface != nullptr) {
+        auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssStatusCb ENGINE_ON description=%s",
+                __func__, r.description().c_str());
+        }
+        r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssStatusCb SESSION_BEGIN description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onStopTrackingCb(LocationError error)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    mMutex.unlock();
+
+    if (error == LOCATION_ERROR_SUCCESS && gnssCbIface != nullptr) {
+        auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssStatusCb SESSION_END description=%s",
+                __func__, r.description().c_str());
+        }
+        r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssStatusCb ENGINE_OFF description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in, IGnssCallback::GnssSvStatus& out)
+{
+    memset(&out, 0, sizeof(IGnssCallback::GnssSvStatus));
+    out.numSvs = in.count;
+    if (out.numSvs > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+        LOC_LOGW("%s]: Too many satellites %u. Clamps to %d.",
+                __FUNCTION__,  out.numSvs, V1_0::GnssMax::SVS_COUNT);
+        out.numSvs = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+    }
+    for (size_t i = 0; i < out.numSvs; i++) {
+        IGnssCallback::GnssSvInfo& info = out.gnssSvList[i];
+        convertGnssSvid(in.gnssSvs[i], info.svid);
+        convertGnssConstellationType(in.gnssSvs[i].type, info.constellation);
+        info.cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+        info.elevationDegrees = in.gnssSvs[i].elevation;
+        info.azimuthDegrees = in.gnssSvs[i].azimuth;
+        info.carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+        info.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+            info.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+            info.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+            info.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+            info.svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/location_api/GnssAPIClient.h b/gps/android/1.1/location_api/GnssAPIClient.h
new file mode 100644
index 0000000..3829265
--- /dev/null
+++ b/gps/android/1.1/location_api/GnssAPIClient.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GNSS_API_CLINET_H
+#define GNSS_API_CLINET_H
+
+
+#include <mutex>
+#include <android/hardware/gnss/1.1/IGnss.h>
+#include <android/hardware/gnss/1.1/IGnssCallback.h>
+#include <android/hardware/gnss/1.0/IGnssNiCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+
+class GnssAPIClient : public LocationAPIClientBase
+{
+public:
+    GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+            const sp<V1_0::IGnssNiCallback>& niCb);
+    GnssAPIClient(const GnssAPIClient&) = delete;
+    GnssAPIClient& operator=(const GnssAPIClient&) = delete;
+
+    // for GpsInterface
+    void gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+            const sp<V1_0::IGnssNiCallback>& niCb);
+    bool gnssStart();
+    bool gnssStop();
+    bool gnssSetPositionMode(V1_0::IGnss::GnssPositionMode mode,
+            V1_0::IGnss::GnssPositionRecurrence recurrence,
+            uint32_t minIntervalMs,
+            uint32_t preferredAccuracyMeters,
+            uint32_t preferredTimeMs,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = 0);
+
+    // for GpsNiInterface
+    void gnssNiRespond(int32_t notifId, V1_0::IGnssNiCallback::GnssUserResponseType userResponse);
+
+    // these apis using LocationAPIControlClient
+    void gnssDeleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags);
+    void gnssEnable(LocationTechnologyType techType);
+    void gnssDisable();
+    void gnssConfigurationUpdate(const GnssConfig& gnssConfig);
+
+    inline LocationCapabilitiesMask gnssGetCapabilities() const {
+        return mLocationCapabilitiesMask;
+    }
+    void requestCapabilities();
+
+    // callbacks we are interested in
+    void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+    void onTrackingCb(Location location) final;
+    void onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification) final;
+    void onGnssSvCb(GnssSvNotification gnssSvNotification) final;
+    void onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification) final;
+
+    void onStartTrackingCb(LocationError error) final;
+    void onStopTrackingCb(LocationError error) final;
+
+private:
+    virtual ~GnssAPIClient();
+
+    sp<V1_0::IGnssCallback> mGnssCbIface;
+    sp<V1_0::IGnssNiCallback> mGnssNiCbIface;
+    std::mutex mMutex;
+    LocationAPIControlClient* mControlClient;
+    LocationCapabilitiesMask mLocationCapabilitiesMask;
+    bool mLocationCapabilitiesCached;
+    TrackingOptions mTrackingOptions;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // GNSS_API_CLINET_H
diff --git a/gps/android/1.1/location_api/LocationUtil.cpp b/gps/android/1.1/location_api/LocationUtil.cpp
new file mode 100644
index 0000000..26fd920
--- /dev/null
+++ b/gps/android/1.1/location_api/LocationUtil.cpp
@@ -0,0 +1,274 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <LocationUtil.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+using ::android::hardware::gnss::V1_0::GnssLocationFlags;
+
+void convertGnssLocation(Location& in, GnssLocation& out)
+{
+    memset(&out, 0, sizeof(GnssLocation));
+    if (in.flags & LOCATION_HAS_LAT_LONG_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_LAT_LONG;
+        out.latitudeDegrees = in.latitude;
+        out.longitudeDegrees = in.longitude;
+    }
+    if (in.flags & LOCATION_HAS_ALTITUDE_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE;
+        out.altitudeMeters = in.altitude;
+    }
+    if (in.flags & LOCATION_HAS_SPEED_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
+        out.speedMetersPerSec = in.speed;
+    }
+    if (in.flags & LOCATION_HAS_BEARING_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
+        out.bearingDegrees = in.bearing;
+    }
+    if (in.flags & LOCATION_HAS_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
+        out.horizontalAccuracyMeters = in.accuracy;
+    }
+    if (in.flags & LOCATION_HAS_VERTICAL_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
+        out.verticalAccuracyMeters = in.verticalAccuracy;
+    }
+    if (in.flags & LOCATION_HAS_SPEED_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
+        out.speedAccuracyMetersPerSecond = in.speedAccuracy;
+    }
+    if (in.flags & LOCATION_HAS_BEARING_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
+        out.bearingAccuracyDegrees = in.bearingAccuracy;
+    }
+
+    out.timestamp = static_cast<V1_0::GnssUtcTime>(in.timestamp);
+}
+
+void convertGnssLocation(const GnssLocation& in, Location& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG) {
+        out.flags |= LOCATION_HAS_LAT_LONG_BIT;
+        out.latitude = in.latitudeDegrees;
+        out.longitude = in.longitudeDegrees;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE) {
+        out.flags |= LOCATION_HAS_ALTITUDE_BIT;
+        out.altitude = in.altitudeMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED) {
+        out.flags |= LOCATION_HAS_SPEED_BIT;
+        out.speed = in.speedMetersPerSec;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+        out.flags |= LOCATION_HAS_BEARING_BIT;
+        out.bearing = in.bearingDegrees;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+        out.flags |= LOCATION_HAS_ACCURACY_BIT;
+        out.accuracy = in.horizontalAccuracyMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+        out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+        out.verticalAccuracy = in.verticalAccuracyMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+        out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+        out.speedAccuracy = in.speedAccuracyMetersPerSecond;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+        out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+        out.bearingAccuracy = in.bearingAccuracyDegrees;
+    }
+
+    out.timestamp = static_cast<uint64_t>(in.timestamp);
+}
+
+void convertGnssConstellationType(GnssSvType& in, GnssConstellationType& out)
+{
+    switch(in) {
+        case GNSS_SV_TYPE_GPS:
+            out = GnssConstellationType::GPS;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = GnssConstellationType::SBAS;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            out = GnssConstellationType::GLONASS;
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = GnssConstellationType::QZSS;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = GnssConstellationType::BEIDOU;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = GnssConstellationType::GALILEO;
+            break;
+        case GNSS_SV_TYPE_UNKNOWN:
+        default:
+            out = GnssConstellationType::UNKNOWN;
+            break;
+    }
+}
+
+void convertGnssSvid(GnssSv& in, int16_t& out)
+{
+    switch(in.type){
+        case GNSS_SV_TYPE_GPS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            if (!isGloSlotUnknown(in.svId)) { // OSN is known
+                out = in.svId - GLO_SV_PRN_MIN + 1;
+            } else { //OSN is not known, report FCN
+                out = in.gloFrequency + 92;
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = in.svId - BDS_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = in.svId - GAL_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = in.svId - NAVIC_SV_PRN_MIN + 1;
+            break;
+        default:
+            out = in.svId;
+            break;
+    }
+}
+
+void convertGnssSvid(GnssMeasurementsData& in, int16_t& out)
+{
+    switch (in.svType) {
+        case GNSS_SV_TYPE_GPS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            if (!isGloSlotUnknown(in.svId)) { // OSN is known
+                out = in.svId - GLO_SV_PRN_MIN + 1;
+            } else { // OSN is not known, report FCN
+                out = in.gloFrequency + 92;
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = in.svId - BDS_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = in.svId - GAL_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = in.svId - NAVIC_SV_PRN_MIN + 1;
+            break;
+        default:
+            out = in.svId;
+            break;
+    }
+}
+
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out)
+{
+    switch(in) {
+        case GNSS_EPH_TYPE_EPHEMERIS:
+            out = GnssDebug::SatelliteEphemerisType::EPHEMERIS;
+            break;
+        case GNSS_EPH_TYPE_ALMANAC:
+            out = GnssDebug::SatelliteEphemerisType::ALMANAC_ONLY;
+            break;
+        case GNSS_EPH_TYPE_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisType::NOT_AVAILABLE;
+            break;
+    }
+}
+
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out)
+{
+    switch(in) {
+        case GNSS_EPH_SOURCE_DEMODULATED:
+            out = GnssDebug::SatelliteEphemerisSource::DEMODULATED;
+            break;
+        case GNSS_EPH_SOURCE_SUPL_PROVIDED:
+            out = GnssDebug::SatelliteEphemerisSource::SUPL_PROVIDED;
+            break;
+        case GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED:
+            out = GnssDebug::SatelliteEphemerisSource::OTHER_SERVER_PROVIDED;
+            break;
+        case GNSS_EPH_SOURCE_LOCAL:
+        case GNSS_EPH_SOURCE_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisSource::OTHER;
+            break;
+    }
+}
+
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out)
+{
+    switch(in) {
+        case GNSS_EPH_HEALTH_GOOD:
+            out = GnssDebug::SatelliteEphemerisHealth::GOOD;
+            break;
+        case GNSS_EPH_HEALTH_BAD:
+            out = GnssDebug::SatelliteEphemerisHealth::BAD;
+            break;
+        case GNSS_EPH_HEALTH_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisHealth::UNKNOWN;
+            break;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/location_api/LocationUtil.h b/gps/android/1.1/location_api/LocationUtil.h
new file mode 100644
index 0000000..af3c93f
--- /dev/null
+++ b/gps/android/1.1/location_api/LocationUtil.h
@@ -0,0 +1,57 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOCATION_UTIL_H
+#define LOCATION_UTIL_H
+
+#include <android/hardware/gnss/1.0/types.h>
+#include <LocationAPI.h>
+#include <GnssDebug.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out);
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out);
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out);
+void convertGnssSvid(GnssSv& in, int16_t& out);
+void convertGnssSvid(GnssMeasurementsData& in, int16_t& out);
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out);
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out);
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out);
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // LOCATION_UTIL_H
diff --git a/gps/android/1.1/location_api/MeasurementAPIClient.cpp b/gps/android/1.1/location_api/MeasurementAPIClient.cpp
new file mode 100644
index 0000000..a87ae6d
--- /dev/null
+++ b/gps/android/1.1/location_api/MeasurementAPIClient.cpp
@@ -0,0 +1,332 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_MeasurementAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "MeasurementAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V1_1::IGnssMeasurementCallback;
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+        V1_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+        IGnssMeasurementCallback::GnssData& out);
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+        V1_0::IGnssMeasurementCallback::GnssMeasurement& out);
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out);
+
+MeasurementAPIClient::MeasurementAPIClient() :
+    mGnssMeasurementCbIface(nullptr),
+    mGnssMeasurementCbIface_1_1(nullptr),
+    mTracking(false)
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+MeasurementAPIClient::~MeasurementAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+// for GpsInterface
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback(const sp<V1_0::IGnssMeasurementCallback>& callback)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    mMutex.lock();
+    mGnssMeasurementCbIface = callback;
+    mMutex.unlock();
+
+    return startTracking();
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback_1_1(
+        const sp<IGnssMeasurementCallback>& callback,
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LOC_LOGD("%s]: (%p) (powermode: %d) (tbm: %d)",
+            __FUNCTION__, &callback, (int)powerMode, timeBetweenMeasurement);
+
+    mMutex.lock();
+    mGnssMeasurementCbIface_1_1 = callback;
+    mMutex.unlock();
+
+    return startTracking(powerMode, timeBetweenMeasurement);
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::startTracking(
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+    if (mGnssMeasurementCbIface_1_1 != nullptr || mGnssMeasurementCbIface != nullptr) {
+        locationCallbacks.gnssMeasurementsCb =
+            [this](GnssMeasurementsNotification gnssMeasurementsNotification) {
+                onGnssMeasurementsCb(gnssMeasurementsNotification);
+            };
+    }
+
+    locAPISetCallbacks(locationCallbacks);
+
+    TrackingOptions options = {};
+    memset(&options, 0, sizeof(TrackingOptions));
+    options.size = sizeof(TrackingOptions);
+    options.minInterval = 1000;
+    options.mode = GNSS_SUPL_MODE_STANDALONE;
+    if (GNSS_POWER_MODE_INVALID != powerMode) {
+        options.powerMode = powerMode;
+        options.tbm = timeBetweenMeasurement;
+    }
+
+    mTracking = true;
+    LOC_LOGD("%s]: start tracking session", __FUNCTION__);
+    locAPIStartTracking(options);
+    return IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+// for GpsMeasurementInterface
+void MeasurementAPIClient::measurementClose() {
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    mTracking = false;
+    locAPIStopTracking();
+}
+
+// callbacks
+void MeasurementAPIClient::onGnssMeasurementsCb(
+        GnssMeasurementsNotification gnssMeasurementsNotification)
+{
+    LOC_LOGD("%s]: (count: %zu active: %d)",
+            __FUNCTION__, gnssMeasurementsNotification.count, mTracking);
+    if (mTracking) {
+        mMutex.lock();
+        sp<V1_0::IGnssMeasurementCallback> gnssMeasurementCbIface = nullptr;
+        sp<IGnssMeasurementCallback> gnssMeasurementCbIface_1_1 = nullptr;
+        if (mGnssMeasurementCbIface_1_1 != nullptr) {
+            gnssMeasurementCbIface_1_1 = mGnssMeasurementCbIface_1_1;
+        } else if (mGnssMeasurementCbIface != nullptr) {
+            gnssMeasurementCbIface = mGnssMeasurementCbIface;
+        }
+        mMutex.unlock();
+
+        if (gnssMeasurementCbIface_1_1 != nullptr) {
+            IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData_1_1(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface_1_1->gnssMeasurementCb(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssMeasurementCbIface != nullptr) {
+            V1_0::IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface->GnssMeasurementCb(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from GnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+        V1_0::IGnssMeasurementCallback::GnssMeasurement& out)
+{
+    memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssMeasurement));
+    if (in.flags & GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SNR;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_FREQUENCY;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_CYCLES;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL;
+    convertGnssSvid(in, out.svid);
+    convertGnssConstellationType(in.svType, out.constellation);
+    out.timeOffsetNs = in.timeOffsetNs;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+    if (in.stateMask &  GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+    out.receivedSvTimeInNs = in.receivedSvTimeNs;
+    out.receivedSvTimeUncertaintyInNs = in.receivedSvTimeUncertaintyNs;
+    out.cN0DbHz = in.carrierToNoiseDbHz;
+    out.pseudorangeRateMps = in.pseudorangeRateMps;
+    out.pseudorangeRateUncertaintyMps = in.pseudorangeRateUncertaintyMps;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+    out.accumulatedDeltaRangeM = in.adrMeters;
+    out.accumulatedDeltaRangeUncertaintyM = in.adrUncertaintyMeters;
+    out.carrierFrequencyHz = in.carrierFrequencyHz;
+    out.carrierCycles = in.carrierCycles;
+    out.carrierPhase = in.carrierPhase;
+    out.carrierPhaseUncertainty = in.carrierPhaseUncertainty;
+    uint8_t indicator =
+        static_cast<uint8_t>(IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN);
+    if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_PRESENT)
+        indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_PRESENT;
+    if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_NOT_PRESENT)
+        indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATIOR_NOT_PRESENT;
+    out.multipathIndicator =
+        static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>(indicator);
+    out.snrDb = in.signalToNoiseRatioDb;
+    out.agcLevelDb = in.agcLevelDb;
+}
+
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out)
+{
+    memset(&out, 0, sizeof(IGnssMeasurementCallback::GnssClock));
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_LEAP_SECOND_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_LEAP_SECOND;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_TIME_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_FULL_BIAS_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_FULL_BIAS;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT_UNCERTAINTY;
+    out.leapSecond = in.leapSecond;
+    out.timeNs = in.timeNs;
+    out.timeUncertaintyNs = in.timeUncertaintyNs;
+    out.fullBiasNs = in.fullBiasNs;
+    out.biasNs = in.biasNs;
+    out.biasUncertaintyNs = in.biasUncertaintyNs;
+    out.driftNsps = in.driftNsps;
+    out.driftUncertaintyNsps = in.driftUncertaintyNsps;
+    out.hwClockDiscontinuityCount = in.hwClockDiscontinuityCount;
+}
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+        V1_0::IGnssMeasurementCallback::GnssData& out)
+{
+    out.measurementCount = in.count;
+    if (out.measurementCount > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+        LOC_LOGW("%s]: Too many measurement %u. Clamps to %d.",
+                __FUNCTION__,  out.measurementCount, V1_0::GnssMax::SVS_COUNT);
+        out.measurementCount = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+    }
+    for (size_t i = 0; i < out.measurementCount; i++) {
+        convertGnssMeasurement(in.measurements[i], out.measurements[i]);
+    }
+    convertGnssClock(in.clock, out.clock);
+}
+
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+        IGnssMeasurementCallback::GnssData& out)
+{
+    out.measurements.resize(in.count);
+    for (size_t i = 0; i < in.count; i++) {
+        convertGnssMeasurement(in.measurements[i], out.measurements[i].v1_0);
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+            out.measurements[i].accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+            out.measurements[i].accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+            out.measurements[i].accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_HALF_CYCLE_RESOLVED_BIT)
+            out.measurements[i].accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_HALF_CYCLE_RESOLVED;
+    }
+    convertGnssClock(in.clock, out.clock);
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/1.1/location_api/MeasurementAPIClient.h b/gps/android/1.1/location_api/MeasurementAPIClient.h
new file mode 100644
index 0000000..5fb307c
--- /dev/null
+++ b/gps/android/1.1/location_api/MeasurementAPIClient.h
@@ -0,0 +1,85 @@
+/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MEASUREMENT_API_CLINET_H
+#define MEASUREMENT_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/1.1/IGnssMeasurement.h>
+#include <android/hardware/gnss/1.1/IGnssMeasurementCallback.h>
+#include <LocationAPIClientBase.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::sp;
+
+class MeasurementAPIClient : public LocationAPIClientBase
+{
+public:
+    MeasurementAPIClient();
+    MeasurementAPIClient(const MeasurementAPIClient&) = delete;
+    MeasurementAPIClient& operator=(const MeasurementAPIClient&) = delete;
+
+    // for GpsMeasurementInterface
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback(
+            const sp<V1_0::IGnssMeasurementCallback>& callback);
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback_1_1(
+            const sp<IGnssMeasurementCallback>& callback,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+    void measurementClose();
+    Return<IGnssMeasurement::GnssMeasurementStatus> startTracking(
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+
+    // callbacks we are interested in
+    void onGnssMeasurementsCb(GnssMeasurementsNotification gnssMeasurementsNotification) final;
+
+private:
+    virtual ~MeasurementAPIClient();
+
+    std::mutex mMutex;
+    sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface;
+    sp<IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1;
+
+    bool mTracking;
+};
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // MEASUREMENT_API_CLINET_H
diff --git a/gps/android/1.1/service.cpp b/gps/android/1.1/service.cpp
new file mode 100644
index 0000000..0cb91f7
--- /dev/null
+++ b/gps/android/1.1/service.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "android.hardware.gnss@1.1-service-qti"
+
+#include <android/hardware/gnss/1.1/IGnss.h>
+#include <hidl/LegacySupport.h>
+#include "loc_cfg.h"
+#include "loc_misc_utils.h"
+
+extern "C" {
+#include "vndfwk-detect.h"
+}
+
+#ifdef ARCH_ARM_32
+#define DEFAULT_HW_BINDER_MEM_SIZE 65536
+#endif
+
+using android::hardware::gnss::V1_1::IGnss;
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::registerPassthroughServiceImplementation;
+using android::hardware::joinRpcThreadpool;
+
+using android::status_t;
+using android::OK;
+
+typedef int vendorEnhancedServiceMain(int /* argc */, char* /* argv */ []);
+
+int main() {
+
+    ALOGI("%s", __FUNCTION__);
+
+    int vendorInfo = getVendorEnhancedInfo();
+    bool vendorEnhanced = ( 1 == vendorInfo || 3 == vendorInfo );
+    setVendorEnhanced(vendorEnhanced);
+
+#ifdef ARCH_ARM_32
+    android::hardware::ProcessState::initWithMmapSize((size_t)(DEFAULT_HW_BINDER_MEM_SIZE));
+#endif
+    configureRpcThreadpool(1, true);
+    status_t status;
+
+    status = registerPassthroughServiceImplementation<IGnss>();
+    if (status == OK) {
+        if (vendorEnhanced) {
+    #ifdef LOC_HIDL_VERSION
+            #define VENDOR_ENHANCED_LIB "vendor.qti.gnss@" LOC_HIDL_VERSION "-service.so"
+
+            void* libHandle = NULL;
+            vendorEnhancedServiceMain* vendorEnhancedMainMethod = (vendorEnhancedServiceMain*)
+                    dlGetSymFromLib(libHandle, VENDOR_ENHANCED_LIB, "main");
+            if (NULL != vendorEnhancedMainMethod) {
+                (*vendorEnhancedMainMethod)(0, NULL);
+            }
+    #else
+            ALOGE("LOC_HIDL_VERSION not defined.");
+    #endif
+        }
+
+        joinRpcThreadpool();
+
+    } else {
+        ALOGE("Error while registering IGnss 1.1 service: %d", status);
+    }
+
+    return 0;
+}
diff --git a/gps/android/2.0/AGnss.cpp b/gps/android/2.0/AGnss.cpp
new file mode 100644
index 0000000..a48f1a0
--- /dev/null
+++ b/gps/android/2.0/AGnss.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_AGnssInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "AGnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+static AGnss* spAGnss = nullptr;
+
+AGnss::AGnss(Gnss* gnss) : mGnss(gnss) {
+    spAGnss = this;
+}
+
+AGnss::~AGnss() {
+    spAGnss = nullptr;
+}
+
+void AGnss::agnssStatusIpV4Cb(AGnssExtStatusIpV4 status) {
+    if (nullptr != spAGnss) {
+        spAGnss->statusCb(status.type, status.status);
+    }
+}
+
+void AGnss::statusCb(AGpsExtType type, LocAGpsStatusValue status) {
+
+    V2_0::IAGnssCallback::AGnssType  aType;
+    IAGnssCallback::AGnssStatusValue aStatus;
+
+    switch (type) {
+    case LOC_AGPS_TYPE_SUPL:
+        aType = IAGnssCallback::AGnssType::SUPL;
+        break;
+    case LOC_AGPS_TYPE_SUPL_ES:
+        aType = IAGnssCallback::AGnssType::SUPL_EIMS;
+        break;
+    default:
+        LOC_LOGE("invalid type: %d", type);
+        return;
+    }
+
+    switch (status) {
+    case LOC_GPS_REQUEST_AGPS_DATA_CONN:
+        aStatus = IAGnssCallback::AGnssStatusValue::REQUEST_AGNSS_DATA_CONN;
+        break;
+    case LOC_GPS_RELEASE_AGPS_DATA_CONN:
+        aStatus = IAGnssCallback::AGnssStatusValue::RELEASE_AGNSS_DATA_CONN;
+        break;
+    case LOC_GPS_AGPS_DATA_CONNECTED:
+        aStatus = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONNECTED;
+        break;
+    case LOC_GPS_AGPS_DATA_CONN_DONE:
+        aStatus = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_DONE;
+        break;
+    case LOC_GPS_AGPS_DATA_CONN_FAILED:
+        aStatus = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_FAILED;
+        break;
+    default:
+        LOC_LOGE("invalid status: %d", status);
+        return;
+    }
+
+    if (mAGnssCbIface != nullptr) {
+        auto r = mAGnssCbIface->agnssStatusCb(aType, aStatus);
+        if (!r.isOk()) {
+            LOC_LOGw("Error invoking AGNSS status cb %s", r.description().c_str());
+        }
+    }
+    else {
+        LOC_LOGw("setCallback has not been called yet");
+    }
+}
+
+Return<void> AGnss::setCallback(const sp<V2_0::IAGnssCallback>& callback) {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return Void();
+    }
+
+    // Save the interface
+    mAGnssCbIface = callback;
+
+    AgpsCbInfo cbInfo = {};
+    cbInfo.statusV4Cb = (void*)agnssStatusIpV4Cb;
+    cbInfo.atlType = AGPS_ATL_TYPE_SUPL | AGPS_ATL_TYPE_SUPL_ES;
+
+    mGnss->getGnssInterface()->agpsInit(cbInfo);
+    return Void();
+}
+
+Return<bool> AGnss::dataConnClosed() {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnClosed(LOC_AGPS_TYPE_SUPL);
+    return true;
+}
+
+Return<bool> AGnss::dataConnFailed() {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnFailed(LOC_AGPS_TYPE_SUPL);
+    return true;
+}
+
+Return<bool> AGnss::dataConnOpen(uint64_t /*networkHandle*/, const hidl_string& apn,
+        V2_0::IAGnss::ApnIpType apnIpType) {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    /* Validate */
+    if(apn.empty()){
+        LOC_LOGE("Invalid APN");
+        return false;
+    }
+
+    LOC_LOGD("dataConnOpen APN name = [%s]", apn.c_str());
+
+    AGpsBearerType bearerType;
+    switch (apnIpType) {
+    case IAGnss::ApnIpType::IPV4:
+        bearerType = AGPS_APN_BEARER_IPV4;
+        break;
+    case IAGnss::ApnIpType::IPV6:
+        bearerType = AGPS_APN_BEARER_IPV6;
+        break;
+    case IAGnss::ApnIpType::IPV4V6:
+        bearerType = AGPS_APN_BEARER_IPV4V6;
+        break;
+    default:
+        bearerType = AGPS_APN_BEARER_IPV4;
+        break;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnOpen(
+        LOC_AGPS_TYPE_SUPL, apn.c_str(), apn.size(), (int)bearerType);
+    return true;
+}
+
+Return<bool> AGnss::setServer(V2_0::IAGnssCallback::AGnssType type,
+                              const hidl_string& hostname,
+                              int32_t port) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+    config.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+    if (type == IAGnssCallback::AGnssType::SUPL) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL;
+    } else if (type == IAGnssCallback::AGnssType::C2K) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_C2K;
+    } else if (type == IAGnssCallback::AGnssType::SUPL_EIMS) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL_EIMS;
+    } else if (type == IAGnssCallback::AGnssType::SUPL_IMS) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL_IMS;
+    } else {
+        LOC_LOGE("%s]: invalid AGnssType: %d", __FUNCTION__, static_cast<uint8_t>(type));
+        return false;
+    }
+    config.assistanceServer.hostName = strdup(hostname.c_str());
+    config.assistanceServer.port = port;
+    return mGnss->updateConfiguration(config);
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/AGnss.h b/gps/android/2.0/AGnss.h
new file mode 100644
index 0000000..c442327
--- /dev/null
+++ b/gps/android/2.0/AGnss.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
+#define ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
+
+#include <android/hardware/gnss/2.0/IAGnss.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct AGnss : public V2_0::IAGnss {
+
+    AGnss(Gnss* gnss);
+    ~AGnss();
+    /*
+     * Methods from ::android::hardware::gnss::V2_0::IAGnss interface follow.
+     * These declarations were generated from IAGnss.hal.
+     */
+    Return<void> setCallback(const sp<V2_0::IAGnssCallback>& callback) override;
+
+    Return<bool> dataConnClosed() override;
+
+    Return<bool> dataConnFailed() override;
+
+    Return<bool> dataConnOpen(uint64_t networkHandle, const hidl_string& apn,
+            V2_0::IAGnss::ApnIpType apnIpType) override;
+
+    Return<bool> setServer(V2_0::IAGnssCallback::AGnssType type,
+                         const hidl_string& hostname, int32_t port) override;
+
+    void statusCb(AGpsExtType type, LocAGpsStatusValue status);
+
+    /* Data call setup callback passed down to GNSS HAL implementation */
+    static void agnssStatusIpV4Cb(AGnssExtStatusIpV4 status);
+
+ private:
+    Gnss* mGnss = nullptr;
+    sp<IAGnssCallback> mAGnssCbIface = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
diff --git a/gps/android/2.0/AGnssRil.cpp b/gps/android/2.0/AGnssRil.cpp
new file mode 100644
index 0000000..d8005e4
--- /dev/null
+++ b/gps/android/2.0/AGnssRil.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc__AGnssRilInterface"
+
+#include <log_util.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sstream>
+#include <string>
+#include "Gnss.h"
+#include "AGnssRil.h"
+#include <DataItemConcreteTypesBase.h>
+
+typedef void* (getLocationInterface)();
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+
+AGnssRil::AGnssRil(Gnss* gnss) : mGnss(gnss) {
+    ENTRY_LOG_CALLFLOW();
+}
+
+AGnssRil::~AGnssRil() {
+    ENTRY_LOG_CALLFLOW();
+}
+
+Return<bool> AGnssRil::updateNetworkState(bool connected, NetworkType type, bool /*roaming*/) {
+    ENTRY_LOG_CALLFLOW();
+    // Extra NetworkTypes not available in IAgnssRil enums
+    const int NetworkType_BLUETOOTH = 7;
+    const int NetworkType_ETHERNET = 9;
+    const int NetworkType_PROXY = 16;
+    std::string apn("");
+
+    // for XTRA
+    if (nullptr != mGnss && ( nullptr != mGnss->getGnssInterface() )) {
+        int8_t typeout = loc_core::TYPE_UNKNOWN;
+        switch(type)
+        {
+            case IAGnssRil::NetworkType::MOBILE:
+                typeout = loc_core::TYPE_MOBILE;
+                break;
+            case IAGnssRil::NetworkType::WIFI:
+                typeout = loc_core::TYPE_WIFI;
+                break;
+            case IAGnssRil::NetworkType::MMS:
+                typeout = loc_core::TYPE_MMS;
+                break;
+            case IAGnssRil::NetworkType::SUPL:
+                typeout = loc_core::TYPE_SUPL;
+                break;
+            case IAGnssRil::NetworkType::DUN:
+                typeout = loc_core::TYPE_DUN;
+                break;
+            case IAGnssRil::NetworkType::HIPRI:
+                typeout = loc_core::TYPE_HIPRI;
+                break;
+            case IAGnssRil::NetworkType::WIMAX:
+                typeout = loc_core::TYPE_WIMAX;
+                break;
+            default:
+                {
+                    int networkType = (int) type;
+                    // Handling network types not available in IAgnssRil
+                    switch(networkType)
+                    {
+                        case NetworkType_BLUETOOTH:
+                            typeout = loc_core::TYPE_BLUETOOTH;
+                            break;
+                        case NetworkType_ETHERNET:
+                            typeout = loc_core::TYPE_ETHERNET;
+                            break;
+                        case NetworkType_PROXY:
+                            typeout = loc_core::TYPE_PROXY;
+                            break;
+                        default:
+                            typeout = loc_core::TYPE_UNKNOWN;
+                    }
+                }
+                break;
+        }
+        mGnss->getGnssInterface()->updateConnectionStatus(connected, typeout, false, 0, apn);
+    }
+    return true;
+}
+Return<bool> AGnssRil::updateNetworkState_2_0(const V2_0::IAGnssRil::NetworkAttributes& attributes) {
+    ENTRY_LOG_CALLFLOW();
+    std::string apn = attributes.apn;
+    if (nullptr != mGnss && (nullptr != mGnss->getGnssInterface())) {
+        int8_t typeout = loc_core::TYPE_UNKNOWN;
+        bool roaming = false;
+        if (attributes.capabilities & IAGnssRil::NetworkCapability::NOT_METERED) {
+            typeout = loc_core::TYPE_WIFI;
+        } else {
+            typeout = loc_core::TYPE_MOBILE;
+        }
+        if (attributes.capabilities & IAGnssRil::NetworkCapability::NOT_ROAMING) {
+            roaming = false;
+        }
+        LOC_LOGd("apn string received is: %s", apn.c_str());
+        mGnss->getGnssInterface()->updateConnectionStatus(attributes.isConnected,
+                typeout, roaming, (NetworkHandle) attributes.networkHandle, apn);
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/AGnssRil.h b/gps/android/2.0/AGnssRil.h
new file mode 100644
index 0000000..a04d8aa
--- /dev/null
+++ b/gps/android/2.0/AGnssRil.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H_
+#define ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H_
+
+#include <android/hardware/gnss/2.0/IAGnssRil.h>
+#include <hidl/Status.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+/*
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface Layer interface
+ * allows the GNSS chipset to request radio interface layer information from Android platform.
+ * Examples of such information are reference location, unique subscriber ID, phone number string
+ * and network availability changes. Also contains wrapper methods to allow methods from
+ * IAGnssiRilCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+struct AGnssRil : public V2_0::IAGnssRil {
+    AGnssRil(Gnss* gnss);
+    ~AGnssRil();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow.
+     * These declarations were generated from IAGnssRil.hal.
+     */
+    Return<void> setCallback(const sp<V1_0::IAGnssRilCallback>& /*callback*/) override {
+        return Void();
+    }
+    Return<void> setRefLocation(const V1_0::IAGnssRil::AGnssRefLocation& /*agnssReflocation*/) override {
+        return Void();
+    }
+    Return<bool> setSetId(V1_0::IAGnssRil::SetIDType /*type*/, const hidl_string& /*setid*/) override {
+        return false;
+    }
+    Return<bool> updateNetworkAvailability(bool /*available*/,
+                                    const hidl_string& /*apn*/) override {
+        return false;
+    }
+    Return<bool> updateNetworkState(bool connected, V1_0::IAGnssRil::NetworkType type, bool roaming) override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IAGnssRil follow
+    Return<bool> updateNetworkState_2_0(const V2_0::IAGnssRil::NetworkAttributes& attributes) override;
+
+ private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H_
diff --git a/gps/android/2.0/Android.mk b/gps/android/2.0/Android.mk
new file mode 100644
index 0000000..e3422f9
--- /dev/null
+++ b/gps/android/2.0/Android.mk
@@ -0,0 +1,112 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@2.0-impl-qti
+
+# activate the following line for debug purposes only, comment out for production
+#LOCAL_SANITIZE_DIAG += $(GNSS_SANITIZE_DIAG)
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+    AGnss.cpp \
+    Gnss.cpp \
+    AGnssRil.cpp \
+    GnssMeasurement.cpp \
+    GnssConfiguration.cpp \
+    GnssBatching.cpp \
+    GnssGeofencing.cpp \
+    GnssNi.cpp \
+    GnssDebug.cpp \
+    MeasurementCorrections.cpp \
+    GnssVisibilityControl.cpp
+
+LOCAL_SRC_FILES += \
+    location_api/GnssAPIClient.cpp \
+    location_api/MeasurementAPIClient.cpp \
+    location_api/GeofenceAPIClient.cpp \
+    location_api/BatchingAPIClient.cpp \
+    location_api/LocationUtil.cpp \
+
+ifeq ($(GNSS_HIDL_LEGACY_MEASURMENTS),true)
+LOCAL_CFLAGS += \
+     -DGNSS_HIDL_LEGACY_MEASURMENTS
+endif
+
+LOCAL_C_INCLUDES:= \
+    $(LOCAL_PATH)/location_api
+
+LOCAL_HEADER_LIBRARIES := \
+    libgps.utils_headers \
+    libloc_core_headers \
+    libloc_pla_headers \
+    liblocation_api_headers \
+    liblocbatterylistener_headers
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libhidlbase \
+    libcutils \
+    libutils \
+    android.hardware.gnss@1.0 \
+    android.hardware.gnss@1.1 \
+    android.hardware.gnss@2.0 \
+    android.hardware.gnss.measurement_corrections@1.0 \
+    android.hardware.gnss.visibility_control@1.0 \
+    android.hardware.health@1.0 \
+    android.hardware.health@2.0 \
+    android.hardware.health@2.1 \
+    android.hardware.power@1.2 \
+    libbase
+
+LOCAL_SHARED_LIBRARIES += \
+    libloc_core \
+    libgps.utils \
+    libdl \
+    liblocation_api \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@2.0-service-qti
+
+# activate the following line for debug purposes only, comment out for production
+#LOCAL_SANITIZE_DIAG += $(GNSS_SANITIZE_DIAG)
+LOCAL_VINTF_FRAGMENTS := android.hardware.gnss@2.0-service-qti.xml
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_INIT_RC := android.hardware.gnss@2.0-service-qti.rc
+LOCAL_SRC_FILES := \
+    service.cpp \
+
+LOCAL_HEADER_LIBRARIES := \
+    libgps.utils_headers \
+    libloc_core_headers \
+    libloc_pla_headers \
+    liblocation_api_headers
+
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libcutils \
+    libdl \
+    libbase \
+    libutils \
+    libgps.utils \
+    libqti_vndfwk_detect \
+
+LOCAL_SHARED_LIBRARIES += \
+    libhidlbase \
+    android.hardware.gnss@1.0 \
+    android.hardware.gnss@1.1 \
+    android.hardware.gnss@2.0 \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+ifneq ($(LOC_HIDL_VERSION),)
+LOCAL_CFLAGS += -DLOC_HIDL_VERSION='"$(LOC_HIDL_VERSION)"'
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/gps/android/2.0/Gnss.cpp b/gps/android/2.0/Gnss.cpp
new file mode 100644
index 0000000..823ef6e
--- /dev/null
+++ b/gps/android/2.0/Gnss.cpp
@@ -0,0 +1,677 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
+
+#include <fstream>
+#include <log_util.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "Gnss.h"
+#include "LocationUtil.h"
+#include "battery_listener.h"
+#include "loc_misc_utils.h"
+
+typedef const GnssInterface* (getLocationInterface)();
+
+#define IMAGES_INFO_FILE "/sys/devices/soc0/images"
+#define DELIMITER ";"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::visibility_control::V1_0::implementation::GnssVisibilityControl;
+static sp<Gnss> sGnss;
+static std::string getVersionString() {
+    static std::string version;
+    if (!version.empty())
+        return version;
+
+    char value[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware", value, "unknown");
+    version.append(value).append(DELIMITER);
+
+    std::ifstream in(IMAGES_INFO_FILE);
+    std::string s;
+    while(getline(in, s)) {
+        std::size_t found = s.find("CRM:");
+        if (std::string::npos == found) {
+            continue;
+        }
+
+        // skip over space characters after "CRM:"
+        const char* substr = s.c_str();
+        found += 4;
+        while (0 != substr[found] && isspace(substr[found])) {
+            found++;
+        }
+        if (s.find("11:") != found) {
+            continue;
+        }
+        s.erase(0, found + 3);
+
+        found = s.find_first_of("\r\n");
+        if (std::string::npos != found) {
+            s.erase(s.begin() + found, s.end());
+        }
+        version.append(s).append(DELIMITER);
+    }
+    return version;
+}
+
+void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnss != nullptr) {
+        mGnss->getGnssInterface()->resetNetworkInfo();
+        mGnss->cleanup();
+    }
+}
+
+void location_on_battery_status_changed(bool charging) {
+    LOC_LOGd("battery status changed to %s charging", charging ? "" : "not");
+    if (sGnss != nullptr) {
+        sGnss->getGnssInterface()->updateBatteryStatus(charging);
+    }
+}
+Gnss::Gnss() {
+    ENTRY_LOG_CALLFLOW();
+    sGnss = this;
+    // initilize gnss interface at first in case needing notify battery status
+    sGnss->getGnssInterface()->initialize();
+    // register health client to listen on battery change
+    loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
+    // clear pending GnssConfig
+    memset(&mPendingConfig, 0, sizeof(GnssConfig));
+    mGnssDeathRecipient = new GnssDeathRecipient(this);
+}
+
+Gnss::~Gnss() {
+    ENTRY_LOG_CALLFLOW();
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+    sGnss = nullptr;
+}
+
+GnssAPIClient* Gnss::getApi() {
+    if (mApi != nullptr) {
+        return mApi;
+    }
+
+    if (mGnssCbIface_2_0 != nullptr) {
+        mApi = new GnssAPIClient(mGnssCbIface_2_0);
+    } else if (mGnssCbIface_1_1 != nullptr) {
+        mApi = new GnssAPIClient(mGnssCbIface_1_1, mGnssNiCbIface);
+    } else if (mGnssCbIface != nullptr) {
+        mApi = new GnssAPIClient(mGnssCbIface, mGnssNiCbIface);
+    } else {
+        LOC_LOGW("%s] GnssAPIClient is not ready", __FUNCTION__);
+        return mApi;
+    }
+
+    if (mPendingConfig.size == sizeof(GnssConfig)) {
+        // we have pending GnssConfig
+        mApi->gnssConfigurationUpdate(mPendingConfig);
+        // clear size to invalid mPendingConfig
+        mPendingConfig.size = 0;
+        if (mPendingConfig.assistanceServer.hostName != nullptr) {
+            free((void*)mPendingConfig.assistanceServer.hostName);
+        }
+    }
+
+    return mApi;
+}
+
+const GnssInterface* Gnss::getGnssInterface() {
+    static bool getGnssInterfaceFailed = false;
+
+    if (nullptr == mGnssInterface && !getGnssInterfaceFailed) {
+        void * libHandle = nullptr;
+        getLocationInterface* getter = (getLocationInterface*)
+                dlGetSymFromLib(libHandle, "libgnss.so", "getGnssInterface");
+
+        if (nullptr == getter) {
+            getGnssInterfaceFailed = true;
+        } else {
+            mGnssInterface = (GnssInterface*)(*getter)();
+        }
+    }
+    return mGnssInterface;
+}
+
+Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback)  {
+    ENTRY_LOG_CALLFLOW();
+
+    // In case where previous call to setCallback_1_1 or setCallback_2_0, then
+    // we need to cleanup these interfaces/callbacks here since we no longer
+    // do so in cleanup() function to keep callbacks around after cleanup()
+    if (mApi != nullptr) {
+        mApi->gnssUpdateCallbacks_2_0(nullptr);
+    }
+    if (mGnssCbIface_1_1 != nullptr) {
+        mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_1_1 = nullptr;
+    }
+    if (mGnssCbIface_2_0 != nullptr) {
+        mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_2_0 = nullptr;
+    }
+
+
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+    }
+    mGnssCbIface = callback;
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+    }
+
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+        api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
+    }
+    return true;
+}
+
+Return<bool> Gnss::setGnssNiCb(const sp<IGnssNiCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    mGnssNiCbIface = callback;
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+    }
+    return true;
+}
+
+Return<bool> Gnss::updateConfiguration(GnssConfig& gnssConfig) {
+    ENTRY_LOG_CALLFLOW();
+    GnssAPIClient* api = getApi();
+    if (api) {
+        api->gnssConfigurationUpdate(gnssConfig);
+    } else if (gnssConfig.flags != 0) {
+        // api is not ready yet, update mPendingConfig with gnssConfig
+        mPendingConfig.size = sizeof(GnssConfig);
+
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+            mPendingConfig.gpsLock = gnssConfig.gpsLock;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+            mPendingConfig.suplVersion = gnssConfig.suplVersion;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+            mPendingConfig.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+            mPendingConfig.assistanceServer.type = gnssConfig.assistanceServer.type;
+            if (mPendingConfig.assistanceServer.hostName != nullptr) {
+                free((void*)mPendingConfig.assistanceServer.hostName);
+                mPendingConfig.assistanceServer.hostName =
+                    strdup(gnssConfig.assistanceServer.hostName);
+            }
+            mPendingConfig.assistanceServer.port = gnssConfig.assistanceServer.port;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+            mPendingConfig.lppProfileMask = gnssConfig.lppProfileMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT;
+            mPendingConfig.lppeControlPlaneMask = gnssConfig.lppeControlPlaneMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT;
+            mPendingConfig.lppeUserPlaneMask = gnssConfig.lppeUserPlaneMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+            mPendingConfig.aGlonassPositionProtocolMask = gnssConfig.aGlonassPositionProtocolMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+            mPendingConfig.emergencyPdnForEmergencySupl = gnssConfig.emergencyPdnForEmergencySupl;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+            mPendingConfig.suplEmergencyServices = gnssConfig.suplEmergencyServices;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+            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;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT;
+            mPendingConfig.emergencyExtensionSeconds = gnssConfig.emergencyExtensionSeconds;
+        }
+    }
+    return true;
+}
+
+Return<bool> Gnss::start()  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssStart();
+    }
+    return retVal;
+}
+
+Return<bool> Gnss::stop()  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssStop();
+    }
+    return retVal;
+}
+
+Return<void> Gnss::cleanup()  {
+    ENTRY_LOG_CALLFLOW();
+
+    if (mApi != nullptr) {
+        mApi->gnssStop();
+        mApi->gnssDisable();
+    }
+
+    return Void();
+}
+
+Return<bool> Gnss::injectLocation(double latitudeDegrees,
+                                  double longitudeDegrees,
+                                  float accuracyMeters)  {
+    ENTRY_LOG_CALLFLOW();
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        gnssInterface->injectLocation(latitudeDegrees, longitudeDegrees, accuracyMeters);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs,
+                              int32_t uncertaintyMs) {
+    return true;
+}
+
+Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags)  {
+    ENTRY_LOG_CALLFLOW();
+    GnssAPIClient* api = getApi();
+    if (api) {
+        api->gnssDeleteAidingData(aidingDataFlags);
+    }
+    return Void();
+}
+
+Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                   V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                   uint32_t minIntervalMs,
+                                   uint32_t preferredAccuracyMeters,
+                                   uint32_t preferredTimeMs)  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+                preferredAccuracyMeters, preferredTimeMs);
+    }
+    return retVal;
+}
+
+Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss()  {
+    ENTRY_LOG_CALLFLOW();
+    // deprecated function. Must return nullptr to pass VTS
+    return nullptr;
+}
+
+Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi()  {
+    ENTRY_LOG_CALLFLOW();
+    // deprecated function. Must return nullptr to pass VTS
+    return nullptr;
+}
+
+Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssMeasurement == nullptr)
+        mGnssMeasurement = new GnssMeasurement();
+    return mGnssMeasurement;
+}
+
+Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration()  {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssConfig == nullptr) {
+        mGnssConfig = new GnssConfiguration(this);
+    }
+    return mGnssConfig;
+}
+
+Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing()  {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssGeofencingIface == nullptr) {
+        mGnssGeofencingIface = new GnssGeofencing();
+    }
+    return mGnssGeofencingIface;
+}
+
+Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching()  {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssBatching == nullptr) {
+        mGnssBatching = new GnssBatching();
+    }
+    return mGnssBatching;
+}
+
+Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssDebug == nullptr) {
+        mGnssDebug = new GnssDebug(this);
+    }
+    return mGnssDebug;
+}
+
+Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssRil == nullptr) {
+        mGnssRil = new AGnssRil(this);
+    }
+    return mGnssRil;
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    auto r = callback->gnssNameCb(getVersionString());
+    if (!r.isOk()) {
+        LOC_LOGE("%s] Error from gnssNameCb description=%s",
+                __func__, r.description().c_str());
+    }
+
+    // In case where previous call to setCallback or setCallback_2_1, then
+    // we need to cleanup these interfaces/callbacks here since we no longer
+    // do so in cleanup() function to keep callbacks around after cleanup()
+    if (mApi != nullptr) {
+        mApi->gnssUpdateCallbacks_2_0(nullptr);
+    }
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface = nullptr;
+    }
+    if (mGnssCbIface_2_0 != nullptr) {
+        mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_2_0 = nullptr;
+    }
+
+
+    if (mGnssCbIface_1_1 != nullptr) {
+        mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+    }
+    mGnssCbIface_1_1 = callback;
+    if (mGnssCbIface_1_1 != nullptr) {
+        mGnssCbIface_1_1->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+    }
+
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        OdcpiRequestCallback cb = [this](const OdcpiRequestInfo& odcpiRequest) {
+            odcpiRequestCb(odcpiRequest);
+        };
+        gnssInterface->odcpiInit(cb, OdcpiPrioritytype::ODCPI_HANDLER_PRIORITY_LOW);
+    }
+
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface_1_1, mGnssNiCbIface);
+        api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
+    }
+
+    return true;
+}
+
+Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+        V1_0::IGnss::GnssPositionRecurrence recurrence,
+        uint32_t minIntervalMs,
+        uint32_t preferredAccuracyMeters,
+        uint32_t preferredTimeMs,
+        bool lowPowerMode) {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        GnssPowerMode powerMode = lowPowerMode?
+                GNSS_POWER_MODE_M4 : GNSS_POWER_MODE_M2;
+        retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+                preferredAccuracyMeters, preferredTimeMs, powerMode, minIntervalMs);
+    }
+    return retVal;
+}
+
+Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
+    ENTRY_LOG_CALLFLOW();
+#ifdef GNSS_HIDL_LEGACY_MEASURMENTS
+    return nullptr;
+#else
+    if (mGnssMeasurement == nullptr)
+        mGnssMeasurement = new GnssMeasurement();
+    return mGnssMeasurement;
+#endif
+}
+
+Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssConfig == nullptr)
+        mGnssConfig = new GnssConfiguration(this);
+    return mGnssConfig;
+}
+
+Return<bool> Gnss::injectBestLocation(const GnssLocation& gnssLocation) {
+    ENTRY_LOG_CALLFLOW();
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        Location location = {};
+        convertGnssLocation(gnssLocation, location);
+        gnssInterface->odcpiInject(location);
+    }
+    return true;
+}
+
+void Gnss::odcpiRequestCb(const OdcpiRequestInfo& request) {
+    ENTRY_LOG_CALLFLOW();
+
+    if (ODCPI_REQUEST_TYPE_STOP == request.type) {
+        return;
+    }
+    if (mGnssCbIface_2_0 != nullptr) {
+        // For emergency mode, request DBH (Device based hybrid) location
+        // Mark Independent from GNSS flag to false.
+        if (ODCPI_REQUEST_TYPE_START == request.type) {
+            LOC_LOGd("gnssRequestLocationCb_2_0 isUserEmergency = %d", request.isEmergencyMode);
+            auto r = mGnssCbIface_2_0->gnssRequestLocationCb_2_0(!request.isEmergencyMode,
+                                                                 request.isEmergencyMode);
+            if (!r.isOk()) {
+                LOC_LOGe("Error invoking gnssRequestLocationCb_2_0 %s", r.description().c_str());
+            }
+        } else {
+            LOC_LOGv("Unsupported ODCPI request type: %d", request.type);
+        }
+    } else if (mGnssCbIface_1_1 != nullptr) {
+        // For emergency mode, request DBH (Device based hybrid) location
+        // Mark Independent from GNSS flag to false.
+        if (ODCPI_REQUEST_TYPE_START == request.type) {
+            auto r = mGnssCbIface_1_1->gnssRequestLocationCb(!request.isEmergencyMode);
+            if (!r.isOk()) {
+                LOC_LOGe("Error invoking gnssRequestLocationCb %s", r.description().c_str());
+            }
+        } else {
+            LOC_LOGv("Unsupported ODCPI request type: %d", request.type);
+        }
+    } else {
+        LOC_LOGe("ODCPI request not supported.");
+    }
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnss follow.
+Return<bool> Gnss::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    auto r = callback->gnssNameCb(getVersionString());
+    if (!r.isOk()) {
+        LOC_LOGE("%s] Error from gnssNameCb description=%s",
+                __func__, r.description().c_str());
+    }
+
+    // In case where previous call to setCallback or setCallback_1_1, then
+    // we need to cleanup these interfaces/callbacks here since we no longer
+    // do so in cleanup() function to keep callbacks around after cleanup()
+    if (mApi != nullptr) {
+        mApi->gnssUpdateCallbacks(nullptr, nullptr);
+    }
+    mGnssNiCbIface = nullptr;
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface = nullptr;
+    }
+    if (mGnssCbIface_1_1 != nullptr) {
+        mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_1_1 = nullptr;
+    }
+
+    if (mGnssCbIface_2_0 != nullptr) {
+        mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+    }
+    mGnssCbIface_2_0 = callback;
+    if (mGnssCbIface_2_0 != nullptr) {
+        mGnssCbIface_2_0->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+    }
+
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        OdcpiRequestCallback cb = [this](const OdcpiRequestInfo& odcpiRequest) {
+            odcpiRequestCb(odcpiRequest);
+        };
+        gnssInterface->odcpiInit(cb, OdcpiPrioritytype::ODCPI_HANDLER_PRIORITY_LOW);
+    }
+
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks_2_0(mGnssCbIface_2_0);
+        api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
+    }
+
+    return true;
+}
+
+Return<sp<V2_0::IAGnss>> Gnss::getExtensionAGnss_2_0() {
+    ENTRY_LOG_CALLFLOW();
+    if (mAGnssIface_2_0 == nullptr) {
+        mAGnssIface_2_0 = new AGnss(this);
+    }
+    return mAGnssIface_2_0;
+}
+Return<sp<V2_0::IAGnssRil>> Gnss::getExtensionAGnssRil_2_0() {
+    if (mGnssRil == nullptr) {
+        mGnssRil = new AGnssRil(this);
+    }
+    return mGnssRil;
+}
+
+Return<sp<V2_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_0() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssConfig == nullptr) {
+        mGnssConfig = new GnssConfiguration(this);
+    }
+    return mGnssConfig;
+}
+Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() {
+    ENTRY_LOG_CALLFLOW();
+#ifdef GNSS_HIDL_LEGACY_MEASURMENTS
+    return nullptr;
+#else
+    if (mGnssMeasurement == nullptr)
+        mGnssMeasurement = new GnssMeasurement();
+    return mGnssMeasurement;
+#endif
+}
+Return<sp<::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections>>
+        Gnss::getExtensionMeasurementCorrections() {
+    // We do not support, so return nullptr to pass VTS
+    return nullptr;
+}
+Return<sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl>>
+        Gnss::getExtensionVisibilityControl() {
+    ENTRY_LOG_CALLFLOW();
+    if (mVisibCtrl == nullptr) {
+        mVisibCtrl = new GnssVisibilityControl(this);
+    }
+    return mVisibCtrl;
+}
+
+Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation& gnssLocation) {
+    ENTRY_LOG_CALLFLOW();
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        Location location = {};
+        convertGnssLocation(gnssLocation, location);
+        gnssInterface->odcpiInject(location);
+    }
+    return true;
+}
+
+Return<sp<V2_0::IGnssDebug>> Gnss::getExtensionGnssDebug_2_0() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssDebug == nullptr) {
+        mGnssDebug = new GnssDebug(this);
+    }
+    return mGnssDebug;
+}
+
+Return<sp<V2_0::IGnssBatching>> Gnss::getExtensionGnssBatching_2_0() {
+    return nullptr;
+}
+
+V1_0::IGnss* HIDL_FETCH_IGnss(const char* hal) {
+    ENTRY_LOG_CALLFLOW();
+    V1_0::IGnss* iface = nullptr;
+    iface = new Gnss();
+    if (iface == nullptr) {
+        LOC_LOGE("%s]: failed to get %s", __FUNCTION__, hal);
+    }
+    return iface;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/Gnss.h b/gps/android/2.0/Gnss.h
new file mode 100644
index 0000000..a403d61
--- /dev/null
+++ b/gps/android/2.0/Gnss.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSS_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSS_H
+
+#include <AGnss.h>
+#include <AGnssRil.h>
+#include <GnssConfiguration.h>
+#include <GnssMeasurement.h>
+#include <GnssBatching.h>
+#include <GnssGeofencing.h>
+#include <GnssNi.h>
+#include <GnssDebug.h>
+
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <MeasurementCorrections.h>
+#include <GnssVisibilityControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include "GnssAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using ::android::hardware::gnss::measurement_corrections::V1_0::implementation::MeasurementCorrections;
+using ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
+
+struct Gnss : public IGnss {
+    Gnss();
+    ~Gnss();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnss follow.
+     * These declarations were generated from Gnss.hal.
+     */
+    Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback)  override;
+    Return<bool> start()  override;
+    Return<bool> stop()  override;
+    Return<void> cleanup()  override;
+    Return<bool> injectLocation(double latitudeDegrees,
+                                double longitudeDegrees,
+                                float accuracyMeters)  override;
+    Return<bool> injectTime(int64_t timeMs,
+                            int64_t timeReferenceMs,
+                            int32_t uncertaintyMs) override;
+    Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags)  override;
+    Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                 V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                 uint32_t minIntervalMs,
+                                 uint32_t preferredAccuracyMeters,
+                                 uint32_t preferredTimeMs)  override;
+    Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+    Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+    Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+    Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+    Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+    Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+    Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+
+    inline Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override {
+        return nullptr;
+    }
+
+    inline Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override {
+        return nullptr;
+    }
+
+    Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+    Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
+    Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+            V1_0::IGnss::GnssPositionRecurrence recurrence,
+            uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+            uint32_t preferredTimeMs, bool lowPowerMode) override;
+    Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+    Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+    Return<bool> injectBestLocation(const GnssLocation& location) override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IGnss follow.
+    Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override;
+    Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override;
+    Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override;
+
+    Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
+    Return<sp<::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections>>
+            getExtensionMeasurementCorrections() override;
+    Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
+
+    Return<bool> injectBestLocation_2_0(const ::android::hardware::gnss::V2_0::GnssLocation& location) override;
+
+    Return<sp<V2_0::IGnssBatching>> getExtensionGnssBatching_2_0() override;
+    Return<sp<V2_0::IGnssDebug>> getExtensionGnssDebug_2_0() override;
+
+
+    /**
+     * This method returns the IGnssVisibilityControl interface.
+     *
+     * @return visibilityControlIface Handle to the IGnssVisibilityControl interface.
+     */
+    Return<sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl>>
+            getExtensionVisibilityControl() override;
+
+
+    // These methods are not part of the IGnss base class.
+    GnssAPIClient* getApi();
+    Return<bool> setGnssNiCb(const sp<IGnssNiCallback>& niCb);
+    Return<bool> updateConfiguration(GnssConfig& gnssConfig);
+    const GnssInterface* getGnssInterface();
+
+    // Callback for ODCPI request
+    void odcpiRequestCb(const OdcpiRequestInfo& request);
+
+ private:
+    struct GnssDeathRecipient : hidl_death_recipient {
+        GnssDeathRecipient(sp<Gnss> gnss) : mGnss(gnss) {
+        }
+        ~GnssDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<Gnss> mGnss;
+    };
+
+ private:
+    sp<GnssDeathRecipient> mGnssDeathRecipient = nullptr;
+
+    sp<V1_0::IGnssNi> mGnssNi = nullptr;
+    sp<V1_0::IGnssGeofencing> mGnssGeofencingIface = nullptr;
+    sp<V1_0::IAGnss> mAGnssIface = nullptr;
+    sp<V1_0::IGnssCallback> mGnssCbIface = nullptr;
+    sp<V1_0::IGnssNiCallback> mGnssNiCbIface = nullptr;
+    sp<V1_1::IGnssCallback> mGnssCbIface_1_1 = nullptr;
+    sp<V2_0::IAGnss> mAGnssIface_2_0 = nullptr;
+    sp<V2_0::IAGnssRil> mGnssRil = nullptr;
+    sp<V2_0::IGnssMeasurement> mGnssMeasurement = nullptr;
+    sp<V2_0::IGnssConfiguration> mGnssConfig = nullptr;
+    sp<V2_0::IGnssBatching> mGnssBatching = nullptr;
+    sp<V2_0::IGnssDebug> mGnssDebug = nullptr;
+    sp<V2_0::IGnssCallback> mGnssCbIface_2_0 = nullptr;
+    sp<IMeasurementCorrections> mGnssMeasCorr = nullptr;
+    sp<IGnssVisibilityControl> mVisibCtrl = nullptr;
+
+    GnssAPIClient* mApi = nullptr;
+    GnssConfig mPendingConfig;
+    const GnssInterface* mGnssInterface = nullptr;
+};
+
+extern "C" V1_0::IGnss* HIDL_FETCH_IGnss(const char* name);
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSS_H
diff --git a/gps/android/2.0/GnssBatching.cpp b/gps/android/2.0/GnssBatching.cpp
new file mode 100644
index 0000000..6a2a09e
--- /dev/null
+++ b/gps/android/2.0/GnssBatching.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssBatchingInterface"
+
+#include <log_util.h>
+#include <BatchingAPIClient.h>
+#include "GnssBatching.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void GnssBatching::GnssBatchingDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssBatching != nullptr) {
+        mGnssBatching->stop();
+        mGnssBatching->cleanup();
+    }
+}
+
+GnssBatching::GnssBatching() : mApi(nullptr) {
+    mGnssBatchingDeathRecipient = new GnssBatchingDeathRecipient(this);
+}
+
+GnssBatching::~GnssBatching() {
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+Return<bool> GnssBatching::init(const sp<V1_0::IGnssBatchingCallback>& callback) {
+    if (mApi != nullptr) {
+        LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+        mApi->destroy();
+        mApi = nullptr;
+    }
+
+    mApi = new BatchingAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+        return false;
+    }
+
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+    }
+    mGnssBatchingCbIface = callback;
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return true;
+}
+
+Return<uint16_t> GnssBatching::getBatchSize() {
+    uint16_t ret = 0;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->getBatchSize();
+    }
+    return ret;
+}
+
+Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
+    bool ret = false;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->startSession(options);
+    }
+    return ret;
+}
+
+Return<void> GnssBatching::flush() {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->flushBatchedLocations();
+    }
+    return Void();
+}
+
+Return<bool> GnssBatching::stop() {
+    bool ret = false;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->stopSession();
+    }
+    return ret;
+}
+
+Return<void> GnssBatching::cleanup() {
+    if (mApi != nullptr) {
+        mApi->stopSession();
+    }
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+        mGnssBatchingCbIface = nullptr;
+    }
+    if (mGnssBatchingCbIface_2_0 != nullptr) {
+        mGnssBatchingCbIface_2_0->unlinkToDeath(mGnssBatchingDeathRecipient);
+        mGnssBatchingCbIface_2_0 = nullptr;
+    }
+    return Void();
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnssBatching follow.
+Return<bool> GnssBatching::init_2_0(const sp<V2_0::IGnssBatchingCallback>& callback) {
+    if (mApi != nullptr) {
+        LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+        mApi->destroy();
+        mApi = nullptr;
+    }
+
+    mApi = new BatchingAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+        return false;
+    }
+
+    if (mGnssBatchingCbIface_2_0 != nullptr) {
+        mGnssBatchingCbIface_2_0->unlinkToDeath(mGnssBatchingDeathRecipient);
+    }
+    mGnssBatchingCbIface_2_0 = callback;
+    if (mGnssBatchingCbIface_2_0 != nullptr) {
+        mGnssBatchingCbIface_2_0->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/GnssBatching.h b/gps/android/2.0/GnssBatching.h
new file mode 100644
index 0000000..4c8d1db
--- /dev/null
+++ b/gps/android/2.0/GnssBatching.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
+
+#include <android/hardware/gnss/2.0/IGnssBatching.h>
+#include <hidl/Status.h>
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnssBatching;
+using ::android::hardware::gnss::V2_0::IGnssBatchingCallback;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+class BatchingAPIClient;
+struct GnssBatching : public IGnssBatching {
+    GnssBatching();
+    ~GnssBatching();
+
+    // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+    Return<bool> init(const sp<V1_0::IGnssBatchingCallback>& callback) override;
+    Return<uint16_t> getBatchSize() override;
+    Return<bool> start(const IGnssBatching::Options& options ) override;
+    Return<void> flush() override;
+    Return<bool> stop() override;
+    Return<void> cleanup() override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IGnssBatching follow.
+    Return<bool> init_2_0(const sp<V2_0::IGnssBatchingCallback>& callback) override;
+
+ private:
+    struct GnssBatchingDeathRecipient : hidl_death_recipient {
+        GnssBatchingDeathRecipient(sp<GnssBatching> gnssBatching) :
+            mGnssBatching(gnssBatching) {
+        }
+        ~GnssBatchingDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssBatching> mGnssBatching;
+    };
+
+ private:
+    sp<GnssBatchingDeathRecipient> mGnssBatchingDeathRecipient = nullptr;
+    sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface = nullptr;
+    BatchingAPIClient* mApi = nullptr;
+    sp<V2_0::IGnssBatchingCallback> mGnssBatchingCbIface_2_0 = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
diff --git a/gps/android/2.0/GnssConfiguration.cpp b/gps/android/2.0/GnssConfiguration.cpp
new file mode 100644
index 0000000..55a70dc
--- /dev/null
+++ b/gps/android/2.0/GnssConfiguration.cpp
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssConfigurationInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssConfiguration.h"
+#include "ContextBase.h"
+#include <android/hardware/gnss/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::GnssConstellationType;
+using namespace loc_core;
+
+GnssConfiguration::GnssConfiguration(Gnss* gnss) : mGnss(gnss) {
+}
+
+// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enabled)  {
+    // deprecated function. Must return false to pass VTS
+    return false;
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t version)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+    switch (version) {
+        case 0x00020004:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_4;
+            break;
+        case 0x00020002:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_2;
+            break;
+        case 0x00020000:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_0;
+            break;
+        case 0x00010000:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_1_0_0;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid version: 0x%x.", __FUNCTION__, version);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplMode(uint8_t mode)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+    switch (mode) {
+        case 0:
+            config.suplModeMask = 0; // STANDALONE ONLY
+            break;
+        case 1:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT;
+            break;
+        case 2:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+            break;
+        case 3:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT | GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid mode: %d.", __FUNCTION__, mode);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfileMask) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config = {};
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+    config.lppProfileMask = GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE; //default
+
+    if (lppProfileMask & (1<<0)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_BIT;
+    }
+    if (lppProfileMask & (1<<1)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_BIT;
+    }
+    if (lppProfileMask & (1<<2)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_OVER_NR5G_SA_BIT;
+    }
+    if (lppProfileMask & (1<<3)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_OVER_NR5G_SA_BIT;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+
+    config.flags = GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+    if (protocol & (1<<0)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRC_CONTROL_PLANE_BIT;
+    }
+    if (protocol & (1<<1)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRLP_USER_PLANE_BIT;
+    }
+    if (protocol & (1<<2)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_USER_PLANE_BIT;
+    }
+    if (protocol & (1<<3)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_CONTROL_PLANE_BIT;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) {
+
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config = {};
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+    switch (lock) {
+    case 0:
+        config.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+        break;
+    case 1:
+        config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO;
+        break;
+    case 2:
+        config.gpsLock = GNSS_CONFIG_GPS_LOCK_NI;
+        break;
+    case 3:
+        config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
+        break;
+    default:
+        LOC_LOGE("%s]: invalid lock: %d.", __FUNCTION__, lock);
+        return false;
+    }
+
+    mGnss->updateConfiguration(config);
+    // Must return false to pass VTS
+    return false;
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+    config.emergencyPdnForEmergencySupl = (enabled ?
+            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES :
+            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO);
+
+    return mGnss->updateConfiguration(config);
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist(
+            const hidl_vec<GnssConfiguration::BlacklistedSource>& blacklist) {
+
+    ENTRY_LOG_CALLFLOW();
+    if (nullptr == mGnss) {
+        LOC_LOGe("mGnss is null");
+        return false;
+    }
+
+    // blValid is true if blacklist is empty, i.e. clearing the BL;
+    // if blacklist is not empty, blValid is initialied to false, and later
+    // updated in the for loop to become true only if there is at least
+    // one {constellation, svid} in the list that is valid.
+    bool blValid = (0 == blacklist.size());
+    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++) {
+        // Set blValid true if any one source is valid
+        blValid = setBlacklistedSource(source, blacklist[idx]) || blValid;
+        config.blacklistedSvIds.push_back(source);
+    }
+
+    // Update configuration only if blValid is true
+    // i.e. only if atleast one source is valid for blacklisting
+    return (blValid && mGnss->updateConfiguration(config));
+}
+
+bool GnssConfiguration::setBlacklistedSource(
+        GnssSvIdSource& copyToSource,
+        const GnssConfiguration::BlacklistedSource& copyFromSource) {
+
+    bool retVal = true;
+    uint16_t svIdOffset = 0;
+    copyToSource.size = sizeof(GnssSvIdSource);
+    copyToSource.svId = copyFromSource.svid;
+
+    switch(copyFromSource.constellation) {
+    case GnssConstellationType::GPS:
+        copyToSource.constellation = GNSS_SV_TYPE_GPS;
+        LOC_LOGe("GPS SVs can't be blacklisted.");
+        retVal = false;
+        break;
+    case GnssConstellationType::SBAS:
+        copyToSource.constellation = GNSS_SV_TYPE_SBAS;
+        LOC_LOGe("SBAS SVs can't be blacklisted.");
+        retVal = false;
+        break;
+    case GnssConstellationType::GLONASS:
+        copyToSource.constellation = GNSS_SV_TYPE_GLONASS;
+        svIdOffset = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::QZSS:
+        copyToSource.constellation = GNSS_SV_TYPE_QZSS;
+        svIdOffset = 0;
+        break;
+    case GnssConstellationType::BEIDOU:
+        copyToSource.constellation = GNSS_SV_TYPE_BEIDOU;
+        svIdOffset = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::GALILEO:
+        copyToSource.constellation = GNSS_SV_TYPE_GALILEO;
+        svIdOffset = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID - 1;
+        break;
+    default:
+        copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
+        LOC_LOGe("Invalid constellation %hhu", copyFromSource.constellation);
+        retVal = false;
+        break;
+    }
+
+    if (copyToSource.svId > 0 && svIdOffset > 0) {
+        copyToSource.svId += svIdOffset;
+    }
+
+    return retVal;
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnss == nullptr) {
+        LOC_LOGe("mGnss is nullptr");
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT;
+    config.emergencyExtensionSeconds = emergencyExtensionSeconds;
+
+    return mGnss->updateConfiguration(config);
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/GnssConfiguration.h b/gps/android/2.0/GnssConfiguration.h
new file mode 100644
index 0000000..c3de2c9
--- /dev/null
+++ b/gps/android/2.0/GnssConfiguration.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+
+ /* Copyright (C) 2016 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.
+ */
+
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSCONFIGURATION_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSCONFIGURATION_H
+
+#include <android/hardware/gnss/2.0/IGnssConfiguration.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/*
+ * Interface for passing GNSS configuration info from platform to HAL.
+ */
+struct Gnss;
+struct GnssConfiguration : public V2_0::IGnssConfiguration {
+    GnssConfiguration(Gnss* gnss);
+    ~GnssConfiguration() = default;
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+     * These declarations were generated from IGnssConfiguration.hal.
+     */
+    Return<bool> setSuplVersion(uint32_t version) override;
+    Return<bool> setSuplMode(uint8_t mode) override;
+    Return<bool> setSuplEs(bool enabled) override;
+    Return<bool> setLppProfile(uint8_t lppProfileMask) override;
+    Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override;
+    Return<bool> setEmergencySuplPdn(bool enable) override;
+    Return<bool> setGpsLock(uint8_t lock) override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+    Return<bool> setBlacklist(
+            const hidl_vec<GnssConfiguration::BlacklistedSource>& blacklist) override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+    Return<bool> setEsExtensionSec(uint32_t emergencyExtensionSeconds) override;
+
+ private:
+    Gnss* mGnss = nullptr;
+    bool setBlacklistedSource(
+            GnssSvIdSource& copyToSource,
+            const GnssConfiguration::BlacklistedSource& copyFromSource);
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSCONFIGURATION_H
diff --git a/gps/android/2.0/GnssDebug.cpp b/gps/android/2.0/GnssDebug.cpp
new file mode 100644
index 0000000..dc0d9f4
--- /dev/null
+++ b/gps/android/2.0/GnssDebug.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssDebugInterface"
+
+#include <log/log.h>
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssDebug.h"
+#include "LocationUtil.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::gnss::V2_0::IGnssDebug;
+
+#define GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS (20000000)
+#define GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS   (20000)
+#define GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC     (500)
+#define GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG       (180)
+
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME            (1483228800000LL) // 1/1/2017 00:00 GMT
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN    (999) // 999 ns
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX    (1.57783680E17) // 5 years in ns
+#define GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC (2.0e5)  // ppm
+
+GnssDebug::GnssDebug(Gnss* gnss) : mGnss(gnss)
+{
+}
+
+/*
+ * This methods requests position, time and satellite ephemeris debug information
+ * from the HAL.
+ *
+ * @return void
+*/
+Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    V1_0::IGnssDebug::DebugData data = { };
+
+    if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+        LOC_LOGE("GnssDebug - Null GNSS interface");
+        _hidl_cb(data);
+        return Void();
+    }
+
+    // get debug report snapshot via hal interface
+    GnssDebugReport reports = { };
+    mGnss->getGnssInterface()->getDebugReport(reports);
+
+    // location block
+    if (reports.mLocation.mValid) {
+        data.position.valid = true;
+        data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+        data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+        data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+        data.position.speedMetersPerSec =
+            (double)(reports.mLocation.mLocation.speed);
+        data.position.bearingDegrees =
+            (double)(reports.mLocation.mLocation.bearing);
+        data.position.horizontalAccuracyMeters =
+            (double)(reports.mLocation.mLocation.accuracy);
+        data.position.verticalAccuracyMeters =
+            reports.mLocation.verticalAccuracyMeters;
+        data.position.speedAccuracyMetersPerSecond =
+            reports.mLocation.speedAccuracyMetersPerSecond;
+        data.position.bearingAccuracyDegrees =
+            reports.mLocation.bearingAccuracyDegrees;
+
+        timeval tv_now, tv_report;
+        tv_report.tv_sec  = reports.mLocation.mUtcReported.tv_sec;
+        tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+        gettimeofday(&tv_now, NULL);
+        data.position.ageSeconds =
+            (tv_now.tv_sec - tv_report.tv_sec) +
+            (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+    }
+    else {
+        data.position.valid = false;
+    }
+
+    if (data.position.horizontalAccuracyMeters <= 0 ||
+        data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+        data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+    }
+    if (data.position.verticalAccuracyMeters <= 0 ||
+        data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+        data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+    }
+    if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+        data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+        data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+    }
+    if (data.position.bearingAccuracyDegrees <= 0 ||
+        data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+        data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+    }
+
+    // time block
+    if (reports.mTime.mValid) {
+        data.time.timeEstimate = reports.mTime.timeEstimate;
+        data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+        data.time.frequencyUncertaintyNsPerSec =
+            reports.mTime.frequencyUncertaintyNsPerSec;
+    }
+
+    if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+        data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+    }
+    if (data.time.timeUncertaintyNs <= 0) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
+    } else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
+    }
+    if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+        data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+        data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+    }
+
+    // satellite data block
+    V1_0::IGnssDebug::SatelliteData s = { };
+    std::vector<V1_0::IGnssDebug::SatelliteData> s_array;
+
+    for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+        memset(&s, 0, sizeof(s));
+        s.svid = reports.mSatelliteInfo[i].svid;
+        convertGnssConstellationType(
+            reports.mSatelliteInfo[i].constellation, s.constellation);
+        convertGnssEphemerisType(
+            reports.mSatelliteInfo[i].mEphemerisType, s.ephemerisType);
+        convertGnssEphemerisSource(
+            reports.mSatelliteInfo[i].mEphemerisSource, s.ephemerisSource);
+        convertGnssEphemerisHealth(
+            reports.mSatelliteInfo[i].mEphemerisHealth, s.ephemerisHealth);
+
+        s.ephemerisAgeSeconds =
+            reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+        s.serverPredictionIsAvailable =
+            reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+        s.serverPredictionAgeSeconds =
+            reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+        s_array.push_back(s);
+    }
+    data.satelliteDataArray = s_array;
+
+    // callback HIDL with collected debug data
+    _hidl_cb(data);
+    return Void();
+}
+
+Return<void> GnssDebug::getDebugData_2_0(getDebugData_2_0_cb _hidl_cb)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    V2_0::IGnssDebug::DebugData data = { };
+
+    if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+        LOC_LOGE("GnssDebug - Null GNSS interface");
+        _hidl_cb(data);
+        return Void();
+    }
+
+    // get debug report snapshot via hal interface
+    GnssDebugReport reports = { };
+    mGnss->getGnssInterface()->getDebugReport(reports);
+
+    // location block
+    if (reports.mLocation.mValid) {
+        data.position.valid = true;
+        data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+        data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+        data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+        data.position.speedMetersPerSec =
+            (double)(reports.mLocation.mLocation.speed);
+        data.position.bearingDegrees =
+            (double)(reports.mLocation.mLocation.bearing);
+        data.position.horizontalAccuracyMeters =
+            (double)(reports.mLocation.mLocation.accuracy);
+        data.position.verticalAccuracyMeters =
+            reports.mLocation.verticalAccuracyMeters;
+        data.position.speedAccuracyMetersPerSecond =
+            reports.mLocation.speedAccuracyMetersPerSecond;
+        data.position.bearingAccuracyDegrees =
+            reports.mLocation.bearingAccuracyDegrees;
+
+        timeval tv_now, tv_report;
+        tv_report.tv_sec  = reports.mLocation.mUtcReported.tv_sec;
+        tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+        gettimeofday(&tv_now, NULL);
+        data.position.ageSeconds =
+            (tv_now.tv_sec - tv_report.tv_sec) +
+            (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+    }
+    else {
+        data.position.valid = false;
+    }
+
+    if (data.position.horizontalAccuracyMeters <= 0 ||
+        data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+        data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+    }
+    if (data.position.verticalAccuracyMeters <= 0 ||
+        data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+        data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+    }
+    if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+        data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+        data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+    }
+    if (data.position.bearingAccuracyDegrees <= 0 ||
+        data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+        data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+    }
+
+    // time block
+    if (reports.mTime.mValid) {
+        data.time.timeEstimate = reports.mTime.timeEstimate;
+        data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+        data.time.frequencyUncertaintyNsPerSec =
+            reports.mTime.frequencyUncertaintyNsPerSec;
+    }
+
+    if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+        data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+    }
+    if (data.time.timeUncertaintyNs <= 0) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
+    }
+    else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
+    }
+    if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+        data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+        data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+    }
+
+    // satellite data block
+    V2_0::IGnssDebug::SatelliteData s = { };
+    std::vector<V2_0::IGnssDebug::SatelliteData> s_array;
+
+    for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+        memset(&s, 0, sizeof(s));
+        s.v1_0.svid = reports.mSatelliteInfo[i].svid;
+        convertGnssConstellationType(
+            reports.mSatelliteInfo[i].constellation, s.constellation);
+        convertGnssEphemerisType(
+            reports.mSatelliteInfo[i].mEphemerisType, s.v1_0.ephemerisType);
+        convertGnssEphemerisSource(
+            reports.mSatelliteInfo[i].mEphemerisSource, s.v1_0.ephemerisSource);
+        convertGnssEphemerisHealth(
+            reports.mSatelliteInfo[i].mEphemerisHealth, s.v1_0.ephemerisHealth);
+
+        s.v1_0.ephemerisAgeSeconds =
+            reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+        s.v1_0.serverPredictionIsAvailable =
+            reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+        s.v1_0.serverPredictionAgeSeconds =
+            reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+        s_array.push_back(s);
+    }
+    data.satelliteDataArray = s_array;
+
+    // callback HIDL with collected debug data
+    _hidl_cb(data);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/GnssDebug.h b/gps/android/2.0/GnssDebug.h
new file mode 100644
index 0000000..8d75bea
--- /dev/null
+++ b/gps/android/2.0/GnssDebug.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
+
+
+#include <android/hardware/gnss/2.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnssDebug;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/* Interface for GNSS Debug support. */
+struct Gnss;
+struct GnssDebug : public IGnssDebug {
+    GnssDebug(Gnss* gnss);
+    ~GnssDebug() {};
+
+    //  Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow
+    Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
+    //  Methods from ::android::hardware::gnss::V2_0::IGnssDebug follow.
+    Return<void> getDebugData_2_0(getDebugData_2_0_cb _hidl_cb) override;
+
+private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
diff --git a/gps/android/2.0/GnssGeofencing.cpp b/gps/android/2.0/GnssGeofencing.cpp
new file mode 100644
index 0000000..b6fc94b
--- /dev/null
+++ b/gps/android/2.0/GnssGeofencing.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "GnssHal_GnssGeofencing"
+
+#include <log_util.h>
+#include <GeofenceAPIClient.h>
+#include "GnssGeofencing.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void GnssGeofencing::GnssGeofencingDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssGeofencing != nullptr) {
+        mGnssGeofencing->removeAllGeofences();
+    }
+}
+
+GnssGeofencing::GnssGeofencing() : mApi(nullptr) {
+    mGnssGeofencingDeathRecipient = new GnssGeofencingDeathRecipient(this);
+}
+
+GnssGeofencing::~GnssGeofencing() {
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback)  {
+    if (mApi != nullptr) {
+        LOC_LOGd("mApi is NOT nullptr");
+        return Void();
+    }
+
+    mApi = new GeofenceAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+    }
+
+    if (mGnssGeofencingCbIface != nullptr) {
+        mGnssGeofencingCbIface->unlinkToDeath(mGnssGeofencingDeathRecipient);
+    }
+    mGnssGeofencingCbIface = callback;
+    if (mGnssGeofencingCbIface != nullptr) {
+        mGnssGeofencingCbIface->linkToDeath(mGnssGeofencingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return Void();
+}
+
+Return<void> GnssGeofencing::addGeofence(
+        int32_t geofenceId,
+        double latitudeDegrees,
+        double longitudeDegrees,
+        double radiusMeters,
+        IGnssGeofenceCallback::GeofenceTransition lastTransition,
+        int32_t monitorTransitions,
+        uint32_t notificationResponsivenessMs,
+        uint32_t unknownTimerMs)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceAdd(
+                geofenceId,
+                latitudeDegrees,
+                longitudeDegrees,
+                radiusMeters,
+                static_cast<int32_t>(lastTransition),
+                monitorTransitions,
+                notificationResponsivenessMs,
+                unknownTimerMs);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofencePause(geofenceId);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceResume(geofenceId, monitorTransitions);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceRemove(geofenceId);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::removeAllGeofences()  {
+    if (mApi == nullptr) {
+        LOC_LOGD("%s]: mApi is nullptr, do nothing", __FUNCTION__);
+    } else {
+        mApi->geofenceRemoveAll();
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/GnssGeofencing.h b/gps/android/2.0/GnssGeofencing.h
new file mode 100644
index 0000000..caa56d0
--- /dev/null
+++ b/gps/android/2.0/GnssGeofencing.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
+
+#include <android/hardware/gnss/1.0/IGnssGeofencing.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::IGnssGeofencing;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class GeofenceAPIClient;
+struct GnssGeofencing : public IGnssGeofencing {
+    GnssGeofencing();
+    ~GnssGeofencing();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+     * These declarations were generated from IGnssGeofencing.hal.
+     */
+    Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback)  override;
+    Return<void> addGeofence(int32_t geofenceId,
+                             double latitudeDegrees,
+                             double longitudeDegrees,
+                             double radiusMeters,
+                             IGnssGeofenceCallback::GeofenceTransition lastTransition,
+                             int32_t monitorTransitions,
+                             uint32_t notificationResponsivenessMs,
+                             uint32_t unknownTimerMs)  override;
+
+    Return<void> pauseGeofence(int32_t geofenceId)  override;
+    Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  override;
+    Return<void> removeGeofence(int32_t geofenceId)  override;
+
+ private:
+    // This method is not part of the IGnss base class.
+    // It is called by GnssGeofencingDeathRecipient to remove all geofences added so far.
+    Return<void> removeAllGeofences();
+
+ private:
+    struct GnssGeofencingDeathRecipient : hidl_death_recipient {
+        GnssGeofencingDeathRecipient(sp<GnssGeofencing> gnssGeofencing) :
+            mGnssGeofencing(gnssGeofencing) {
+        }
+        ~GnssGeofencingDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssGeofencing> mGnssGeofencing;
+    };
+
+ private:
+    sp<GnssGeofencingDeathRecipient> mGnssGeofencingDeathRecipient = nullptr;
+    sp<IGnssGeofenceCallback> mGnssGeofencingCbIface = nullptr;
+    GeofenceAPIClient* mApi = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
diff --git a/gps/android/2.0/GnssMeasurement.cpp b/gps/android/2.0/GnssMeasurement.cpp
new file mode 100644
index 0000000..6cb55ca
--- /dev/null
+++ b/gps/android/2.0/GnssMeasurement.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssMeasurementInterface"
+
+#include <log_util.h>
+#include "GnssMeasurement.h"
+#include "MeasurementAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void GnssMeasurement::GnssMeasurementDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssMeasurement != nullptr) {
+        mGnssMeasurement->close();
+    }
+}
+
+GnssMeasurement::GnssMeasurement() {
+    mGnssMeasurementDeathRecipient = new GnssMeasurementDeathRecipient(this);
+    mApi = new MeasurementAPIClient();
+}
+
+GnssMeasurement::~GnssMeasurement() {
+    if (mApi) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+        const sp<V1_0::IGnssMeasurementCallback>& callback)  {
+
+    Return<GnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    clearInterfaces();
+
+    mGnssMeasurementCbIface = callback;
+    mGnssMeasurementCbIface->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    return mApi->measurementSetCallback(callback);
+}
+
+void GnssMeasurement::clearInterfaces() {
+    if (mGnssMeasurementCbIface != nullptr) {
+        mGnssMeasurementCbIface->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface = nullptr;
+    }
+    if (mGnssMeasurementCbIface_1_1 != nullptr) {
+        mGnssMeasurementCbIface_1_1->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface_1_1 = nullptr;
+    }
+    if (mGnssMeasurementCbIface_2_0 != nullptr) {
+        mGnssMeasurementCbIface_2_0->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface_2_0 = nullptr;
+    }
+}
+
+Return<void> GnssMeasurement::close()  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    clearInterfaces();
+    mApi->measurementClose();
+
+    return Void();
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_1_1(
+        const sp<V1_1::IGnssMeasurementCallback>& callback, bool enableFullTracking) {
+
+    Return<GnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface_1_1 != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (nullptr == mApi) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    clearInterfaces();
+
+    mGnssMeasurementCbIface_1_1 = callback;
+    mGnssMeasurementCbIface_1_1->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    GnssPowerMode powerMode = enableFullTracking?
+            GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;
+
+    return mApi->measurementSetCallback_1_1(callback, powerMode);
+}
+// Methods from ::android::hardware::gnss::V2_0::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
+        const sp<V2_0::IGnssMeasurementCallback>& callback,
+        bool enableFullTracking) {
+
+    Return<GnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface_2_0 != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (nullptr == mApi) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    clearInterfaces();
+
+    mGnssMeasurementCbIface_2_0 = callback;
+    mGnssMeasurementCbIface_2_0->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    GnssPowerMode powerMode = enableFullTracking ?
+        GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;
+
+    return mApi->measurementSetCallback_2_0(callback, powerMode);
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/GnssMeasurement.h b/gps/android/2.0/GnssMeasurement.h
new file mode 100644
index 0000000..7fa66b4
--- /dev/null
+++ b/gps/android/2.0/GnssMeasurement.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSMEASUREMENT_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSMEASUREMENT_H
+
+#include <android/hardware/gnss/2.0/IGnssMeasurement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class MeasurementAPIClient;
+struct GnssMeasurement : public V2_0::IGnssMeasurement {
+    GnssMeasurement();
+    ~GnssMeasurement();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+     * These declarations were generated from IGnssMeasurement.hal.
+     */
+    Return<GnssMeasurement::GnssMeasurementStatus> setCallback(
+        const sp<V1_0::IGnssMeasurementCallback>& callback) override;
+    Return<void> close() override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+    Return<GnssMeasurement::GnssMeasurementStatus> setCallback_1_1(
+            const sp<V1_1::IGnssMeasurementCallback>& callback,
+            bool enableFullTracking) override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IGnssMeasurement follow.
+    Return<GnssMeasurement::GnssMeasurementStatus> setCallback_2_0(
+            const sp<V2_0::IGnssMeasurementCallback>& callback,
+            bool enableFullTracking) override;
+ private:
+    struct GnssMeasurementDeathRecipient : hidl_death_recipient {
+        GnssMeasurementDeathRecipient(sp<GnssMeasurement> gnssMeasurement) :
+            mGnssMeasurement(gnssMeasurement) {
+        }
+        ~GnssMeasurementDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssMeasurement> mGnssMeasurement;
+    };
+
+ private:
+    sp<GnssMeasurementDeathRecipient> mGnssMeasurementDeathRecipient = nullptr;
+    sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface = nullptr;
+    sp<V1_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1 = nullptr;
+    sp<V2_0::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_0 = nullptr;
+    MeasurementAPIClient* mApi;
+    void clearInterfaces();
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSMEASUREMENT_H
diff --git a/gps/android/2.0/GnssNi.cpp b/gps/android/2.0/GnssNi.cpp
new file mode 100644
index 0000000..d65a488
--- /dev/null
+++ b/gps/android/2.0/GnssNi.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssNiInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssNi.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void GnssNi::GnssNiDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    // we do nothing here
+    // Gnss::GnssDeathRecipient will stop the session
+}
+
+GnssNi::GnssNi(Gnss* gnss) : mGnss(gnss) {
+    mGnssNiDeathRecipient = new GnssNiDeathRecipient(this);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    mGnss->setGnssNiCb(callback);
+
+    if (mGnssNiCbIface != nullptr) {
+        mGnssNiCbIface->unlinkToDeath(mGnssNiDeathRecipient);
+    }
+    mGnssNiCbIface = callback;
+    if (mGnssNiCbIface != nullptr) {
+        mGnssNiCbIface->linkToDeath(mGnssNiDeathRecipient, 0 /*cookie*/);
+    }
+
+    return Void();
+}
+
+Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    GnssAPIClient* api = mGnss->getApi();
+    if (api == nullptr) {
+        LOC_LOGE("%s]: api is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    api->gnssNiRespond(notifId, userResponse);
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/GnssNi.h b/gps/android/2.0/GnssNi.h
new file mode 100644
index 0000000..26e281f
--- /dev/null
+++ b/gps/android/2.0/GnssNi.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
+
+#include <android/hardware/gnss/1.0/IGnssNi.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssNi;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct GnssNi : public IGnssNi {
+    GnssNi(Gnss* gnss);
+    ~GnssNi() = default;
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+     * These declarations were generated from IGnssNi.hal.
+     */
+    Return<void> setCallback(const sp<IGnssNiCallback>& callback) override;
+    Return<void> respond(int32_t notifId,
+                         IGnssNiCallback::GnssUserResponseType userResponse) override;
+
+ private:
+    struct GnssNiDeathRecipient : hidl_death_recipient {
+        GnssNiDeathRecipient(sp<GnssNi> gnssNi) : mGnssNi(gnssNi) {
+        }
+        ~GnssNiDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssNi> mGnssNi;
+    };
+
+ private:
+    sp<GnssNiDeathRecipient> mGnssNiDeathRecipient = nullptr;
+    sp<IGnssNiCallback> mGnssNiCbIface = nullptr;
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
diff --git a/gps/android/2.0/GnssVisibilityControl.cpp b/gps/android/2.0/GnssVisibilityControl.cpp
new file mode 100644
index 0000000..5a8c697
--- /dev/null
+++ b/gps/android/2.0/GnssVisibilityControl.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include "GnssVisibilityControl.h"
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace visibility_control {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+static GnssVisibilityControl* spGnssVisibilityControl = nullptr;
+
+static void convertGnssNfwNotification(GnssNfwNotification& in,
+    IGnssVisibilityControlCallback::NfwNotification& out);
+
+GnssVisibilityControl::GnssVisibilityControl(Gnss* gnss) : mGnss(gnss) {
+    spGnssVisibilityControl = this;
+}
+GnssVisibilityControl::~GnssVisibilityControl() {
+    spGnssVisibilityControl = nullptr;
+}
+
+void GnssVisibilityControl::nfwStatusCb(GnssNfwNotification notification) {
+    if (nullptr != spGnssVisibilityControl) {
+        spGnssVisibilityControl->statusCb(notification);
+    }
+}
+
+bool GnssVisibilityControl::isInEmergencySession() {
+    if (nullptr != spGnssVisibilityControl) {
+        return spGnssVisibilityControl->isE911Session();
+    }
+    return false;
+}
+
+static void convertGnssNfwNotification(GnssNfwNotification& in,
+    IGnssVisibilityControlCallback::NfwNotification& out)
+{
+    memset(&out, 0, sizeof(IGnssVisibilityControlCallback::NfwNotification));
+    out.proxyAppPackageName = in.proxyAppPackageName;
+    out.protocolStack = (IGnssVisibilityControlCallback::NfwProtocolStack)in.protocolStack;
+    out.otherProtocolStackName = in.otherProtocolStackName;
+    out.requestor = (IGnssVisibilityControlCallback::NfwRequestor)in.requestor;
+    out.requestorId = in.requestorId;
+    out.responseType = (IGnssVisibilityControlCallback::NfwResponseType)in.responseType;
+    out.inEmergencyMode = in.inEmergencyMode;
+    out.isCachedLocation = in.isCachedLocation;
+}
+
+void GnssVisibilityControl::statusCb(GnssNfwNotification notification) {
+
+    if (mGnssVisibilityControlCbIface != nullptr) {
+        IGnssVisibilityControlCallback::NfwNotification nfwNotification;
+
+        // Convert from one structure to another
+        convertGnssNfwNotification(notification, nfwNotification);
+
+        auto r = mGnssVisibilityControlCbIface->nfwNotifyCb(nfwNotification);
+        if (!r.isOk()) {
+            LOC_LOGw("Error invoking NFW status cb %s", r.description().c_str());
+        }
+    } else {
+        LOC_LOGw("setCallback has not been called yet");
+    }
+}
+
+bool GnssVisibilityControl::isE911Session() {
+
+    if (mGnssVisibilityControlCbIface != nullptr) {
+        auto r = mGnssVisibilityControlCbIface->isInEmergencySession();
+        if (!r.isOk()) {
+            LOC_LOGw("Error invoking NFW status cb %s", r.description().c_str());
+            return false;
+        } else {
+            return (r);
+        }
+    } else {
+        LOC_LOGw("setCallback has not been called yet");
+        return false;
+    }
+}
+
+// Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl follow.
+Return<bool> GnssVisibilityControl::enableNfwLocationAccess(const hidl_vec<::android::hardware::hidl_string>& proxyApps) {
+
+    if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
+        LOC_LOGe("Null GNSS interface");
+        return false;
+    }
+
+    /* If the vector is empty we need to disable all NFW clients
+       If there is at least one app in the vector we need to enable
+       all NFW clients */
+    if (0 == proxyApps.size()) {
+        mGnss->getGnssInterface()->enableNfwLocationAccess(false);
+    } else {
+        mGnss->getGnssInterface()->enableNfwLocationAccess(true);
+    }
+
+    return true;
+}
+/**
+ * Registers the callback for HAL implementation to use.
+ *
+ * @param callback Handle to IGnssVisibilityControlCallback interface.
+ */
+Return<bool> GnssVisibilityControl::setCallback(const ::android::sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback>& callback) {
+
+    if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
+        LOC_LOGe("Null GNSS interface");
+        return false;
+    }
+    mGnssVisibilityControlCbIface = callback;
+
+    NfwCbInfo cbInfo = {};
+    cbInfo.visibilityControlCb = (void*)nfwStatusCb;
+    cbInfo.isInEmergencySession = (void*)isInEmergencySession;
+
+    mGnss->getGnssInterface()->nfwInit(cbInfo);
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace visibility_control
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/GnssVisibilityControl.h b/gps/android/2.0/GnssVisibilityControl.h
new file mode 100644
index 0000000..9c26e38
--- /dev/null
+++ b/gps/android/2.0/GnssVisibilityControl.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
+
+#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <gps_extended_c.h>
+#include <location_interface.h>
+#include "Gnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace visibility_control {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V2_0::implementation::Gnss;
+
+struct GnssVisibilityControl : public IGnssVisibilityControl {
+    GnssVisibilityControl(Gnss* gnss);
+    ~GnssVisibilityControl();
+
+    // Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl follow.
+    Return<bool> enableNfwLocationAccess(const hidl_vec<::android::hardware::hidl_string>& proxyApps) override;
+    /**
+     * Registers the callback for HAL implementation to use.
+     *
+     * @param callback Handle to IGnssVisibilityControlCallback interface.
+     */
+    Return<bool> setCallback(const ::android::sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback>& callback) override;
+
+    void statusCb(GnssNfwNotification notification);
+    bool isE911Session();
+
+    /* Data call setup callback passed down to GNSS HAL implementation */
+    static void nfwStatusCb(GnssNfwNotification notification);
+    static bool isInEmergencySession();
+
+private:
+    Gnss* mGnss = nullptr;
+    sp<IGnssVisibilityControlCallback> mGnssVisibilityControlCbIface = nullptr;
+};
+
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace visibility_control
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
diff --git a/gps/android/2.0/MeasurementCorrections.cpp b/gps/android/2.0/MeasurementCorrections.cpp
new file mode 100644
index 0000000..bb75073
--- /dev/null
+++ b/gps/android/2.0/MeasurementCorrections.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "LocSvc_MeasurementCorrectionsInterface"
+
+#include <log_util.h>
+#include "MeasurementCorrections.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+MeasurementCorrections::MeasurementCorrections() {
+}
+
+MeasurementCorrections::~MeasurementCorrections() {
+}
+
+Return<bool> MeasurementCorrections::setCorrections(
+        const ::android::hardware::gnss::measurement_corrections::
+                V1_0::MeasurementCorrections& /*corrections*/) {
+    return true;
+}
+
+Return<bool> MeasurementCorrections::setCallback(
+        const sp<V1_0::IMeasurementCorrectionsCallback>& /*callback*/) {
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace measurement_corrections
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/MeasurementCorrections.h b/gps/android/2.0/MeasurementCorrections.h
new file mode 100644
index 0000000..96b1120
--- /dev/null
+++ b/gps/android/2.0/MeasurementCorrections.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_MeasurementCorrections_H
+#define ANDROID_HARDWARE_GNSS_V1_0_MeasurementCorrections_H
+
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+
+struct MeasurementCorrections : public IMeasurementCorrections {
+    MeasurementCorrections();
+    ~MeasurementCorrections();
+
+// Methods from ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections follow.
+Return<bool> setCorrections(
+        const ::android::hardware::gnss::measurement_corrections::
+                V1_0::MeasurementCorrections& corrections) override;
+
+Return<bool> setCallback(const sp<IMeasurementCorrectionsCallback>& callback) override;
+};
+
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace measurement_corrections
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_MeasurementCorrections_H
diff --git a/gps/android/2.0/android.hardware.gnss@2.0-service-qti.rc b/gps/android/2.0/android.hardware.gnss@2.0-service-qti.rc
new file mode 100644
index 0000000..ad46d5d
--- /dev/null
+++ b/gps/android/2.0/android.hardware.gnss@2.0-service-qti.rc
@@ -0,0 +1,4 @@
+service gnss_service /vendor/bin/hw/android.hardware.gnss@2.0-service-qti
+    class hal
+    user gps
+    group system gps radio vendor_qti_diag
diff --git a/gps/android/2.0/android.hardware.gnss@2.0-service-qti.xml b/gps/android/2.0/android.hardware.gnss@2.0-service-qti.xml
new file mode 100644
index 0000000..ff9fb2c
--- /dev/null
+++ b/gps/android/2.0/android.hardware.gnss@2.0-service-qti.xml
@@ -0,0 +1,36 @@
+<!-- Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.gnss</name>
+        <transport>hwbinder</transport>
+        <fqname>@1.1::IGnss/default</fqname>
+        <fqname>@2.0::IGnss/default</fqname>
+    </hal>
+</manifest>
+
diff --git a/gps/android/2.0/location_api/BatchingAPIClient.cpp b/gps/android/2.0/location_api/BatchingAPIClient.cpp
new file mode 100644
index 0000000..766c37a
--- /dev/null
+++ b/gps/android/2.0/location_api/BatchingAPIClient.cpp
@@ -0,0 +1,251 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_BatchingAPIClient"
+
+#include <inttypes.h>
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "BatchingAPIClient.h"
+
+#include "limits.h"
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnssBatching;
+using ::android::hardware::gnss::V2_0::IGnssBatchingCallback;
+using ::android::hardware::gnss::V2_0::GnssLocation;
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+        LocationCapabilitiesMask mask);
+
+BatchingAPIClient::BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssBatchingCbIface(nullptr),
+    mDefaultId(UINT_MAX),
+    mLocationCapabilitiesMask(0),
+    mGnssBatchingCbIface_2_0(nullptr)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    gnssUpdateCallbacks(callback);
+}
+
+BatchingAPIClient::BatchingAPIClient(const sp<V2_0::IGnssBatchingCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssBatchingCbIface(nullptr),
+    mDefaultId(UINT_MAX),
+    mLocationCapabilitiesMask(0),
+    mGnssBatchingCbIface_2_0(nullptr)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    gnssUpdateCallbacks_2_0(callback);
+}
+
+BatchingAPIClient::~BatchingAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+int BatchingAPIClient::getBatchSize()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    return locAPIGetBatchSize();
+}
+
+void BatchingAPIClient::setCallbacks()
+{
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.batchingCb = [this](size_t count, Location* location,
+        BatchingOptions batchOptions) {
+        onBatchingCb(count, location, batchOptions);
+    };
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+void BatchingAPIClient::gnssUpdateCallbacks(const sp<V1_0::IGnssBatchingCallback>& callback)
+{
+    mMutex.lock();
+    mGnssBatchingCbIface = callback;
+    mMutex.unlock();
+
+    if (mGnssBatchingCbIface != nullptr) {
+        setCallbacks();
+    }
+}
+
+void BatchingAPIClient::gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssBatchingCallback>& callback)
+{
+    mMutex.lock();
+    mGnssBatchingCbIface_2_0 = callback;
+    mMutex.unlock();
+
+    if (mGnssBatchingCbIface_2_0 != nullptr) {
+        setCallbacks();
+    }
+}
+
+int BatchingAPIClient::startSession(const IGnssBatching::Options& opts)
+{
+    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+    int retVal = -1;
+    LocationOptions options;
+    convertBatchOption(opts, options, mLocationCapabilitiesMask);
+    uint32_t mode = 0;
+    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+        mode = SESSION_MODE_ON_FULL;
+    }
+    if (locAPIStartSession(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+int BatchingAPIClient::updateSessionOptions(const IGnssBatching::Options& opts)
+{
+    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+    int retVal = -1;
+    LocationOptions options;
+    convertBatchOption(opts, options, mLocationCapabilitiesMask);
+
+    uint32_t mode = 0;
+    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+        mode = SESSION_MODE_ON_FULL;
+    }
+    if (locAPIUpdateSessionOptions(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+int BatchingAPIClient::stopSession()
+{
+    LOC_LOGD("%s]: ", __FUNCTION__);
+    int retVal = -1;
+    if (locAPIStopSession(mDefaultId) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+void BatchingAPIClient::getBatchedLocation(int last_n_locations)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, last_n_locations);
+    locAPIGetBatchedLocations(mDefaultId, last_n_locations);
+}
+
+void BatchingAPIClient::flushBatchedLocations()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
+}
+
+void BatchingAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+    LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
+    mLocationCapabilitiesMask = capabilitiesMask;
+}
+
+void BatchingAPIClient::onBatchingCb(size_t count, Location* location,
+        BatchingOptions /*batchOptions*/)
+{
+    mMutex.lock();
+    auto gnssBatchingCbIface(mGnssBatchingCbIface);
+    auto gnssBatchingCbIface_2_0(mGnssBatchingCbIface_2_0);
+    mMutex.unlock();
+
+    LOC_LOGD("%s]: (count: %zu)", __FUNCTION__, count);
+    if (gnssBatchingCbIface_2_0 != nullptr && count > 0) {
+        hidl_vec<V2_0::GnssLocation> locationVec;
+        locationVec.resize(count);
+        for (size_t i = 0; i < count; i++) {
+            convertGnssLocation(location[i], locationVec[i]);
+        }
+        auto r = gnssBatchingCbIface_2_0->gnssLocationBatchCb(locationVec);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationBatchCb 2.0 description=%s",
+                __func__, r.description().c_str());
+        }
+    } else if (gnssBatchingCbIface != nullptr && count > 0) {
+        hidl_vec<V1_0::GnssLocation> locationVec;
+        locationVec.resize(count);
+        for (size_t i = 0; i < count; i++) {
+            convertGnssLocation(location[i], locationVec[i]);
+        }
+        auto r = gnssBatchingCbIface->gnssLocationBatchCb(locationVec);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationBatchCb 1.0 description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+        LocationCapabilitiesMask mask)
+{
+    memset(&out, 0, sizeof(LocationOptions));
+    out.size = sizeof(LocationOptions);
+    out.minInterval = (uint32_t)(in.periodNanos / 1000000L);
+    out.minDistance = 0;
+    out.mode = GNSS_SUPL_MODE_STANDALONE;
+    if (mask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+        out.mode = GNSS_SUPL_MODE_MSA;
+    if (mask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+        out.mode = GNSS_SUPL_MODE_MSB;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/location_api/BatchingAPIClient.h b/gps/android/2.0/location_api/BatchingAPIClient.h
new file mode 100644
index 0000000..d2d9b4a
--- /dev/null
+++ b/gps/android/2.0/location_api/BatchingAPIClient.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef BATCHING_API_CLINET_H
+#define BATCHING_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/2.0/IGnssBatching.h>
+#include <android/hardware/gnss/2.0/IGnssBatchingCallback.h>
+#include <pthread.h>
+
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+class BatchingAPIClient : public LocationAPIClientBase
+{
+public:
+    BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback);
+    BatchingAPIClient(const sp<V2_0::IGnssBatchingCallback>& callback);
+    void gnssUpdateCallbacks(const sp<V1_0::IGnssBatchingCallback>& callback);
+    void gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssBatchingCallback>& callback);
+    int getBatchSize();
+    int startSession(const V1_0::IGnssBatching::Options& options);
+    int updateSessionOptions(const V1_0::IGnssBatching::Options& options);
+    int stopSession();
+    void getBatchedLocation(int last_n_locations);
+    void flushBatchedLocations();
+
+    inline LocationCapabilitiesMask getCapabilities() { return mLocationCapabilitiesMask; }
+
+    // callbacks
+    void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+    void onBatchingCb(size_t count, Location* location, BatchingOptions batchOptions) final;
+
+private:
+    void setCallbacks();
+    ~BatchingAPIClient();
+
+    std::mutex mMutex;
+    sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface;
+    uint32_t mDefaultId;
+    LocationCapabilitiesMask mLocationCapabilitiesMask;
+    sp<V2_0::IGnssBatchingCallback> mGnssBatchingCbIface_2_0;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // BATCHING_API_CLINET_H
diff --git a/gps/android/2.0/location_api/GeofenceAPIClient.cpp b/gps/android/2.0/location_api/GeofenceAPIClient.cpp
new file mode 100644
index 0000000..a93c988
--- /dev/null
+++ b/gps/android/2.0/location_api/GeofenceAPIClient.cpp
@@ -0,0 +1,275 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_GeofenceApiClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GeofenceAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+GeofenceAPIClient::GeofenceAPIClient(const sp<IGnssGeofenceCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssGeofencingCbIface(callback)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+
+    locationCallbacks.geofenceBreachCb = nullptr;
+    if (mGnssGeofencingCbIface != nullptr) {
+        locationCallbacks.geofenceBreachCb =
+            [this](GeofenceBreachNotification geofenceBreachNotification) {
+                onGeofenceBreachCb(geofenceBreachNotification);
+            };
+
+        locationCallbacks.geofenceStatusCb =
+            [this](GeofenceStatusNotification geofenceStatusNotification) {
+                onGeofenceStatusCb(geofenceStatusNotification);
+            };
+    }
+
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+void GeofenceAPIClient::geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+        double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+        uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms)
+{
+    LOC_LOGD("%s]: (%d %f %f %f %d %d %d %d)", __FUNCTION__,
+            geofence_id, latitude, longitude, radius_meters,
+            last_transition, monitor_transitions, notification_responsiveness_ms, unknown_timer_ms);
+
+    GeofenceOption options;
+    memset(&options, 0, sizeof(GeofenceOption));
+    options.size = sizeof(GeofenceOption);
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+        options.breachTypeMask |= GEOFENCE_BREACH_ENTER_BIT;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+        options.breachTypeMask |=  GEOFENCE_BREACH_EXIT_BIT;
+    options.responsiveness = notification_responsiveness_ms;
+
+    GeofenceInfo data;
+    data.size = sizeof(GeofenceInfo);
+    data.latitude = latitude;
+    data.longitude = longitude;
+    data.radius = radius_meters;
+
+    LocationError err = (LocationError)locAPIAddGeofences(1, &geofence_id, &options, &data);
+    if (LOCATION_ERROR_SUCCESS != err) {
+        onAddGeofencesCb(1, &err, &geofence_id);
+    }
+}
+
+void GeofenceAPIClient::geofencePause(uint32_t geofence_id)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+    locAPIPauseGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceResume(uint32_t geofence_id, int32_t monitor_transitions)
+{
+    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, geofence_id, monitor_transitions);
+    GeofenceBreachTypeMask mask = 0;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+        mask |= GEOFENCE_BREACH_ENTER_BIT;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+        mask |=  GEOFENCE_BREACH_EXIT_BIT;
+    locAPIResumeGeofences(1, &geofence_id, &mask);
+}
+
+void GeofenceAPIClient::geofenceRemove(uint32_t geofence_id)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+    locAPIRemoveGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceRemoveAll()
+{
+    LOC_LOGD("%s]", __FUNCTION__);
+    // TODO locAPIRemoveAllGeofences();
+}
+
+// callbacks
+void GeofenceAPIClient::onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceBreachNotification.count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < geofenceBreachNotification.count; i++) {
+            GnssLocation gnssLocation;
+            convertGnssLocation(geofenceBreachNotification.location, gnssLocation);
+
+            IGnssGeofenceCallback::GeofenceTransition transition;
+            if (geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER)
+                transition = IGnssGeofenceCallback::GeofenceTransition::ENTERED;
+            else if (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT)
+                transition = IGnssGeofenceCallback::GeofenceTransition::EXITED;
+            else {
+                // continue with other breach if transition is
+                // nether GPS_GEOFENCE_ENTERED nor GPS_GEOFENCE_EXITED
+                continue;
+            }
+
+            auto r = mGnssGeofencingCbIface->gnssGeofenceTransitionCb(
+                    geofenceBreachNotification.ids[i], gnssLocation, transition,
+                    static_cast<V1_0::GnssUtcTime>(geofenceBreachNotification.timestamp));
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceTransitionCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceStatusNotification.available);
+    if (mGnssGeofencingCbIface != nullptr) {
+        IGnssGeofenceCallback::GeofenceAvailability status =
+            IGnssGeofenceCallback::GeofenceAvailability::UNAVAILABLE;
+        if (geofenceStatusNotification.available == GEOFENCE_STATUS_AVAILABILE_YES) {
+            status = IGnssGeofenceCallback::GeofenceAvailability::AVAILABLE;
+        }
+        GnssLocation gnssLocation;
+        memset(&gnssLocation, 0, sizeof(GnssLocation));
+        auto r = mGnssGeofencingCbIface->gnssGeofenceStatusCb(status, gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssGeofenceStatusCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GeofenceAPIClient::onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_EXISTS)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_EXISTS;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceAddCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceAddCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceRemoveCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceRemoveCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofencePauseCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofencePauseCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceResumeCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceResumeCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/location_api/GeofenceAPIClient.h b/gps/android/2.0/location_api/GeofenceAPIClient.h
new file mode 100644
index 0000000..5bce476
--- /dev/null
+++ b/gps/android/2.0/location_api/GeofenceAPIClient.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GEOFENCE_API_CLINET_H
+#define GEOFENCE_API_CLINET_H
+
+
+#include <android/hardware/gnss/1.0/IGnssGeofenceCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class GeofenceAPIClient : public LocationAPIClientBase
+{
+public:
+    GeofenceAPIClient(const sp<V1_0::IGnssGeofenceCallback>& callback);
+
+    void geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+            double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+            uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms);
+    void geofencePause(uint32_t geofence_id);
+    void geofenceResume(uint32_t geofence_id, int32_t monitor_transitions);
+    void geofenceRemove(uint32_t geofence_id);
+    void geofenceRemoveAll();
+
+    // callbacks
+    void onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification) final;
+    void onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification) final;
+    void onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+
+private:
+    virtual ~GeofenceAPIClient() = default;
+
+    sp<V1_0::IGnssGeofenceCallback> mGnssGeofencingCbIface;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // GEOFENCE_API_CLINET_H
diff --git a/gps/android/2.0/location_api/GnssAPIClient.cpp b/gps/android/2.0/location_api/GnssAPIClient.cpp
new file mode 100644
index 0000000..44007d9
--- /dev/null
+++ b/gps/android/2.0/location_api/GnssAPIClient.cpp
@@ -0,0 +1,728 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_GnssAPIClient"
+#define SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC (590 * 60 * 60 * 1000) // 590 hours
+
+#include <inttypes.h>
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GnssAPIClient.h"
+#include <LocContext.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnss;
+using ::android::hardware::gnss::V2_0::IGnssCallback;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::gnss::V2_0::GnssLocation;
+
+static void convertGnssSvStatus(GnssSvNotification& in, V1_0::IGnssCallback::GnssSvStatus& out);
+static void convertGnssSvStatus(GnssSvNotification& in,
+        hidl_vec<V2_0::IGnssCallback::GnssSvInfo>& out);
+
+GnssAPIClient::GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+        const sp<V1_0::IGnssNiCallback>& niCb) :
+    LocationAPIClientBase(),
+    mGnssCbIface(nullptr),
+    mGnssNiCbIface(nullptr),
+    mControlClient(new LocationAPIControlClient()),
+    mLocationCapabilitiesMask(0),
+    mLocationCapabilitiesCached(false),
+    mTracking(false),
+    mGnssCbIface_2_0(nullptr)
+{
+    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+    initLocationOptions();
+    gnssUpdateCallbacks(gpsCb, niCb);
+}
+
+GnssAPIClient::GnssAPIClient(const sp<V2_0::IGnssCallback>& gpsCb) :
+    LocationAPIClientBase(),
+    mGnssCbIface(nullptr),
+    mGnssNiCbIface(nullptr),
+    mControlClient(new LocationAPIControlClient()),
+    mLocationCapabilitiesMask(0),
+    mLocationCapabilitiesCached(false),
+    mTracking(false),
+    mGnssCbIface_2_0(nullptr)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &gpsCb);
+
+    initLocationOptions();
+    gnssUpdateCallbacks_2_0(gpsCb);
+}
+
+GnssAPIClient::~GnssAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    if (mControlClient) {
+        delete mControlClient;
+        mControlClient = nullptr;
+    }
+}
+
+void GnssAPIClient::initLocationOptions()
+{
+    // set default LocationOptions.
+    memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+    mTrackingOptions.size = sizeof(TrackingOptions);
+    mTrackingOptions.minInterval = 1000;
+    mTrackingOptions.minDistance = 0;
+    mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+}
+
+void GnssAPIClient::setCallbacks()
+{
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.trackingCb = [this](Location location) {
+        onTrackingCb(location);
+    };
+
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    if (mGnssNiCbIface != nullptr) {
+        loc_core::ContextBase* context =
+                loc_core::LocContext::getLocContext(loc_core::LocContext::mLocationHalName);
+        if (!context->hasAgpsExtendedCapabilities()) {
+            LOC_LOGD("Registering NI CB");
+            locationCallbacks.gnssNiCb = [this](uint32_t id, GnssNiNotification gnssNiNotify) {
+                onGnssNiCb(id, gnssNiNotify);
+            };
+        }
+    }
+
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssSvCb = [this](GnssSvNotification gnssSvNotification) {
+        onGnssSvCb(gnssSvNotification);
+    };
+
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssNmeaCb = [this](GnssNmeaNotification gnssNmeaNotification) {
+        onGnssNmeaCb(gnssNmeaNotification);
+    };
+
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+// for GpsInterface
+void GnssAPIClient::gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+    const sp<IGnssNiCallback>& niCb)
+{
+    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+    mMutex.lock();
+    mGnssCbIface = gpsCb;
+    mGnssNiCbIface = niCb;
+    mMutex.unlock();
+
+    if (mGnssCbIface != nullptr || mGnssNiCbIface != nullptr) {
+        setCallbacks();
+    }
+}
+
+void GnssAPIClient::gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssCallback>& gpsCb)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &gpsCb);
+
+    mMutex.lock();
+    mGnssCbIface_2_0 = gpsCb;
+    mMutex.unlock();
+
+    if (mGnssCbIface_2_0 != nullptr) {
+        setCallbacks();
+    }
+}
+
+bool GnssAPIClient::gnssStart()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+
+    mMutex.lock();
+    mTracking = true;
+    mMutex.unlock();
+
+    bool retVal = true;
+    locAPIStartTracking(mTrackingOptions);
+    return retVal;
+}
+
+bool GnssAPIClient::gnssStop()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+
+    mMutex.lock();
+    mTracking = false;
+    mMutex.unlock();
+
+    bool retVal = true;
+    locAPIStopTracking();
+    return retVal;
+}
+
+bool GnssAPIClient::gnssSetPositionMode(IGnss::GnssPositionMode mode,
+        IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs,
+        uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs,
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LOC_LOGD("%s]: (%d %d %d %d %d %d %d)", __FUNCTION__,
+            (int)mode, recurrence, minIntervalMs, preferredAccuracyMeters,
+            preferredTimeMs, (int)powerMode, timeBetweenMeasurement);
+    bool retVal = true;
+    memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+    mTrackingOptions.size = sizeof(TrackingOptions);
+    mTrackingOptions.minInterval = minIntervalMs;
+    if (IGnss::GnssPositionMode::MS_ASSISTED == mode ||
+            IGnss::GnssPositionRecurrence::RECURRENCE_SINGLE == recurrence) {
+        // We set a very large interval to simulate SINGLE mode. Once we report a fix,
+        // the caller should take the responsibility to stop the session.
+        // For MSA, we always treat it as SINGLE mode.
+        mTrackingOptions.minInterval = SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC;
+    }
+    if (mode == IGnss::GnssPositionMode::STANDALONE)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+    else if (mode == IGnss::GnssPositionMode::MS_BASED)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_MSB;
+    else if (mode ==  IGnss::GnssPositionMode::MS_ASSISTED)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_MSA;
+    else {
+        LOC_LOGD("%s]: invalid GnssPositionMode: %d", __FUNCTION__, (int)mode);
+        retVal = false;
+    }
+    if (GNSS_POWER_MODE_INVALID != powerMode) {
+        mTrackingOptions.powerMode = powerMode;
+        mTrackingOptions.tbm = timeBetweenMeasurement;
+    }
+    locAPIUpdateTrackingOptions(mTrackingOptions);
+    return retVal;
+}
+
+// for GpsNiInterface
+void GnssAPIClient::gnssNiRespond(int32_t notifId,
+        IGnssNiCallback::GnssUserResponseType userResponse)
+{
+    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, notifId, static_cast<int>(userResponse));
+    GnssNiResponse data;
+    switch (userResponse) {
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT:
+        data = GNSS_NI_RESPONSE_ACCEPT;
+        break;
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY:
+        data = GNSS_NI_RESPONSE_DENY;
+        break;
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP:
+        data = GNSS_NI_RESPONSE_NO_RESPONSE;
+        break;
+    default:
+        data = GNSS_NI_RESPONSE_IGNORE;
+        break;
+    }
+
+    locAPIGnssNiResponse(notifId, data);
+}
+
+// these apis using LocationAPIControlClient
+void GnssAPIClient::gnssDeleteAidingData(IGnss::GnssAidingData aidingDataFlags)
+{
+    LOC_LOGD("%s]: (%02hx)", __FUNCTION__, aidingDataFlags);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    GnssAidingData data;
+    memset(&data, 0, sizeof (GnssAidingData));
+    data.sv.svTypeMask = GNSS_AIDING_DATA_SV_TYPE_GPS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_NAVIC_BIT;
+    data.posEngineMask = STANDARD_POSITIONING_ENGINE;
+
+    if (aidingDataFlags == IGnss::GnssAidingData::DELETE_ALL)
+        data.deleteAll = true;
+    else {
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_EPHEMERIS)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_EPHEMERIS_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_ALMANAC)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_ALMANAC_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_POSITION)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_POSITION_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_TIME)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_TIME_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_IONO)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_IONOSPHERE_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_UTC)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_UTC_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_HEALTH)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_HEALTH_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVDIR)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_DIRECTION_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVSTEER)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_STEER_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SADATA)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_SA_DATA_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_RTI)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_RTI_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_CELLDB_INFO)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_CELLDB_BIT;
+    }
+    mControlClient->locAPIGnssDeleteAidingData(data);
+}
+
+void GnssAPIClient::gnssEnable(LocationTechnologyType techType)
+{
+    LOC_LOGD("%s]: (%0d)", __FUNCTION__, techType);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIEnable(techType);
+}
+
+void GnssAPIClient::gnssDisable()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIDisable();
+}
+
+void GnssAPIClient::gnssConfigurationUpdate(const GnssConfig& gnssConfig)
+{
+    LOC_LOGD("%s]: (%02x)", __FUNCTION__, gnssConfig.flags);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIGnssUpdateConfig(gnssConfig);
+}
+
+void GnssAPIClient::requestCapabilities() {
+    // only send capablities if it's already cached, otherwise the first time LocationAPI
+    // is initialized, capabilities will be sent by LocationAPI
+    if (mLocationCapabilitiesCached) {
+        onCapabilitiesCb(mLocationCapabilitiesMask);
+    }
+}
+
+// callbacks
+void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+    LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
+    mLocationCapabilitiesMask = capabilitiesMask;
+    mLocationCapabilitiesCached = true;
+
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    mMutex.unlock();
+
+    if (gnssCbIface_2_0 != nullptr || gnssCbIface != nullptr) {
+        uint32_t data = 0;
+        if ((capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT))
+            data |= IGnssCallback::Capabilities::SCHEDULING;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GEOFENCE_BIT)
+            data |= V1_0::IGnssCallback::Capabilities::GEOFENCING;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT)
+            data |= V1_0::IGnssCallback::Capabilities::MEASUREMENTS;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+            data |= IGnssCallback::Capabilities::MSB;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+            data |= IGnssCallback::Capabilities::MSA;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT)
+            data |= IGnssCallback::Capabilities::LOW_POWER_MODE;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT)
+            data |= IGnssCallback::Capabilities::SATELLITE_BLACKLIST;
+
+        IGnssCallback::GnssSystemInfo gnssInfo = { .yearOfHw = 2015 };
+
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT) {
+            gnssInfo.yearOfHw++; // 2016
+            if (capabilitiesMask & LOCATION_CAPABILITIES_DEBUG_NMEA_BIT) {
+                gnssInfo.yearOfHw++; // 2017
+                if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT ||
+                    capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT) {
+                    gnssInfo.yearOfHw++; // 2018
+                    if (capabilitiesMask & LOCATION_CAPABILITIES_PRIVACY_BIT) {
+                        gnssInfo.yearOfHw++; // 2019
+                    }
+                }
+            }
+        }
+        LOC_LOGV("%s:%d] set_system_info_cb (%d)", __FUNCTION__, __LINE__, gnssInfo.yearOfHw);
+
+        if (gnssCbIface_2_0 != nullptr) {
+            auto r = gnssCbIface_2_0->gnssSetCapabilitiesCb_2_0(data);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetCapabilitiesCb_2_0 description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface_2_0->gnssSetSystemInfoCb(gnssInfo);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssCbIface != nullptr) {
+            auto r = gnssCbIface->gnssSetCapabilitesCb(data);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetCapabilitesCb description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface->gnssSetSystemInfoCb(gnssInfo);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+
+    }
+
+}
+
+void GnssAPIClient::onTrackingCb(Location location)
+{
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    bool isTracking = mTracking;
+    mMutex.unlock();
+
+    LOC_LOGD("%s]: (flags: %02x isTracking: %d)", __FUNCTION__, location.flags, isTracking);
+
+    if (!isTracking) {
+        return;
+    }
+
+    if (gnssCbIface_2_0 != nullptr) {
+        V2_0::GnssLocation gnssLocation;
+        convertGnssLocation(location, gnssLocation);
+        auto r = gnssCbIface_2_0->gnssLocationCb_2_0(gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationCb_2_0 description=%s",
+                __func__, r.description().c_str());
+        }
+    } else if (gnssCbIface != nullptr) {
+        V1_0::GnssLocation gnssLocation;
+        convertGnssLocation(location, gnssLocation);
+        auto r = gnssCbIface->gnssLocationCb(gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationCb description=%s",
+                __func__, r.description().c_str());
+        }
+    } else {
+        LOC_LOGW("%s] No GNSS Interface ready for gnssLocationCb ", __FUNCTION__);
+    }
+
+}
+
+void GnssAPIClient::onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification)
+{
+    LOC_LOGD("%s]: (id: %d)", __FUNCTION__, id);
+    mMutex.lock();
+    auto gnssNiCbIface(mGnssNiCbIface);
+    mMutex.unlock();
+
+    if (gnssNiCbIface == nullptr) {
+        LOC_LOGE("%s]: mGnssNiCbIface is nullptr", __FUNCTION__);
+        return;
+    }
+
+    IGnssNiCallback::GnssNiNotification notificationGnss = {};
+
+    notificationGnss.notificationId = id;
+
+    if (gnssNiNotification.type == GNSS_NI_TYPE_VOICE)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::VOICE;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_SUPL)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_SUPL;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_CONTROL_PLANE)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_CTRL_PLANE;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_EMERGENCY_SUPL)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::EMERGENCY_SUPL;
+
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_NOTIFICATION_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_NOTIFY;
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_VERIFICATION_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_VERIFY;
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::PRIVACY_OVERRIDE;
+
+    notificationGnss.timeoutSec = gnssNiNotification.timeout;
+
+    if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_ACCEPT)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT;
+    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_DENY)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY;
+    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_NO_RESPONSE ||
+            gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_IGNORE)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP;
+
+    notificationGnss.requestorId = gnssNiNotification.requestor;
+
+    notificationGnss.notificationMessage = gnssNiNotification.message;
+
+    if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+    if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+    gnssNiCbIface->niNotifyCb(notificationGnss);
+}
+
+void GnssAPIClient::onGnssSvCb(GnssSvNotification gnssSvNotification)
+{
+    LOC_LOGD("%s]: (count: %u)", __FUNCTION__, gnssSvNotification.count);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    mMutex.unlock();
+
+    if (gnssCbIface_2_0 != nullptr) {
+        hidl_vec<V2_0::IGnssCallback::GnssSvInfo> svInfoList;
+        convertGnssSvStatus(gnssSvNotification, svInfoList);
+        auto r = gnssCbIface_2_0->gnssSvStatusCb_2_0(svInfoList);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSvStatusCb_2_0 description=%s",
+                __func__, r.description().c_str());
+        }
+    } else if (gnssCbIface != nullptr) {
+        V1_0::IGnssCallback::GnssSvStatus svStatus;
+        convertGnssSvStatus(gnssSvNotification, svStatus);
+        auto r = gnssCbIface->gnssSvStatusCb(svStatus);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSvStatusCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
+{
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr || gnssCbIface_2_0 != nullptr) {
+        const std::string s(gnssNmeaNotification.nmea);
+        std::stringstream ss(s);
+        std::string each;
+        while(std::getline(ss, each, '\n')) {
+            each += '\n';
+            android::hardware::hidl_string nmeaString;
+            nmeaString.setToExternal(each.c_str(), each.length());
+            if (gnssCbIface_2_0 != nullptr) {
+                auto r = gnssCbIface_2_0->gnssNmeaCb(
+                        static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+                if (!r.isOk()) {
+                    LOC_LOGE("%s] Error from gnssCbIface_2_0 nmea=%s length=%u description=%s",
+                             __func__, gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+                             r.description().c_str());
+                }
+            } else if (gnssCbIface != nullptr) {
+                auto r = gnssCbIface->gnssNmeaCb(
+                        static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+                if (!r.isOk()) {
+                    LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%u description=%s",
+                             __func__, gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+                             r.description().c_str());
+                }
+            }
+        }
+    }
+}
+
+void GnssAPIClient::onStartTrackingCb(LocationError error)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    mMutex.unlock();
+
+    if (error == LOCATION_ERROR_SUCCESS) {
+        if (gnssCbIface_2_0 != nullptr) {
+            auto r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2.0 ENGINE_ON description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2.0 SESSION_BEGIN description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssCbIface != nullptr) {
+            auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb ENGINE_ON description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb SESSION_BEGIN description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GnssAPIClient::onStopTrackingCb(LocationError error)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    mMutex.unlock();
+
+    if (error == LOCATION_ERROR_SUCCESS) {
+        if (gnssCbIface_2_0 != nullptr) {
+            auto r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2.0 SESSION_END description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2.0 ENGINE_OFF description=%s",
+                    __func__, r.description().c_str());
+            }
+
+        } else if (gnssCbIface != nullptr) {
+            auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb SESSION_END description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb ENGINE_OFF description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in, V1_0::IGnssCallback::GnssSvStatus& out)
+{
+    memset(&out, 0, sizeof(IGnssCallback::GnssSvStatus));
+    out.numSvs = in.count;
+    if (out.numSvs > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+        LOC_LOGW("%s]: Too many satellites %u. Clamps to %d.",
+                __FUNCTION__,  out.numSvs, V1_0::GnssMax::SVS_COUNT);
+        out.numSvs = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+    }
+    for (size_t i = 0; i < out.numSvs; i++) {
+        convertGnssSvid(in.gnssSvs[i], out.gnssSvList[i].svid);
+        convertGnssConstellationType(in.gnssSvs[i].type, out.gnssSvList[i].constellation);
+        out.gnssSvList[i].cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+        out.gnssSvList[i].elevationDegrees = in.gnssSvs[i].elevation;
+        out.gnssSvList[i].azimuthDegrees = in.gnssSvs[i].azimuth;
+        out.gnssSvList[i].carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+        out.gnssSvList[i].svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+            out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+            out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+            out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+            out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+    }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in,
+        hidl_vec<V2_0::IGnssCallback::GnssSvInfo>& out)
+{
+    out.resize(in.count);
+    for (size_t i = 0; i < in.count; i++) {
+        convertGnssSvid(in.gnssSvs[i], out[i].v1_0.svid);
+        out[i].v1_0.cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+        out[i].v1_0.elevationDegrees = in.gnssSvs[i].elevation;
+        out[i].v1_0.azimuthDegrees = in.gnssSvs[i].azimuth;
+        out[i].v1_0.carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+        out[i].v1_0.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+            out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+            out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+            out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+            out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+
+        convertGnssConstellationType(in.gnssSvs[i].type, out[i].constellation);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/location_api/GnssAPIClient.h b/gps/android/2.0/location_api/GnssAPIClient.h
new file mode 100644
index 0000000..cfa78c7
--- /dev/null
+++ b/gps/android/2.0/location_api/GnssAPIClient.h
@@ -0,0 +1,115 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GNSS_API_CLINET_H
+#define GNSS_API_CLINET_H
+
+
+#include <mutex>
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnssCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class GnssAPIClient : public LocationAPIClientBase
+{
+public:
+    GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+            const sp<V1_0::IGnssNiCallback>& niCb);
+    GnssAPIClient(const sp<V2_0::IGnssCallback>& gpsCb);
+    GnssAPIClient(const GnssAPIClient&) = delete;
+    GnssAPIClient& operator=(const GnssAPIClient&) = delete;
+
+    // for GpsInterface
+    void gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+            const sp<V1_0::IGnssNiCallback>& niCb);
+    void gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssCallback>& gpsCb);
+    bool gnssStart();
+    bool gnssStop();
+    bool gnssSetPositionMode(V1_0::IGnss::GnssPositionMode mode,
+            V1_0::IGnss::GnssPositionRecurrence recurrence,
+            uint32_t minIntervalMs,
+            uint32_t preferredAccuracyMeters,
+            uint32_t preferredTimeMs,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = 0);
+
+    // for GpsNiInterface
+    void gnssNiRespond(int32_t notifId, V1_0::IGnssNiCallback::GnssUserResponseType userResponse);
+
+    // these apis using LocationAPIControlClient
+    void gnssDeleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags);
+    void gnssEnable(LocationTechnologyType techType);
+    void gnssDisable();
+    void gnssConfigurationUpdate(const GnssConfig& gnssConfig);
+
+    inline LocationCapabilitiesMask gnssGetCapabilities() const {
+        return mLocationCapabilitiesMask;
+    }
+    void requestCapabilities();
+
+    // callbacks we are interested in
+    void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+    void onTrackingCb(Location location) final;
+    void onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification) final;
+    void onGnssSvCb(GnssSvNotification gnssSvNotification) final;
+    void onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification) final;
+
+    void onStartTrackingCb(LocationError error) final;
+    void onStopTrackingCb(LocationError error) final;
+
+private:
+    virtual ~GnssAPIClient();
+
+    void setCallbacks();
+    void initLocationOptions();
+    sp<V1_0::IGnssCallback> mGnssCbIface;
+    sp<V1_0::IGnssNiCallback> mGnssNiCbIface;
+    std::mutex mMutex;
+    LocationAPIControlClient* mControlClient;
+    LocationCapabilitiesMask mLocationCapabilitiesMask;
+    bool mLocationCapabilitiesCached;
+    TrackingOptions mTrackingOptions;
+    bool mTracking;
+    sp<V2_0::IGnssCallback> mGnssCbIface_2_0;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // GNSS_API_CLINET_H
diff --git a/gps/android/2.0/location_api/LocationUtil.cpp b/gps/android/2.0/location_api/LocationUtil.cpp
new file mode 100644
index 0000000..961b7b1
--- /dev/null
+++ b/gps/android/2.0/location_api/LocationUtil.cpp
@@ -0,0 +1,334 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <LocationUtil.h>
+#include <log_util.h>
+#include <inttypes.h>
+#include <gps_extended_c.h>
+#include <loc_misc_utils.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::GnssLocation;
+using ::android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
+using ::android::hardware::gnss::V2_0::GnssConstellationType;
+using ::android::hardware::gnss::V1_0::GnssLocationFlags;
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out)
+{
+    memset(&out, 0, sizeof(V1_0::GnssLocation));
+    if (in.flags & LOCATION_HAS_LAT_LONG_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_LAT_LONG;
+        out.latitudeDegrees = in.latitude;
+        out.longitudeDegrees = in.longitude;
+    }
+    if (in.flags & LOCATION_HAS_ALTITUDE_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE;
+        out.altitudeMeters = in.altitude;
+    }
+    if (in.flags & LOCATION_HAS_SPEED_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
+        out.speedMetersPerSec = in.speed;
+    }
+    if (in.flags & LOCATION_HAS_BEARING_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
+        out.bearingDegrees = in.bearing;
+    }
+    if (in.flags & LOCATION_HAS_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
+        out.horizontalAccuracyMeters = in.accuracy;
+    }
+    if (in.flags & LOCATION_HAS_VERTICAL_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
+        out.verticalAccuracyMeters = in.verticalAccuracy;
+    }
+    if (in.flags & LOCATION_HAS_SPEED_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
+        out.speedAccuracyMetersPerSecond = in.speedAccuracy;
+    }
+    if (in.flags & LOCATION_HAS_BEARING_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
+        out.bearingAccuracyDegrees = in.bearingAccuracy;
+    }
+
+    out.timestamp = static_cast<V1_0::GnssUtcTime>(in.timestamp);
+}
+
+void convertGnssLocation(Location& in, V2_0::GnssLocation& out)
+{
+    memset(&out, 0, sizeof(V2_0::GnssLocation));
+    convertGnssLocation(in, out.v1_0);
+
+    if (in.flags & LOCATION_HAS_ELAPSED_REAL_TIME) {
+        out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIMESTAMP_NS;
+        out.elapsedRealtime.timestampNs = in.elapsedRealTime;
+        out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS;
+        out.elapsedRealtime.timeUncertaintyNs = in.elapsedRealTimeUnc;
+        LOC_LOGd("out.elapsedRealtime.timestampNs=%" PRIi64 ""
+                 " out.elapsedRealtime.timeUncertaintyNs=%" PRIi64 ""
+                 " out.elapsedRealtime.flags=0x%X",
+                 out.elapsedRealtime.timestampNs,
+                 out.elapsedRealtime.timeUncertaintyNs, out.elapsedRealtime.flags);
+    }
+}
+
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG) {
+        out.flags |= LOCATION_HAS_LAT_LONG_BIT;
+        out.latitude = in.latitudeDegrees;
+        out.longitude = in.longitudeDegrees;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE) {
+        out.flags |= LOCATION_HAS_ALTITUDE_BIT;
+        out.altitude = in.altitudeMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED) {
+        out.flags |= LOCATION_HAS_SPEED_BIT;
+        out.speed = in.speedMetersPerSec;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+        out.flags |= LOCATION_HAS_BEARING_BIT;
+        out.bearing = in.bearingDegrees;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+        out.flags |= LOCATION_HAS_ACCURACY_BIT;
+        out.accuracy = in.horizontalAccuracyMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+        out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+        out.verticalAccuracy = in.verticalAccuracyMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+        out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+        out.speedAccuracy = in.speedAccuracyMetersPerSecond;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+        out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+        out.bearingAccuracy = in.bearingAccuracyDegrees;
+    }
+
+    out.timestamp = static_cast<uint64_t>(in.timestamp);
+}
+
+void convertGnssLocation(const V2_0::GnssLocation& in, Location& out)
+{
+    memset(&out, 0, sizeof(out));
+    convertGnssLocation(in.v1_0, out);
+}
+
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out)
+{
+    switch(in) {
+        case GNSS_SV_TYPE_GPS:
+            out = V1_0::GnssConstellationType::GPS;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = V1_0::GnssConstellationType::SBAS;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            out = V1_0::GnssConstellationType::GLONASS;
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = V1_0::GnssConstellationType::QZSS;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = V1_0::GnssConstellationType::BEIDOU;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = V1_0::GnssConstellationType::GALILEO;
+            break;
+        case GNSS_SV_TYPE_UNKNOWN:
+        default:
+            out = V1_0::GnssConstellationType::UNKNOWN;
+            break;
+    }
+}
+
+void convertGnssConstellationType(GnssSvType& in, V2_0::GnssConstellationType& out)
+{
+    switch(in) {
+        case GNSS_SV_TYPE_GPS:
+            out = V2_0::GnssConstellationType::GPS;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = V2_0::GnssConstellationType::SBAS;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            out = V2_0::GnssConstellationType::GLONASS;
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = V2_0::GnssConstellationType::QZSS;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = V2_0::GnssConstellationType::BEIDOU;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = V2_0::GnssConstellationType::GALILEO;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = V2_0::GnssConstellationType::IRNSS;
+            break;
+        case GNSS_SV_TYPE_UNKNOWN:
+        default:
+            out = V2_0::GnssConstellationType::UNKNOWN;
+            break;
+    }
+}
+
+void convertGnssSvid(GnssSv& in, int16_t& out)
+{
+    switch (in.type) {
+        case GNSS_SV_TYPE_GPS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            if (!isGloSlotUnknown(in.svId)) { // OSN is known
+                out = in.svId - GLO_SV_PRN_MIN + 1;
+            } else { // OSN is not known, report FCN
+                out = in.gloFrequency + 92;
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = in.svId - BDS_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = in.svId - GAL_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = in.svId - NAVIC_SV_PRN_MIN + 1;
+            break;
+        default:
+            out = in.svId;
+            break;
+    }
+}
+
+void convertGnssSvid(GnssMeasurementsData& in, int16_t& out)
+{
+    switch (in.svType) {
+        case GNSS_SV_TYPE_GPS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            if (!isGloSlotUnknown(in.svId)) { // OSN is known
+                out = in.svId - GLO_SV_PRN_MIN + 1;
+            } else { // OSN is not known, report FCN
+                out = in.gloFrequency + 92;
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = in.svId - BDS_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = in.svId - GAL_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = in.svId - NAVIC_SV_PRN_MIN + 1;
+            break;
+        default:
+            out = in.svId;
+            break;
+    }
+}
+
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out)
+{
+    switch(in) {
+        case GNSS_EPH_TYPE_EPHEMERIS:
+            out = GnssDebug::SatelliteEphemerisType::EPHEMERIS;
+            break;
+        case GNSS_EPH_TYPE_ALMANAC:
+            out = GnssDebug::SatelliteEphemerisType::ALMANAC_ONLY;
+            break;
+        case GNSS_EPH_TYPE_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisType::NOT_AVAILABLE;
+            break;
+    }
+}
+
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out)
+{
+    switch(in) {
+        case GNSS_EPH_SOURCE_DEMODULATED:
+            out = GnssDebug::SatelliteEphemerisSource::DEMODULATED;
+            break;
+        case GNSS_EPH_SOURCE_SUPL_PROVIDED:
+            out = GnssDebug::SatelliteEphemerisSource::SUPL_PROVIDED;
+            break;
+        case GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED:
+            out = GnssDebug::SatelliteEphemerisSource::OTHER_SERVER_PROVIDED;
+            break;
+        case GNSS_EPH_SOURCE_LOCAL:
+        case GNSS_EPH_SOURCE_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisSource::OTHER;
+            break;
+    }
+}
+
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out)
+{
+    switch(in) {
+        case GNSS_EPH_HEALTH_GOOD:
+            out = GnssDebug::SatelliteEphemerisHealth::GOOD;
+            break;
+        case GNSS_EPH_HEALTH_BAD:
+            out = GnssDebug::SatelliteEphemerisHealth::BAD;
+            break;
+        case GNSS_EPH_HEALTH_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisHealth::UNKNOWN;
+            break;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/location_api/LocationUtil.h b/gps/android/2.0/location_api/LocationUtil.h
new file mode 100644
index 0000000..70729e4
--- /dev/null
+++ b/gps/android/2.0/location_api/LocationUtil.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOCATION_UTIL_H
+#define LOCATION_UTIL_H
+
+#include <android/hardware/gnss/2.0/types.h>
+#include <LocationAPI.h>
+#include <GnssDebug.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out);
+void convertGnssLocation(Location& in, V2_0::GnssLocation& out);
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out);
+void convertGnssLocation(const V2_0::GnssLocation& in, Location& out);
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out);
+void convertGnssConstellationType(GnssSvType& in, V2_0::GnssConstellationType& out);
+void convertGnssSvid(GnssSv& in, int16_t& out);
+void convertGnssSvid(GnssMeasurementsData& in, int16_t& out);
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out);
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out);
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out);
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // LOCATION_UTIL_H
diff --git a/gps/android/2.0/location_api/MeasurementAPIClient.cpp b/gps/android/2.0/location_api/MeasurementAPIClient.cpp
new file mode 100644
index 0000000..425415f
--- /dev/null
+++ b/gps/android/2.0/location_api/MeasurementAPIClient.cpp
@@ -0,0 +1,507 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_MeasurementAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+#include <inttypes.h>
+
+#include "LocationUtil.h"
+#include "MeasurementAPIClient.h"
+#include <loc_misc_utils.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V2_0::IGnssMeasurementCallback;
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+        V1_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+        V1_1::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssData_2_0(GnssMeasurementsNotification& in,
+        V2_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+        V1_0::IGnssMeasurementCallback::GnssMeasurement& out);
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out);
+static void convertGnssMeasurementsCodeType(GnssMeasurementsCodeType& in,
+        ::android::hardware::hidl_string& out);
+static void convertElapsedRealtimeNanos(GnssMeasurementsNotification& in,
+        ::android::hardware::gnss::V2_0::ElapsedRealtime& elapsedRealtimeNanos);
+
+MeasurementAPIClient::MeasurementAPIClient() :
+    mGnssMeasurementCbIface(nullptr),
+    mGnssMeasurementCbIface_1_1(nullptr),
+    mGnssMeasurementCbIface_2_0(nullptr),
+    mTracking(false)
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+MeasurementAPIClient::~MeasurementAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+void MeasurementAPIClient::clearInterfaces()
+{
+    mGnssMeasurementCbIface = nullptr;
+    mGnssMeasurementCbIface_1_1 = nullptr;
+    mGnssMeasurementCbIface_2_0 = nullptr;
+}
+
+// for GpsInterface
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback(const sp<V1_0::IGnssMeasurementCallback>& callback)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    mMutex.lock();
+    clearInterfaces();
+    mGnssMeasurementCbIface = callback;
+    mMutex.unlock();
+
+    return startTracking();
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback_1_1(
+        const sp<V1_1::IGnssMeasurementCallback>& callback,
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LOC_LOGD("%s]: (%p) (powermode: %d) (tbm: %d)",
+            __FUNCTION__, &callback, (int)powerMode, timeBetweenMeasurement);
+
+    mMutex.lock();
+    clearInterfaces();
+    mGnssMeasurementCbIface_1_1 = callback;
+    mMutex.unlock();
+
+    return startTracking(powerMode, timeBetweenMeasurement);
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback_2_0(
+    const sp<V2_0::IGnssMeasurementCallback>& callback,
+    GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LOC_LOGD("%s]: (%p) (powermode: %d) (tbm: %d)",
+        __FUNCTION__, &callback, (int)powerMode, timeBetweenMeasurement);
+
+    mMutex.lock();
+    clearInterfaces();
+    mGnssMeasurementCbIface_2_0 = callback;
+    mMutex.unlock();
+
+    return startTracking(powerMode, timeBetweenMeasurement);
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::startTracking(
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+    if (mGnssMeasurementCbIface_2_0 != nullptr ||
+        mGnssMeasurementCbIface_1_1 != nullptr ||
+        mGnssMeasurementCbIface != nullptr) {
+        locationCallbacks.gnssMeasurementsCb =
+            [this](GnssMeasurementsNotification gnssMeasurementsNotification) {
+                onGnssMeasurementsCb(gnssMeasurementsNotification);
+            };
+    }
+
+    locAPISetCallbacks(locationCallbacks);
+
+    TrackingOptions options = {};
+    memset(&options, 0, sizeof(TrackingOptions));
+    options.size = sizeof(TrackingOptions);
+    options.minInterval = 1000;
+    options.mode = GNSS_SUPL_MODE_STANDALONE;
+    if (GNSS_POWER_MODE_INVALID != powerMode) {
+        options.powerMode = powerMode;
+        options.tbm = timeBetweenMeasurement;
+    }
+
+    mTracking = true;
+    LOC_LOGD("%s]: start tracking session", __FUNCTION__);
+    locAPIStartTracking(options);
+    return IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+// for GpsMeasurementInterface
+void MeasurementAPIClient::measurementClose() {
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    mTracking = false;
+    locAPIStopTracking();
+}
+
+// callbacks
+void MeasurementAPIClient::onGnssMeasurementsCb(
+        GnssMeasurementsNotification gnssMeasurementsNotification)
+{
+    LOC_LOGD("%s]: (count: %u active: %d)",
+            __FUNCTION__, gnssMeasurementsNotification.count, mTracking);
+    if (mTracking) {
+        mMutex.lock();
+        sp<V1_0::IGnssMeasurementCallback> gnssMeasurementCbIface = nullptr;
+        sp<V1_1::IGnssMeasurementCallback> gnssMeasurementCbIface_1_1 = nullptr;
+        sp<V2_0::IGnssMeasurementCallback> gnssMeasurementCbIface_2_0 = nullptr;
+        if (mGnssMeasurementCbIface_2_0 != nullptr) {
+            gnssMeasurementCbIface_2_0 = mGnssMeasurementCbIface_2_0;
+        } else if (mGnssMeasurementCbIface_1_1 != nullptr) {
+            gnssMeasurementCbIface_1_1 = mGnssMeasurementCbIface_1_1;
+        } else if (mGnssMeasurementCbIface != nullptr) {
+            gnssMeasurementCbIface = mGnssMeasurementCbIface;
+        }
+        mMutex.unlock();
+
+        if (gnssMeasurementCbIface_2_0 != nullptr) {
+            V2_0::IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData_2_0(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface_2_0->gnssMeasurementCb_2_0(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssMeasurementCbIface_1_1 != nullptr) {
+            V1_1::IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData_1_1(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface_1_1->gnssMeasurementCb(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssMeasurementCbIface != nullptr) {
+            V1_0::IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface->GnssMeasurementCb(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from GnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+        V1_0::IGnssMeasurementCallback::GnssMeasurement& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in.flags & GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SNR;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_FREQUENCY;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_CYCLES;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL;
+    convertGnssSvid(in, out.svid);
+    convertGnssConstellationType(in.svType, out.constellation);
+    out.timeOffsetNs = in.timeOffsetNs;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+    if (in.stateMask &  GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+    out.receivedSvTimeInNs = in.receivedSvTimeNs;
+    out.receivedSvTimeUncertaintyInNs = in.receivedSvTimeUncertaintyNs;
+    out.cN0DbHz = in.carrierToNoiseDbHz;
+    out.pseudorangeRateMps = in.pseudorangeRateMps;
+    out.pseudorangeRateUncertaintyMps = in.pseudorangeRateUncertaintyMps;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+    out.accumulatedDeltaRangeM = in.adrMeters;
+    out.accumulatedDeltaRangeUncertaintyM = in.adrUncertaintyMeters;
+    out.carrierFrequencyHz = in.carrierFrequencyHz;
+    out.carrierCycles = in.carrierCycles;
+    out.carrierPhase = in.carrierPhase;
+    out.carrierPhaseUncertainty = in.carrierPhaseUncertainty;
+    uint8_t indicator =
+        static_cast<uint8_t>(IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN);
+    if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_PRESENT)
+        indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_PRESENT;
+    if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_NOT_PRESENT)
+        indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATIOR_NOT_PRESENT;
+    out.multipathIndicator =
+        static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>(indicator);
+    out.snrDb = in.signalToNoiseRatioDb;
+    out.agcLevelDb = in.agcLevelDb;
+}
+
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_LEAP_SECOND_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_LEAP_SECOND;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_TIME_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_FULL_BIAS_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_FULL_BIAS;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT_UNCERTAINTY;
+    out.leapSecond = in.leapSecond;
+    out.timeNs = in.timeNs;
+    out.timeUncertaintyNs = in.timeUncertaintyNs;
+    out.fullBiasNs = in.fullBiasNs;
+    out.biasNs = in.biasNs;
+    out.biasUncertaintyNs = in.biasUncertaintyNs;
+    out.driftNsps = in.driftNsps;
+    out.driftUncertaintyNsps = in.driftUncertaintyNsps;
+    out.hwClockDiscontinuityCount = in.hwClockDiscontinuityCount;
+}
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+        V1_0::IGnssMeasurementCallback::GnssData& out)
+{
+    memset(&out, 0, sizeof(out));
+    out.measurementCount = in.count;
+    if (out.measurementCount > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+        LOC_LOGW("%s]: Too many measurement %u. Clamps to %d.",
+                __FUNCTION__,  out.measurementCount, V1_0::GnssMax::SVS_COUNT);
+        out.measurementCount = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+    }
+    for (size_t i = 0; i < out.measurementCount; i++) {
+        convertGnssMeasurement(in.measurements[i], out.measurements[i]);
+    }
+    convertGnssClock(in.clock, out.clock);
+}
+
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+        V1_1::IGnssMeasurementCallback::GnssData& out)
+{
+    memset(&out, 0, sizeof(out));
+    out.measurements.resize(in.count);
+    for (size_t i = 0; i < in.count; i++) {
+        convertGnssMeasurement(in.measurements[i], out.measurements[i].v1_0);
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+            out.measurements[i].accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+            out.measurements[i].accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+            out.measurements[i].accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_HALF_CYCLE_RESOLVED_BIT)
+            out.measurements[i].accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_HALF_CYCLE_RESOLVED;
+    }
+    convertGnssClock(in.clock, out.clock);
+}
+
+static void convertGnssData_2_0(GnssMeasurementsNotification& in,
+        V2_0::IGnssMeasurementCallback::GnssData& out)
+{
+    memset(&out, 0, sizeof(out));
+    out.measurements.resize(in.count);
+    for (size_t i = 0; i < in.count; i++) {
+        convertGnssMeasurement(in.measurements[i], out.measurements[i].v1_1.v1_0);
+        convertGnssConstellationType(in.measurements[i].svType, out.measurements[i].constellation);
+        convertGnssMeasurementsCodeType(in.measurements[i].codeType, out.measurements[i].codeType);
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+            out.measurements[i].v1_1.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+            out.measurements[i].v1_1.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+            out.measurements[i].v1_1.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+        if (in.measurements[i].adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_HALF_CYCLE_RESOLVED_BIT)
+            out.measurements[i].v1_1.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_HALF_CYCLE_RESOLVED;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+        if (in.measurements[i].stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+        if (in.measurements[i].stateMask &  GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+        if (in.measurements[i].stateMask &  GNSS_MEASUREMENTS_STATE_TOW_KNOWN_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_KNOWN;
+        if (in.measurements[i].stateMask &  GNSS_MEASUREMENTS_STATE_GLO_TOD_KNOWN_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_KNOWN;
+        if (in.measurements[i].stateMask &  GNSS_MEASUREMENTS_STATE_2ND_CODE_LOCK_BIT)
+            out.measurements[i].state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_2ND_CODE_LOCK;
+    }
+    convertGnssClock(in.clock, out.clock);
+    convertElapsedRealtimeNanos(in, out.elapsedRealtime);
+}
+
+static void convertElapsedRealtimeNanos(GnssMeasurementsNotification& in,
+        ::android::hardware::gnss::V2_0::ElapsedRealtime& elapsedRealtime)
+{
+    if (in.clock.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_ELAPSED_REAL_TIME_BIT) {
+        elapsedRealtime.flags |= V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS;
+        elapsedRealtime.timestampNs = in.clock.elapsedRealTime;
+        elapsedRealtime.flags |= V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS;
+        elapsedRealtime.timeUncertaintyNs = in.clock.elapsedRealTimeUnc;
+        LOC_LOGd("elapsedRealtime.timestampNs=%" PRIi64 ""
+                 " elapsedRealtime.timeUncertaintyNs=%" PRIi64 " elapsedRealtime.flags=0x%X",
+                 elapsedRealtime.timestampNs,
+                 elapsedRealtime.timeUncertaintyNs, elapsedRealtime.flags);
+    }
+}
+
+static void convertGnssMeasurementsCodeType(GnssMeasurementsCodeType& in,
+        ::android::hardware::hidl_string& out)
+{
+    switch(in) {
+        case GNSS_MEASUREMENTS_CODE_TYPE_A:
+            out = "A";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_B:
+            out = "B";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_C:
+            out = "C";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_I:
+            out = "I";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_L:
+            out = "L";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_M:
+            out = "M";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_P:
+            out = "P";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_Q:
+            out = "Q";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_S:
+            out = "S";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_W:
+            out = "W";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_X:
+            out = "X";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_Y:
+            out = "Y";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_Z:
+            out = "Z";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_N:
+            out = "N";
+            break;
+        default:
+            out = "UNKNOWN";
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.0/location_api/MeasurementAPIClient.h b/gps/android/2.0/location_api/MeasurementAPIClient.h
new file mode 100644
index 0000000..6c2d38d
--- /dev/null
+++ b/gps/android/2.0/location_api/MeasurementAPIClient.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MEASUREMENT_API_CLINET_H
+#define MEASUREMENT_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/2.0/IGnssMeasurement.h>
+//#include <android/hardware/gnss/1.1/IGnssMeasurementCallback.h>
+#include <LocationAPIClientBase.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+
+class MeasurementAPIClient : public LocationAPIClientBase
+{
+public:
+    MeasurementAPIClient();
+    MeasurementAPIClient(const MeasurementAPIClient&) = delete;
+    MeasurementAPIClient& operator=(const MeasurementAPIClient&) = delete;
+
+    // for GpsMeasurementInterface
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback(
+            const sp<V1_0::IGnssMeasurementCallback>& callback);
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback_1_1(
+            const sp<V1_1::IGnssMeasurementCallback>& callback,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback_2_0(
+            const sp<V2_0::IGnssMeasurementCallback>& callback,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+    void measurementClose();
+    Return<IGnssMeasurement::GnssMeasurementStatus> startTracking(
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+
+    // callbacks we are interested in
+    void onGnssMeasurementsCb(GnssMeasurementsNotification gnssMeasurementsNotification) final;
+
+private:
+    virtual ~MeasurementAPIClient();
+
+    std::mutex mMutex;
+    sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface;
+    sp<V1_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1;
+    sp<V2_0::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_0;
+    bool mTracking;
+    void clearInterfaces();
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // MEASUREMENT_API_CLINET_H
diff --git a/gps/android/2.0/service.cpp b/gps/android/2.0/service.cpp
new file mode 100644
index 0000000..f7efb18
--- /dev/null
+++ b/gps/android/2.0/service.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "android.hardware.gnss@2.0-service-qti"
+
+#include <android/hardware/gnss/2.0/IGnss.h>
+#include <hidl/LegacySupport.h>
+#include "loc_cfg.h"
+#include "loc_misc_utils.h"
+
+extern "C" {
+#include "vndfwk-detect.h"
+}
+
+#ifdef ARCH_ARM_32
+#define DEFAULT_HW_BINDER_MEM_SIZE 65536
+#endif
+
+using android::hardware::gnss::V2_0::IGnss;
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::registerPassthroughServiceImplementation;
+using android::hardware::joinRpcThreadpool;
+
+using android::status_t;
+using android::OK;
+
+typedef int vendorEnhancedServiceMain(int /* argc */, char* /* argv */ []);
+
+int main() {
+
+    ALOGI("%s", __FUNCTION__);
+
+    int vendorInfo = getVendorEnhancedInfo();
+    bool vendorEnhanced = ( 1 == vendorInfo || 3 == vendorInfo );
+    setVendorEnhanced(vendorEnhanced);
+
+#ifdef ARCH_ARM_32
+    android::hardware::ProcessState::initWithMmapSize((size_t)(DEFAULT_HW_BINDER_MEM_SIZE));
+#endif
+    configureRpcThreadpool(1, true);
+    status_t status;
+
+    status = registerPassthroughServiceImplementation<IGnss>();
+    if (status == OK) {
+    #ifdef LOC_HIDL_VERSION
+        #define VENDOR_ENHANCED_LIB "vendor.qti.gnss@" LOC_HIDL_VERSION "-service.so"
+
+        void* libHandle = NULL;
+        vendorEnhancedServiceMain* vendorEnhancedMainMethod = (vendorEnhancedServiceMain*)
+                dlGetSymFromLib(libHandle, VENDOR_ENHANCED_LIB, "main");
+        if (NULL != vendorEnhancedMainMethod) {
+            (*vendorEnhancedMainMethod)(0, NULL);
+        }
+    #else
+        ALOGI("LOC_HIDL_VERSION not defined.");
+    #endif
+        joinRpcThreadpool();
+    } else {
+        ALOGE("Error while registering IGnss 2.0 service: %d", status);
+    }
+
+    return 0;
+}
diff --git a/gps/android/2.1/AGnss.cpp b/gps/android/2.1/AGnss.cpp
new file mode 100644
index 0000000..ce7b3aa
--- /dev/null
+++ b/gps/android/2.1/AGnss.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_AGnssInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "AGnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+static AGnss* spAGnss = nullptr;
+
+AGnss::AGnss(Gnss* gnss) : mGnss(gnss), mType(LOC_AGPS_TYPE_INVALID) {
+    spAGnss = this;
+}
+
+AGnss::~AGnss() {
+    spAGnss = nullptr;
+}
+
+void AGnss::agnssStatusIpV4Cb(AGnssExtStatusIpV4 status) {
+    if (nullptr != spAGnss) {
+        spAGnss->statusCb(status.type, status.status);
+    }
+}
+
+void AGnss::statusCb(AGpsExtType type, LocAGpsStatusValue status) {
+
+    V2_0::IAGnssCallback::AGnssType  aType;
+    IAGnssCallback::AGnssStatusValue aStatus;
+
+    // cache the AGps Type
+    mType = type;
+
+    switch (type) {
+    case LOC_AGPS_TYPE_SUPL:
+        aType = IAGnssCallback::AGnssType::SUPL;
+        break;
+    case LOC_AGPS_TYPE_SUPL_ES:
+        aType = IAGnssCallback::AGnssType::SUPL_EIMS;
+        break;
+    default:
+        LOC_LOGE("invalid type: %d", type);
+        return;
+    }
+
+    switch (status) {
+    case LOC_GPS_REQUEST_AGPS_DATA_CONN:
+        aStatus = IAGnssCallback::AGnssStatusValue::REQUEST_AGNSS_DATA_CONN;
+        break;
+    case LOC_GPS_RELEASE_AGPS_DATA_CONN:
+        aStatus = IAGnssCallback::AGnssStatusValue::RELEASE_AGNSS_DATA_CONN;
+        break;
+    case LOC_GPS_AGPS_DATA_CONNECTED:
+        aStatus = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONNECTED;
+        break;
+    case LOC_GPS_AGPS_DATA_CONN_DONE:
+        aStatus = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_DONE;
+        break;
+    case LOC_GPS_AGPS_DATA_CONN_FAILED:
+        aStatus = IAGnssCallback::AGnssStatusValue::AGNSS_DATA_CONN_FAILED;
+        break;
+    default:
+        LOC_LOGE("invalid status: %d", status);
+        return;
+    }
+
+    if (mAGnssCbIface != nullptr) {
+        auto r = mAGnssCbIface->agnssStatusCb(aType, aStatus);
+        if (!r.isOk()) {
+            LOC_LOGw("Error invoking AGNSS status cb %s", r.description().c_str());
+        }
+    }
+    else {
+        LOC_LOGw("setCallback has not been called yet");
+    }
+}
+
+Return<void> AGnss::setCallback(const sp<V2_0::IAGnssCallback>& callback) {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return Void();
+    }
+
+    // Save the interface
+    mAGnssCbIface = callback;
+
+    AgpsCbInfo cbInfo = {};
+    cbInfo.statusV4Cb = (void*)agnssStatusIpV4Cb;
+    cbInfo.atlType = AGPS_ATL_TYPE_SUPL | AGPS_ATL_TYPE_SUPL_ES;
+
+    mGnss->getGnssInterface()->agpsInit(cbInfo);
+    return Void();
+}
+
+Return<bool> AGnss::dataConnClosed() {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnClosed(LOC_AGPS_TYPE_SUPL);
+    return true;
+}
+
+Return<bool> AGnss::dataConnFailed() {
+
+    if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnFailed(LOC_AGPS_TYPE_SUPL);
+    return true;
+}
+
+Return<bool> AGnss::dataConnOpen(uint64_t /*networkHandle*/, const hidl_string& apn,
+        V2_0::IAGnss::ApnIpType apnIpType) {
+
+    if (mGnss == nullptr || mGnss->getGnssInterface() == nullptr){
+        LOC_LOGE("Null GNSS interface");
+        return false;
+    }
+
+    std::string apnString(apn.c_str());
+    // During Emergency SUPL, an apn name of "sos" means that no
+    // apn was found, like in the simless case, so apn is cleared
+    if (LOC_AGPS_TYPE_SUPL_ES == mType && "sos" == apnString) {
+        LOC_LOGD("dataConnOpen APN name = [sos] cleared");
+        apnString.clear();
+    }
+
+    LOC_LOGD("dataConnOpen APN name = [%s]", apnString.c_str());
+
+    AGpsBearerType bearerType;
+    switch (apnIpType) {
+    case IAGnss::ApnIpType::IPV4:
+        bearerType = AGPS_APN_BEARER_IPV4;
+        break;
+    case IAGnss::ApnIpType::IPV6:
+        bearerType = AGPS_APN_BEARER_IPV6;
+        break;
+    case IAGnss::ApnIpType::IPV4V6:
+        bearerType = AGPS_APN_BEARER_IPV4V6;
+        break;
+    default:
+        bearerType = AGPS_APN_BEARER_IPV4;
+        break;
+    }
+
+    mGnss->getGnssInterface()->agpsDataConnOpen(
+        LOC_AGPS_TYPE_SUPL, apnString.c_str(), apnString.size(), (int)bearerType);
+    return true;
+}
+
+Return<bool> AGnss::setServer(V2_0::IAGnssCallback::AGnssType type,
+                              const hidl_string& hostname,
+                              int32_t port) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+    config.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+    if (type == IAGnssCallback::AGnssType::SUPL) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL;
+    } else if (type == IAGnssCallback::AGnssType::C2K) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_C2K;
+    } else if (type == IAGnssCallback::AGnssType::SUPL_EIMS) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL_EIMS;
+    } else if (type == IAGnssCallback::AGnssType::SUPL_IMS) {
+        config.assistanceServer.type = GNSS_ASSISTANCE_TYPE_SUPL_IMS;
+    } else {
+        LOC_LOGE("%s]: invalid AGnssType: %d", __FUNCTION__, static_cast<uint8_t>(type));
+        return false;
+    }
+    config.assistanceServer.hostName = strdup(hostname.c_str());
+    config.assistanceServer.port = port;
+    return mGnss->updateConfiguration(config);
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/AGnss.h b/gps/android/2.1/AGnss.h
new file mode 100644
index 0000000..cf9c8a7
--- /dev/null
+++ b/gps/android/2.1/AGnss.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
+#define ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
+
+#include <android/hardware/gnss/2.0/IAGnss.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::hardware::gnss::V2_0::IAGnssCallback;
+
+struct Gnss;
+struct AGnss : public V2_0::IAGnss {
+
+    AGnss(Gnss* gnss);
+    ~AGnss();
+    /*
+     * Methods from ::android::hardware::gnss::V2_0::IAGnss interface follow.
+     * These declarations were generated from IAGnss.hal.
+     */
+    Return<void> setCallback(const sp<V2_0::IAGnssCallback>& callback) override;
+
+    Return<bool> dataConnClosed() override;
+
+    Return<bool> dataConnFailed() override;
+
+    Return<bool> dataConnOpen(uint64_t networkHandle, const hidl_string& apn,
+            V2_0::IAGnss::ApnIpType apnIpType) override;
+
+    Return<bool> setServer(V2_0::IAGnssCallback::AGnssType type,
+                         const hidl_string& hostname, int32_t port) override;
+
+    void statusCb(AGpsExtType type, LocAGpsStatusValue status);
+
+    /* Data call setup callback passed down to GNSS HAL implementation */
+    static void agnssStatusIpV4Cb(AGnssExtStatusIpV4 status);
+
+ private:
+    Gnss* mGnss = nullptr;
+    sp<V2_0::IAGnssCallback> mAGnssCbIface = nullptr;
+
+    AGpsExtType mType;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_AGNSS_H
diff --git a/gps/android/2.1/AGnssRil.cpp b/gps/android/2.1/AGnssRil.cpp
new file mode 100644
index 0000000..f413e93
--- /dev/null
+++ b/gps/android/2.1/AGnssRil.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc__AGnssRilInterface"
+
+#include <log_util.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sstream>
+#include <string>
+#include "Gnss.h"
+#include "AGnssRil.h"
+#include <DataItemConcreteTypesBase.h>
+
+typedef void* (getLocationInterface)();
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+
+AGnssRil::AGnssRil(Gnss* gnss) : mGnss(gnss) {
+    ENTRY_LOG_CALLFLOW();
+}
+
+AGnssRil::~AGnssRil() {
+    ENTRY_LOG_CALLFLOW();
+}
+
+Return<bool> AGnssRil::updateNetworkState(bool connected, NetworkType type, bool /*roaming*/) {
+    ENTRY_LOG_CALLFLOW();
+    // Extra NetworkTypes not available in IAgnssRil enums
+    const int NetworkType_BLUETOOTH = 7;
+    const int NetworkType_ETHERNET = 9;
+    const int NetworkType_PROXY = 16;
+    std::string apn("");
+
+    // for XTRA
+    if (nullptr != mGnss && ( nullptr != mGnss->getGnssInterface() )) {
+        int8_t typeout = loc_core::TYPE_UNKNOWN;
+        switch(type)
+        {
+            case IAGnssRil::NetworkType::MOBILE:
+                typeout = loc_core::TYPE_MOBILE;
+                break;
+            case IAGnssRil::NetworkType::WIFI:
+                typeout = loc_core::TYPE_WIFI;
+                break;
+            case IAGnssRil::NetworkType::MMS:
+                typeout = loc_core::TYPE_MMS;
+                break;
+            case IAGnssRil::NetworkType::SUPL:
+                typeout = loc_core::TYPE_SUPL;
+                break;
+            case IAGnssRil::NetworkType::DUN:
+                typeout = loc_core::TYPE_DUN;
+                break;
+            case IAGnssRil::NetworkType::HIPRI:
+                typeout = loc_core::TYPE_HIPRI;
+                break;
+            case IAGnssRil::NetworkType::WIMAX:
+                typeout = loc_core::TYPE_WIMAX;
+                break;
+            default:
+                {
+                    int networkType = (int) type;
+                    // Handling network types not available in IAgnssRil
+                    switch(networkType)
+                    {
+                        case NetworkType_BLUETOOTH:
+                            typeout = loc_core::TYPE_BLUETOOTH;
+                            break;
+                        case NetworkType_ETHERNET:
+                            typeout = loc_core::TYPE_ETHERNET;
+                            break;
+                        case NetworkType_PROXY:
+                            typeout = loc_core::TYPE_PROXY;
+                            break;
+                        default:
+                            typeout = loc_core::TYPE_UNKNOWN;
+                    }
+                }
+                break;
+        }
+        mGnss->getGnssInterface()->updateConnectionStatus(connected, typeout, false, 0, apn);
+    }
+    return true;
+}
+Return<bool> AGnssRil::updateNetworkState_2_0(const V2_0::IAGnssRil::NetworkAttributes& attributes) {
+    ENTRY_LOG_CALLFLOW();
+    std::string apn = attributes.apn;
+    if (nullptr != mGnss && (nullptr != mGnss->getGnssInterface())) {
+        int8_t typeout = loc_core::TYPE_UNKNOWN;
+        bool roaming = false;
+        if (attributes.capabilities & IAGnssRil::NetworkCapability::NOT_METERED) {
+            typeout = loc_core::TYPE_WIFI;
+        } else {
+            typeout = loc_core::TYPE_MOBILE;
+        }
+        if (attributes.capabilities & IAGnssRil::NetworkCapability::NOT_ROAMING) {
+            roaming = false;
+        }
+        LOC_LOGd("apn string received is: %s", apn.c_str());
+        mGnss->getGnssInterface()->updateConnectionStatus(attributes.isConnected,
+                typeout, roaming, (NetworkHandle) attributes.networkHandle, apn);
+    }
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/AGnssRil.h b/gps/android/2.1/AGnssRil.h
new file mode 100644
index 0000000..2bf6156
--- /dev/null
+++ b/gps/android/2.1/AGnssRil.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H_
+#define ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H_
+
+#include <android/hardware/gnss/2.0/IAGnssRil.h>
+#include <hidl/Status.h>
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+/*
+ * Extended interface for AGNSS RIL support. An Assisted GNSS Radio Interface Layer interface
+ * allows the GNSS chipset to request radio interface layer information from Android platform.
+ * Examples of such information are reference location, unique subscriber ID, phone number string
+ * and network availability changes. Also contains wrapper methods to allow methods from
+ * IAGnssiRilCallback interface to be passed into the conventional implementation of the GNSS HAL.
+ */
+struct AGnssRil : public V2_0::IAGnssRil {
+    AGnssRil(Gnss* gnss);
+    ~AGnssRil();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IAGnssRil follow.
+     * These declarations were generated from IAGnssRil.hal.
+     */
+    Return<void> setCallback(const sp<V1_0::IAGnssRilCallback>& /*callback*/) override {
+        return Void();
+    }
+    Return<void> setRefLocation(const V1_0::IAGnssRil::AGnssRefLocation& /*agnssReflocation*/) override {
+        return Void();
+    }
+    Return<bool> setSetId(V1_0::IAGnssRil::SetIDType /*type*/, const hidl_string& /*setid*/) override {
+        return false;
+    }
+    Return<bool> updateNetworkAvailability(bool /*available*/,
+                                    const hidl_string& /*apn*/) override {
+        return false;
+    }
+    Return<bool> updateNetworkState(bool connected, V1_0::IAGnssRil::NetworkType type, bool roaming) override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IAGnssRil follow
+    Return<bool> updateNetworkState_2_0(const V2_0::IAGnssRil::NetworkAttributes& attributes) override;
+
+ private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_AGNSSRIL_H_
diff --git a/gps/android/2.1/Android.mk b/gps/android/2.1/Android.mk
new file mode 100644
index 0000000..4be97a9
--- /dev/null
+++ b/gps/android/2.1/Android.mk
@@ -0,0 +1,115 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@2.1-impl-qti
+# activate the following line for debug purposes only, comment out for production
+#LOCAL_SANITIZE_DIAG += $(GNSS_SANITIZE_DIAG)
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+    AGnss.cpp \
+    Gnss.cpp \
+    AGnssRil.cpp \
+    GnssMeasurement.cpp \
+    GnssConfiguration.cpp \
+    GnssBatching.cpp \
+    GnssGeofencing.cpp \
+    GnssNi.cpp \
+    GnssDebug.cpp \
+    GnssAntennaInfo.cpp \
+    MeasurementCorrections.cpp \
+    GnssVisibilityControl.cpp
+
+LOCAL_SRC_FILES += \
+    location_api/GnssAPIClient.cpp \
+    location_api/MeasurementAPIClient.cpp \
+    location_api/GeofenceAPIClient.cpp \
+    location_api/BatchingAPIClient.cpp \
+    location_api/LocationUtil.cpp \
+
+ifeq ($(GNSS_HIDL_LEGACY_MEASURMENTS),true)
+LOCAL_CFLAGS += \
+     -DGNSS_HIDL_LEGACY_MEASURMENTS
+endif
+
+LOCAL_C_INCLUDES:= \
+    $(LOCAL_PATH)/location_api
+
+LOCAL_HEADER_LIBRARIES := \
+    libgps.utils_headers \
+    libloc_core_headers \
+    libloc_pla_headers \
+    liblocation_api_headers \
+    liblocbatterylistener_headers
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libhidlbase \
+    libcutils \
+    libutils \
+    android.hardware.gnss@1.0 \
+    android.hardware.gnss@1.1 \
+    android.hardware.gnss@2.0 \
+    android.hardware.gnss@2.1 \
+    android.hardware.gnss.measurement_corrections@1.0 \
+    android.hardware.gnss.measurement_corrections@1.1 \
+    android.hardware.gnss.visibility_control@1.0 \
+    android.hardware.health@1.0 \
+    android.hardware.health@2.0 \
+    android.hardware.health@2.1 \
+    android.hardware.power@1.2 \
+    libbase
+
+LOCAL_SHARED_LIBRARIES += \
+    libloc_core \
+    libgps.utils \
+    libdl \
+    liblocation_api \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := liblocbatterylistener
+LOCAL_STATIC_LIBRARIES += libhealthhalutils
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.gnss@2.1-service-qti
+
+# activate the following line for debug purposes only, comment out for production
+#LOCAL_SANITIZE_DIAG += $(GNSS_SANITIZE_DIAG)
+LOCAL_VINTF_FRAGMENTS := android.hardware.gnss@2.1-service-qti.xml
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_INIT_RC := android.hardware.gnss@2.1-service-qti.rc
+LOCAL_SRC_FILES := \
+    service.cpp \
+
+LOCAL_HEADER_LIBRARIES := \
+    libgps.utils_headers \
+    libloc_core_headers \
+    libloc_pla_headers \
+    liblocation_api_headers
+
+
+LOCAL_SHARED_LIBRARIES := \
+    liblog \
+    libcutils \
+    libdl \
+    libbase \
+    libutils \
+    libgps.utils \
+    libqti_vndfwk_detect \
+
+LOCAL_SHARED_LIBRARIES += \
+    libhidlbase \
+    android.hardware.gnss@1.0 \
+    android.hardware.gnss@1.1 \
+    android.hardware.gnss@2.0 \
+    android.hardware.gnss@2.1 \
+
+LOCAL_CFLAGS += $(GNSS_CFLAGS)
+
+ifneq ($(LOC_HIDL_VERSION),)
+LOCAL_CFLAGS += -DLOC_HIDL_VERSION='"$(LOC_HIDL_VERSION)"'
+endif
+
+include $(BUILD_EXECUTABLE)
diff --git a/gps/android/2.1/Gnss.cpp b/gps/android/2.1/Gnss.cpp
new file mode 100644
index 0000000..37e1cc5
--- /dev/null
+++ b/gps/android/2.1/Gnss.cpp
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssInterface"
+#define LOG_NDEBUG 0
+
+#include <fstream>
+#include <log_util.h>
+#include <dlfcn.h>
+#include <cutils/properties.h>
+#include "Gnss.h"
+#include "LocationUtil.h"
+#include "battery_listener.h"
+#include "loc_misc_utils.h"
+
+typedef const GnssInterface* (getLocationInterface)();
+
+#define IMAGES_INFO_FILE "/sys/devices/soc0/images"
+#define DELIMITER ";"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::visibility_control::V1_0::implementation::GnssVisibilityControl;
+using ::android::hardware::gnss::measurement_corrections::V1_1::
+        implementation::MeasurementCorrections;
+static sp<Gnss> sGnss;
+static std::string getVersionString() {
+    static std::string version;
+    if (!version.empty())
+        return version;
+
+    char value[PROPERTY_VALUE_MAX] = {0};
+    property_get("ro.hardware", value, "unknown");
+    version.append(value).append(DELIMITER);
+
+    std::ifstream in(IMAGES_INFO_FILE);
+    std::string s;
+    while(getline(in, s)) {
+        std::size_t found = s.find("CRM:");
+        if (std::string::npos == found) {
+            continue;
+        }
+
+        // skip over space characters after "CRM:"
+        const char* substr = s.c_str();
+        found += 4;
+        while (0 != substr[found] && isspace(substr[found])) {
+            found++;
+        }
+        if (s.find("11:") != found) {
+            continue;
+        }
+        s.erase(0, found + 3);
+
+        found = s.find_first_of("\r\n");
+        if (std::string::npos != found) {
+            s.erase(s.begin() + found, s.end());
+        }
+        version.append(s).append(DELIMITER);
+    }
+    return version;
+}
+
+void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnss != nullptr) {
+        mGnss->getGnssInterface()->resetNetworkInfo();
+        mGnss->cleanup();
+    }
+}
+
+void location_on_battery_status_changed(bool charging) {
+    LOC_LOGd("battery status changed to %s charging", charging ? "" : "not");
+    if (sGnss != nullptr) {
+        sGnss->getGnssInterface()->updateBatteryStatus(charging);
+    }
+}
+Gnss::Gnss() {
+    ENTRY_LOG_CALLFLOW();
+    sGnss = this;
+    // initilize gnss interface at first in case needing notify battery status
+    sGnss->getGnssInterface()->initialize();
+    // register health client to listen on battery change
+    loc_extn_battery_properties_listener_init(location_on_battery_status_changed);
+    // clear pending GnssConfig
+    memset(&mPendingConfig, 0, sizeof(GnssConfig));
+    mGnssDeathRecipient = new GnssDeathRecipient(this);
+}
+
+Gnss::~Gnss() {
+    ENTRY_LOG_CALLFLOW();
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+    sGnss = nullptr;
+}
+
+GnssAPIClient* Gnss::getApi() {
+    if (mApi != nullptr) {
+        return mApi;
+    }
+
+    if (mGnssCbIface_2_1 != nullptr) {
+        mApi = new GnssAPIClient(mGnssCbIface_2_1);
+    } else if (mGnssCbIface_2_0 != nullptr) {
+        mApi = new GnssAPIClient(mGnssCbIface_2_0);
+    } else if (mGnssCbIface_1_1 != nullptr) {
+        mApi = new GnssAPIClient(mGnssCbIface_1_1, mGnssNiCbIface);
+    } else if (mGnssCbIface != nullptr) {
+        mApi = new GnssAPIClient(mGnssCbIface, mGnssNiCbIface);
+    } else {
+        LOC_LOGW("%s] GnssAPIClient is not ready", __FUNCTION__);
+        return mApi;
+    }
+
+    if (mPendingConfig.size == sizeof(GnssConfig)) {
+        // we have pending GnssConfig
+        mApi->gnssConfigurationUpdate(mPendingConfig);
+        // clear size to invalid mPendingConfig
+        mPendingConfig.size = 0;
+        if (mPendingConfig.assistanceServer.hostName != nullptr) {
+            free((void*)mPendingConfig.assistanceServer.hostName);
+        }
+    }
+
+    return mApi;
+}
+
+const GnssInterface* Gnss::getGnssInterface() {
+    static bool getGnssInterfaceFailed = false;
+    if (mGnssInterface == nullptr && !getGnssInterfaceFailed) {
+        void * libHandle = nullptr;
+        getLocationInterface* getter = (getLocationInterface*)
+                dlGetSymFromLib(libHandle, "libgnss.so", "getGnssInterface");
+        if (NULL == getter) {
+            getGnssInterfaceFailed = true;
+        } else {
+            mGnssInterface = (GnssInterface*)(*getter)();
+        }
+    }
+    return mGnssInterface;
+}
+
+Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback)  {
+    ENTRY_LOG_CALLFLOW();
+
+    // In case where previous call to setCallback_1_1/setCallback_2_0/setCallback_2_1, then
+    // we need to cleanup these interfaces/callbacks here since we no longer
+    // do so in cleanup() function to keep callbacks around after cleanup()
+    if (mApi != nullptr) {
+        mApi->gnssUpdateCallbacks_2_0(nullptr);
+        mApi->gnssUpdateCallbacks_2_1(nullptr);
+    }
+    if (mGnssCbIface_1_1 != nullptr) {
+        mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_1_1 = nullptr;
+    }
+    if (mGnssCbIface_2_0 != nullptr) {
+        mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_2_0 = nullptr;
+    }
+    if (mGnssCbIface_2_1 != nullptr) {
+        mGnssCbIface_2_1->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_2_1 = nullptr;
+    }
+
+
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+    }
+    mGnssCbIface = callback;
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+    }
+
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+        api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
+    }
+    return true;
+}
+
+Return<bool> Gnss::setGnssNiCb(const sp<IGnssNiCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    mGnssNiCbIface = callback;
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface);
+    }
+    return true;
+}
+
+Return<bool> Gnss::updateConfiguration(GnssConfig& gnssConfig) {
+    ENTRY_LOG_CALLFLOW();
+    GnssAPIClient* api = getApi();
+    if (api) {
+        api->gnssConfigurationUpdate(gnssConfig);
+    } else if (gnssConfig.flags != 0) {
+        // api is not ready yet, update mPendingConfig with gnssConfig
+        mPendingConfig.size = sizeof(GnssConfig);
+
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+            mPendingConfig.gpsLock = gnssConfig.gpsLock;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+            mPendingConfig.suplVersion = gnssConfig.suplVersion;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT;
+            mPendingConfig.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer);
+            mPendingConfig.assistanceServer.type = gnssConfig.assistanceServer.type;
+            if (mPendingConfig.assistanceServer.hostName != nullptr) {
+                free((void*)mPendingConfig.assistanceServer.hostName);
+                mPendingConfig.assistanceServer.hostName =
+                    strdup(gnssConfig.assistanceServer.hostName);
+            }
+            mPendingConfig.assistanceServer.port = gnssConfig.assistanceServer.port;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+            mPendingConfig.lppProfileMask = gnssConfig.lppProfileMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT;
+            mPendingConfig.lppeControlPlaneMask = gnssConfig.lppeControlPlaneMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT;
+            mPendingConfig.lppeUserPlaneMask = gnssConfig.lppeUserPlaneMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+            mPendingConfig.aGlonassPositionProtocolMask = gnssConfig.aGlonassPositionProtocolMask;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+            mPendingConfig.emergencyPdnForEmergencySupl = gnssConfig.emergencyPdnForEmergencySupl;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT;
+            mPendingConfig.suplEmergencyServices = gnssConfig.suplEmergencyServices;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+            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;
+        }
+        if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) {
+            mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT;
+            mPendingConfig.emergencyExtensionSeconds = gnssConfig.emergencyExtensionSeconds;
+        }
+    }
+    return true;
+}
+
+Return<bool> Gnss::start()  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssStart();
+    }
+    return retVal;
+}
+
+Return<bool> Gnss::stop()  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssStop();
+    }
+    return retVal;
+}
+
+Return<void> Gnss::cleanup()  {
+    ENTRY_LOG_CALLFLOW();
+
+    if (mApi != nullptr) {
+        mApi->gnssStop();
+        mApi->gnssDisable();
+    }
+
+    return Void();
+}
+
+Return<bool> Gnss::injectLocation(double latitudeDegrees,
+                                  double longitudeDegrees,
+                                  float accuracyMeters)  {
+    ENTRY_LOG_CALLFLOW();
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        gnssInterface->injectLocation(latitudeDegrees, longitudeDegrees, accuracyMeters);
+        return true;
+    } else {
+        return false;
+    }
+}
+
+Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs,
+                              int32_t uncertaintyMs) {
+    return true;
+}
+
+Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags)  {
+    ENTRY_LOG_CALLFLOW();
+    GnssAPIClient* api = getApi();
+    if (api) {
+        api->gnssDeleteAidingData(aidingDataFlags);
+    }
+    return Void();
+}
+
+Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                   V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                   uint32_t minIntervalMs,
+                                   uint32_t preferredAccuracyMeters,
+                                   uint32_t preferredTimeMs)  {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+                preferredAccuracyMeters, preferredTimeMs);
+    }
+    return retVal;
+}
+
+Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss()  {
+    ENTRY_LOG_CALLFLOW();
+    // deprecated function. Must return nullptr to pass VTS
+    return nullptr;
+}
+
+Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi()  {
+    ENTRY_LOG_CALLFLOW();
+    // deprecated function. Must return nullptr to pass VTS
+    return nullptr;
+}
+
+Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssMeasurement == nullptr) {
+        mGnssMeasurement = new GnssMeasurement();
+    }
+    return mGnssMeasurement;
+}
+
+Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration()  {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssConfig == nullptr) {
+        mGnssConfig = new GnssConfiguration(this);
+    }
+    return mGnssConfig;
+}
+
+Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing()  {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssGeofencingIface == nullptr) {
+        mGnssGeofencingIface = new GnssGeofencing();
+    }
+    return mGnssGeofencingIface;
+}
+
+Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching()  {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssBatching == nullptr) {
+        mGnssBatching = new GnssBatching();
+    }
+    return mGnssBatching;
+}
+
+Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssDebug == nullptr) {
+        mGnssDebug = new GnssDebug(this);
+    }
+    return mGnssDebug;
+}
+
+Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssRil == nullptr) {
+        mGnssRil = new AGnssRil(this);
+    }
+    return mGnssRil;
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+Return<bool> Gnss::setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    auto r = callback->gnssNameCb(getVersionString());
+    if (!r.isOk()) {
+        LOC_LOGE("%s] Error from gnssNameCb description=%s",
+                __func__, r.description().c_str());
+    }
+
+    // In case where previous call to setCallback/setCallback_2_0/setCallback_2_1, then
+    // we need to cleanup these interfaces/callbacks here since we no longer
+    // do so in cleanup() function to keep callbacks around after cleanup()
+    if (mApi != nullptr) {
+        mApi->gnssUpdateCallbacks_2_0(nullptr);
+        mApi->gnssUpdateCallbacks_2_1(nullptr);
+    }
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface = nullptr;
+    }
+    if (mGnssCbIface_2_0 != nullptr) {
+        mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_2_0 = nullptr;
+    }
+    if (mGnssCbIface_2_1 != nullptr) {
+        mGnssCbIface_2_1->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_2_1 = nullptr;
+    }
+
+
+    if (mGnssCbIface_1_1 != nullptr) {
+        mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+    }
+    mGnssCbIface_1_1 = callback;
+    if (mGnssCbIface_1_1 != nullptr) {
+        mGnssCbIface_1_1->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+    }
+
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        OdcpiRequestCallback cb = [this](const OdcpiRequestInfo& odcpiRequest) {
+            odcpiRequestCb(odcpiRequest);
+        };
+        gnssInterface->odcpiInit(cb, OdcpiPrioritytype::ODCPI_HANDLER_PRIORITY_LOW);
+    }
+
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks(mGnssCbIface_1_1, mGnssNiCbIface);
+        api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
+    }
+
+    return true;
+}
+
+Return<bool> Gnss::setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+        V1_0::IGnss::GnssPositionRecurrence recurrence,
+        uint32_t minIntervalMs,
+        uint32_t preferredAccuracyMeters,
+        uint32_t preferredTimeMs,
+        bool lowPowerMode) {
+    ENTRY_LOG_CALLFLOW();
+    bool retVal = false;
+    GnssAPIClient* api = getApi();
+    if (api) {
+        GnssPowerMode powerMode = lowPowerMode?
+                GNSS_POWER_MODE_M4 : GNSS_POWER_MODE_M2;
+        retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs,
+                preferredAccuracyMeters, preferredTimeMs, powerMode, minIntervalMs);
+    }
+    return retVal;
+}
+
+Return<sp<V1_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_1_1() {
+    ENTRY_LOG_CALLFLOW();
+#ifdef GNSS_HIDL_LEGACY_MEASURMENTS
+    return nullptr;
+#else
+    if (mGnssMeasurement == nullptr)
+        mGnssMeasurement = new GnssMeasurement();
+    return mGnssMeasurement;
+#endif
+}
+
+Return<sp<V1_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_1_1() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssConfig == nullptr)
+        mGnssConfig = new GnssConfiguration(this);
+    return mGnssConfig;
+}
+
+Return<bool> Gnss::injectBestLocation(const GnssLocation& gnssLocation) {
+    ENTRY_LOG_CALLFLOW();
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        Location location = {};
+        convertGnssLocation(gnssLocation, location);
+        gnssInterface->odcpiInject(location);
+    }
+    return true;
+}
+
+void Gnss::odcpiRequestCb(const OdcpiRequestInfo& request) {
+    ENTRY_LOG_CALLFLOW();
+    if (ODCPI_REQUEST_TYPE_STOP == request.type) {
+        return;
+    }
+    if (mGnssCbIface_2_1 != nullptr) {
+        // For emergency mode, request DBH (Device based hybrid) location
+        // Mark Independent from GNSS flag to false.
+        if (ODCPI_REQUEST_TYPE_START == request.type) {
+            LOC_LOGd("gnssRequestLocationCb_2_1 isUserEmergency = %d", request.isEmergencyMode);
+            auto r = mGnssCbIface_2_1->gnssRequestLocationCb_2_0(!request.isEmergencyMode,
+                                                                 request.isEmergencyMode);
+            if (!r.isOk()) {
+                LOC_LOGe("Error invoking gnssRequestLocationCb_2_0 %s", r.description().c_str());
+            }
+        } else {
+            LOC_LOGv("Unsupported ODCPI request type: %d", request.type);
+        }
+    } else if (mGnssCbIface_2_0 != nullptr) {
+        // For emergency mode, request DBH (Device based hybrid) location
+        // Mark Independent from GNSS flag to false.
+        if (ODCPI_REQUEST_TYPE_START == request.type) {
+            LOC_LOGd("gnssRequestLocationCb_2_0 isUserEmergency = %d", request.isEmergencyMode);
+            auto r = mGnssCbIface_2_0->gnssRequestLocationCb_2_0(!request.isEmergencyMode,
+                                                                 request.isEmergencyMode);
+            if (!r.isOk()) {
+                LOC_LOGe("Error invoking gnssRequestLocationCb_2_0 %s", r.description().c_str());
+            }
+        } else {
+            LOC_LOGv("Unsupported ODCPI request type: %d", request.type);
+        }
+    } else if (mGnssCbIface_1_1 != nullptr) {
+        // For emergency mode, request DBH (Device based hybrid) location
+        // Mark Independent from GNSS flag to false.
+        if (ODCPI_REQUEST_TYPE_START == request.type) {
+            auto r = mGnssCbIface_1_1->gnssRequestLocationCb(!request.isEmergencyMode);
+            if (!r.isOk()) {
+                LOC_LOGe("Error invoking gnssRequestLocationCb %s", r.description().c_str());
+            }
+        } else {
+            LOC_LOGv("Unsupported ODCPI request type: %d", request.type);
+        }
+    } else {
+        LOC_LOGe("ODCPI request not supported.");
+    }
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnss follow.
+Return<bool> Gnss::setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    auto r = callback->gnssNameCb(getVersionString());
+    if (!r.isOk()) {
+        LOC_LOGE("%s] Error from gnssNameCb description=%s",
+                __func__, r.description().c_str());
+    }
+
+    // In case where previous call to setCallback/setCallback_1_1/setCallback_2_1, then
+    // we need to cleanup these interfaces/callbacks here since we no longer
+    // do so in cleanup() function to keep callbacks around after cleanup()
+    if (mApi != nullptr) {
+        mApi->gnssUpdateCallbacks(nullptr, nullptr);
+        mApi->gnssUpdateCallbacks_2_1(nullptr);
+    }
+    mGnssNiCbIface = nullptr;
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface = nullptr;
+    }
+    if (mGnssCbIface_1_1 != nullptr) {
+        mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_1_1 = nullptr;
+    }
+    if (mGnssCbIface_2_1 != nullptr) {
+        mGnssCbIface_2_1->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_2_1 = nullptr;
+    }
+
+
+    if (mGnssCbIface_2_0 != nullptr) {
+        mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+    }
+    mGnssCbIface_2_0 = callback;
+    if (mGnssCbIface_2_0 != nullptr) {
+        mGnssCbIface_2_0->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+    }
+
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        OdcpiRequestCallback cb = [this](const OdcpiRequestInfo& odcpiRequest) {
+            odcpiRequestCb(odcpiRequest);
+        };
+        gnssInterface->odcpiInit(cb, OdcpiPrioritytype::ODCPI_HANDLER_PRIORITY_LOW);
+    }
+
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks_2_0(mGnssCbIface_2_0);
+        api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
+    }
+
+    return true;
+}
+
+Return<sp<V2_0::IAGnss>> Gnss::getExtensionAGnss_2_0() {
+    ENTRY_LOG_CALLFLOW();
+    if (mAGnssIface_2_0 == nullptr) {
+        mAGnssIface_2_0 = new AGnss(this);
+    }
+    return mAGnssIface_2_0;
+}
+Return<sp<V2_0::IAGnssRil>> Gnss::getExtensionAGnssRil_2_0() {
+
+    if (mGnssRil == nullptr) {
+        mGnssRil = new AGnssRil(this);
+    }
+    return mGnssRil;
+}
+
+Return<sp<V2_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_0() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssConfig == nullptr) {
+        mGnssConfig = new GnssConfiguration(this);
+    }
+    return mGnssConfig;
+}
+Return<sp<V2_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_0() {
+    ENTRY_LOG_CALLFLOW();
+#ifdef GNSS_HIDL_LEGACY_MEASURMENTS
+    return nullptr;
+#else
+    if (mGnssMeasurement == nullptr)
+        mGnssMeasurement = new GnssMeasurement();
+    return mGnssMeasurement;
+#endif
+}
+
+Return<sp<IMeasurementCorrectionsV1_0>>
+        Gnss::getExtensionMeasurementCorrections() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssMeasCorr == nullptr) {
+        mGnssMeasCorr = new MeasurementCorrections(this);
+    }
+    return mGnssMeasCorr;
+}
+
+Return<sp<IMeasurementCorrectionsV1_1>>
+        Gnss::getExtensionMeasurementCorrections_1_1() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssMeasCorr == nullptr) {
+        mGnssMeasCorr = new MeasurementCorrections(this);
+    }
+    return mGnssMeasCorr;
+}
+
+Return<sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl>>
+        Gnss::getExtensionVisibilityControl() {
+    ENTRY_LOG_CALLFLOW();
+    if (mVisibCtrl == nullptr) {
+        mVisibCtrl = new GnssVisibilityControl(this);
+    }
+    return mVisibCtrl;
+}
+
+Return<bool> Gnss::injectBestLocation_2_0(const V2_0::GnssLocation& gnssLocation) {
+    ENTRY_LOG_CALLFLOW();
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (nullptr != gnssInterface) {
+        Location location = {};
+        convertGnssLocation(gnssLocation, location);
+        gnssInterface->odcpiInject(location);
+    }
+    return true;
+}
+
+Return<sp<V2_0::IGnssDebug>> Gnss::getExtensionGnssDebug_2_0() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssDebug == nullptr) {
+        mGnssDebug = new GnssDebug(this);
+    }
+    return mGnssDebug;
+}
+
+Return<sp<V2_0::IGnssBatching>> Gnss::getExtensionGnssBatching_2_0() {
+    return nullptr;
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnss follow.
+Return<bool> Gnss::setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) {
+    ENTRY_LOG_CALLFLOW();
+    auto r = callback->gnssNameCb(getVersionString());
+    if (!r.isOk()) {
+        LOC_LOGE("%s] Error from gnssNameCb description=%s",
+                __func__, r.description().c_str());
+    }
+
+    // In case where previous call to setCallback/setCallback_1_1/setCallback_2_0, then
+    // we need to cleanup these interfaces/callbacks here since we no longer
+    // do so in cleanup() function to keep callbacks around after cleanup()
+    if (mApi != nullptr) {
+        mApi->gnssUpdateCallbacks(nullptr, nullptr);
+        mApi->gnssUpdateCallbacks_2_0(nullptr);
+    }
+    mGnssNiCbIface = nullptr;
+    if (mGnssCbIface != nullptr) {
+        mGnssCbIface->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface = nullptr;
+    }
+    if (mGnssCbIface_1_1 != nullptr) {
+        mGnssCbIface_1_1->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_1_1 = nullptr;
+    }
+    if (mGnssCbIface_2_0 != nullptr) {
+        mGnssCbIface_2_0->unlinkToDeath(mGnssDeathRecipient);
+        mGnssCbIface_2_0 = nullptr;
+    }
+    if (mGnssCbIface_2_1 != nullptr) {
+        mGnssCbIface_2_1->unlinkToDeath(mGnssDeathRecipient);
+    }
+    mGnssCbIface_2_1 = callback;
+    if (mGnssCbIface_2_1 != nullptr) {
+        mGnssCbIface_2_1->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/);
+    }
+
+    const GnssInterface* gnssInterface = getGnssInterface();
+    if (gnssInterface != nullptr) {
+        OdcpiRequestCallback cb = [this](const OdcpiRequestInfo& odcpiRequest) {
+            odcpiRequestCb(odcpiRequest);
+        };
+        gnssInterface->odcpiInit(cb, OdcpiPrioritytype::ODCPI_HANDLER_PRIORITY_LOW);
+    }
+
+    GnssAPIClient* api = getApi();
+    if (api != nullptr) {
+        api->gnssUpdateCallbacks_2_1(mGnssCbIface_2_1);
+        api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS);
+        api->requestCapabilities();
+    }
+
+    return true;
+}
+Return<sp<V2_1::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement_2_1() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssMeasurement == nullptr) {
+        mGnssMeasurement = new GnssMeasurement();
+    }
+    return mGnssMeasurement;
+}
+Return<sp<V2_1::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration_2_1() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssConfig == nullptr) {
+        mGnssConfig = new GnssConfiguration(this);
+    }
+    return mGnssConfig;
+}
+
+Return<sp<V2_1::IGnssAntennaInfo>> Gnss::getExtensionGnssAntennaInfo() {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnssAntennaInfo == nullptr) {
+        mGnssAntennaInfo = new GnssAntennaInfo(this);
+    }
+    return mGnssAntennaInfo;
+}
+
+V1_0::IGnss* HIDL_FETCH_IGnss(const char* hal) {
+    ENTRY_LOG_CALLFLOW();
+    V1_0::IGnss* iface = nullptr;
+    iface = new Gnss();
+    if (iface == nullptr) {
+        LOC_LOGE("%s]: failed to get %s", __FUNCTION__, hal);
+    }
+    return iface;
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/Gnss.h b/gps/android/2.1/Gnss.h
new file mode 100644
index 0000000..c383882
--- /dev/null
+++ b/gps/android/2.1/Gnss.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSS_H
+#define ANDROID_HARDWARE_GNSS_V2_1_GNSS_H
+
+#include <AGnss.h>
+#include <AGnssRil.h>
+#include <GnssConfiguration.h>
+#include <GnssMeasurement.h>
+#include <GnssBatching.h>
+#include <GnssGeofencing.h>
+#include <GnssNi.h>
+#include <GnssDebug.h>
+#include <GnssAntennaInfo.h>
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
+#include <MeasurementCorrections.h>
+#include <GnssVisibilityControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include "GnssAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using IMeasurementCorrectionsV1_0 =
+        ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using IMeasurementCorrectionsV1_1 =
+        ::android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections;
+using ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
+
+struct Gnss : public IGnss {
+    Gnss();
+    ~Gnss();
+
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnss follow.
+     * These declarations were generated from Gnss.hal.
+     */
+    Return<bool> setCallback(const sp<V1_0::IGnssCallback>& callback)  override;
+    Return<bool> start()  override;
+    Return<bool> stop()  override;
+    Return<void> cleanup()  override;
+    Return<bool> injectLocation(double latitudeDegrees,
+                                double longitudeDegrees,
+                                float accuracyMeters)  override;
+    Return<bool> injectTime(int64_t timeMs,
+                            int64_t timeReferenceMs,
+                            int32_t uncertaintyMs) override;
+    Return<void> deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags)  override;
+    Return<bool> setPositionMode(V1_0::IGnss::GnssPositionMode mode,
+                                 V1_0::IGnss::GnssPositionRecurrence recurrence,
+                                 uint32_t minIntervalMs,
+                                 uint32_t preferredAccuracyMeters,
+                                 uint32_t preferredTimeMs)  override;
+    Return<sp<V1_0::IAGnss>> getExtensionAGnss() override;
+    Return<sp<V1_0::IGnssNi>> getExtensionGnssNi() override;
+    Return<sp<V1_0::IGnssMeasurement>> getExtensionGnssMeasurement() override;
+    Return<sp<V1_0::IGnssConfiguration>> getExtensionGnssConfiguration() override;
+    Return<sp<V1_0::IGnssGeofencing>> getExtensionGnssGeofencing() override;
+    Return<sp<V1_0::IGnssBatching>> getExtensionGnssBatching() override;
+
+    Return<sp<V1_0::IAGnssRil>> getExtensionAGnssRil() override;
+
+    inline Return<sp<V1_0::IGnssNavigationMessage>> getExtensionGnssNavigationMessage() override {
+        return nullptr;
+    }
+
+    inline Return<sp<V1_0::IGnssXtra>> getExtensionXtra() override {
+        return nullptr;
+    }
+
+    Return<sp<V1_0::IGnssDebug>> getExtensionGnssDebug() override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnss follow.
+    Return<bool> setCallback_1_1(const sp<V1_1::IGnssCallback>& callback) override;
+    Return<bool> setPositionMode_1_1(V1_0::IGnss::GnssPositionMode mode,
+            V1_0::IGnss::GnssPositionRecurrence recurrence,
+            uint32_t minIntervalMs, uint32_t preferredAccuracyMeters,
+            uint32_t preferredTimeMs, bool lowPowerMode) override;
+    Return<sp<V1_1::IGnssMeasurement>> getExtensionGnssMeasurement_1_1() override;
+    Return<sp<V1_1::IGnssConfiguration>> getExtensionGnssConfiguration_1_1() override;
+    Return<bool> injectBestLocation(const GnssLocation& location) override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IGnss follow.
+    Return<bool> setCallback_2_0(const sp<V2_0::IGnssCallback>& callback) override;
+    Return<sp<V2_0::IAGnss>> getExtensionAGnss_2_0() override;
+    Return<sp<V2_0::IAGnssRil>> getExtensionAGnssRil_2_0() override;
+
+    Return<sp<V2_0::IGnssConfiguration>> getExtensionGnssConfiguration_2_0() override;
+    Return<sp<IMeasurementCorrectionsV1_0>> getExtensionMeasurementCorrections() override;
+    Return<sp<IMeasurementCorrectionsV1_1>> getExtensionMeasurementCorrections_1_1() override;
+    Return<sp<V2_0::IGnssMeasurement>> getExtensionGnssMeasurement_2_0() override;
+
+    Return<bool> injectBestLocation_2_0(
+            const ::android::hardware::gnss::V2_0::GnssLocation& location) override;
+
+    Return<sp<V2_0::IGnssBatching>> getExtensionGnssBatching_2_0() override;
+    Return<sp<V2_0::IGnssDebug>> getExtensionGnssDebug_2_0() override;
+    Return<sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl>>
+            getExtensionVisibilityControl() override;
+
+    // Methods from ::android::hardware::gnss::V2_1::IGnss follow.
+    Return<bool> setCallback_2_1(const sp<V2_1::IGnssCallback>& callback) override;
+    Return<sp<V2_1::IGnssMeasurement>> getExtensionGnssMeasurement_2_1() override;
+    Return<sp<V2_1::IGnssConfiguration>> getExtensionGnssConfiguration_2_1() override;
+    Return<sp<V2_1::IGnssAntennaInfo>> getExtensionGnssAntennaInfo() override;
+
+    // These methods are not part of the IGnss base class.
+    GnssAPIClient* getApi();
+    Return<bool> setGnssNiCb(const sp<IGnssNiCallback>& niCb);
+    Return<bool> updateConfiguration(GnssConfig& gnssConfig);
+    const GnssInterface* getGnssInterface();
+
+    // Callback for ODCPI request
+    void odcpiRequestCb(const OdcpiRequestInfo& request);
+
+ private:
+    struct GnssDeathRecipient : hidl_death_recipient {
+        GnssDeathRecipient(sp<Gnss> gnss) : mGnss(gnss) {
+        }
+        ~GnssDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<Gnss> mGnss;
+    };
+
+ private:
+    sp<GnssDeathRecipient> mGnssDeathRecipient = nullptr;
+
+    sp<V1_0::IGnssNi> mGnssNi = nullptr;
+    sp<V1_0::IGnssGeofencing> mGnssGeofencingIface = nullptr;
+    sp<V1_0::IAGnss> mAGnssIface = nullptr;
+    sp<V1_0::IGnssCallback> mGnssCbIface = nullptr;
+    sp<V1_0::IGnssNiCallback> mGnssNiCbIface = nullptr;
+    sp<V1_1::IGnssCallback> mGnssCbIface_1_1 = nullptr;
+    sp<V2_0::IAGnss> mAGnssIface_2_0 = nullptr;
+    sp<V2_0::IAGnssRil> mGnssRil = nullptr;
+    sp<V2_0::IGnssBatching> mGnssBatching = nullptr;
+    sp<V2_0::IGnssDebug> mGnssDebug = nullptr;
+    sp<V2_0::IGnssCallback> mGnssCbIface_2_0 = nullptr;
+    sp<V2_1::IGnssCallback> mGnssCbIface_2_1 = nullptr;
+    sp<V2_1::IGnssMeasurement> mGnssMeasurement = nullptr;
+    sp<V2_1::IGnssConfiguration> mGnssConfig = nullptr;
+    sp<V2_1::IGnssAntennaInfo> mGnssAntennaInfo = nullptr;
+    sp<IMeasurementCorrectionsV1_1> mGnssMeasCorr = nullptr;
+    sp<IGnssVisibilityControl> mVisibCtrl = nullptr;
+
+    GnssAPIClient* mApi = nullptr;
+    GnssConfig mPendingConfig;
+    const GnssInterface* mGnssInterface = nullptr;
+};
+
+extern "C" V1_0::IGnss* HIDL_FETCH_IGnss(const char* name);
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSS_H
diff --git a/gps/android/2.1/GnssAntennaInfo.cpp b/gps/android/2.1/GnssAntennaInfo.cpp
new file mode 100644
index 0000000..62c4cc7
--- /dev/null
+++ b/gps/android/2.1/GnssAntennaInfo.cpp
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define LOG_TAG "LocSvc_GnssAntennaInfoInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssAntennaInfo.h"
+#include <android/hardware/gnss/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+static GnssAntennaInfo* spGnssAntennaInfo = nullptr;
+
+static void convertGnssAntennaInfo(std::vector<GnssAntennaInformation>& in,
+        hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfos);
+
+void GnssAntennaInfo::GnssAntennaInfoDeathRecipient::serviceDied(uint64_t cookie,
+                                                                 const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    // we do nothing here
+    // Gnss::GnssDeathRecipient will stop the session
+    // However, we need to inform the adapter that the service has died
+    if (nullptr == spGnssAntennaInfo) {
+        LOC_LOGE("%s]: spGnssAntennaInfo is nullptr", __FUNCTION__);
+        return;
+    }
+    if (nullptr == spGnssAntennaInfo->mGnss) {
+        LOC_LOGE("%s]: spGnssAntennaInfo->mGnss is nullptr", __FUNCTION__);
+        return;
+    }
+
+    spGnssAntennaInfo->mGnss->getGnssInterface()->antennaInfoClose();
+}
+
+static void convertGnssAntennaInfo(std::vector<GnssAntennaInformation>& in,
+        hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& out) {
+
+    uint32_t vecSize, numberOfRows, numberOfColumns;
+    vecSize = in.size();
+    out.resize(vecSize);
+    for (uint32_t i = 0; i < vecSize; i++) {
+        out[i].carrierFrequencyMHz = in[i].carrierFrequencyMHz;
+        out[i].phaseCenterOffsetCoordinateMillimeters.x =
+                in[i].phaseCenterOffsetCoordinateMillimeters.x;
+        out[i].phaseCenterOffsetCoordinateMillimeters.xUncertainty =
+                in[i].phaseCenterOffsetCoordinateMillimeters.xUncertainty;
+        out[i].phaseCenterOffsetCoordinateMillimeters.y =
+                in[i].phaseCenterOffsetCoordinateMillimeters.y;
+        out[i].phaseCenterOffsetCoordinateMillimeters.yUncertainty =
+                in[i].phaseCenterOffsetCoordinateMillimeters.yUncertainty;
+        out[i].phaseCenterOffsetCoordinateMillimeters.z =
+                in[i].phaseCenterOffsetCoordinateMillimeters.z;
+        out[i].phaseCenterOffsetCoordinateMillimeters.zUncertainty =
+                in[i].phaseCenterOffsetCoordinateMillimeters.zUncertainty;
+
+        numberOfRows = in[i].phaseCenterVariationCorrectionMillimeters.size();
+        out[i].phaseCenterVariationCorrectionMillimeters.resize(numberOfRows);
+        for (uint32_t j = 0; j < numberOfRows; j++) {
+            numberOfColumns = in[i].phaseCenterVariationCorrectionMillimeters[j].size();
+            out[i].phaseCenterVariationCorrectionMillimeters[j].row.resize(numberOfColumns);
+            for (uint32_t k = 0; k < numberOfColumns; k++) {
+                out[i].phaseCenterVariationCorrectionMillimeters[j].row[k] =
+                        in[i].phaseCenterVariationCorrectionMillimeters[j][k];
+            }
+        }
+
+        numberOfRows = in[i].phaseCenterVariationCorrectionUncertaintyMillimeters.size();
+        out[i].phaseCenterVariationCorrectionUncertaintyMillimeters.resize(numberOfRows);
+        for (uint32_t j = 0; j < numberOfRows; j++) {
+            numberOfColumns = in[i].phaseCenterVariationCorrectionUncertaintyMillimeters[j].size();
+            out[i].phaseCenterVariationCorrectionUncertaintyMillimeters[j].
+                    row.resize(numberOfColumns);
+            for (uint32_t k = 0; k < numberOfColumns; k++) {
+                out[i].phaseCenterVariationCorrectionUncertaintyMillimeters[j].row[k] =
+                        in[i].phaseCenterVariationCorrectionUncertaintyMillimeters[j][k];
+            }
+        }
+
+        numberOfRows = in[i].signalGainCorrectionDbi.size();
+        out[i].signalGainCorrectionDbi.resize(numberOfRows);
+        for (uint32_t j = 0; j < numberOfRows; j++) {
+            numberOfColumns = in[i].signalGainCorrectionDbi[j].size();
+            out[i].signalGainCorrectionDbi[j].row.resize(numberOfColumns);
+            for (uint32_t k = 0; k < numberOfColumns; k++) {
+                out[i].signalGainCorrectionDbi[j].row[k] = in[i].signalGainCorrectionDbi[j][k];
+            }
+        }
+
+        numberOfRows = in[i].signalGainCorrectionUncertaintyDbi.size();
+        out[i].signalGainCorrectionUncertaintyDbi.resize(numberOfRows);
+        for (uint32_t j = 0; j < numberOfRows; j++) {
+            numberOfColumns = in[i].signalGainCorrectionUncertaintyDbi[j].size();
+            out[i].signalGainCorrectionUncertaintyDbi[j].row.resize(numberOfColumns);
+            for (uint32_t k = 0; k < numberOfColumns; k++) {
+                out[i].signalGainCorrectionUncertaintyDbi[j].row[k] =
+                        in[i].signalGainCorrectionUncertaintyDbi[j][k];
+            }
+        }
+    }
+}
+
+GnssAntennaInfo::GnssAntennaInfo(Gnss* gnss) : mGnss(gnss) {
+    mGnssAntennaInfoDeathRecipient = new GnssAntennaInfoDeathRecipient(this);
+    spGnssAntennaInfo = this;
+}
+
+GnssAntennaInfo::~GnssAntennaInfo() {
+    spGnssAntennaInfo = nullptr;
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnssAntennaInfo follow.
+Return<GnssAntennaInfo::GnssAntennaInfoStatus>
+        GnssAntennaInfo::setCallback(const sp<IGnssAntennaInfoCallback>& callback)  {
+    uint32_t retValue;
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return GnssAntennaInfoStatus::ERROR_GENERIC;
+    }
+
+    mGnssAntennaInfoCbIface = callback;
+    retValue = mGnss->getGnssInterface()->antennaInfoInit(aiGnssAntennaInfoCb);
+
+    switch (retValue) {
+    case ANTENNA_INFO_SUCCESS: return GnssAntennaInfoStatus::SUCCESS;
+    case ANTENNA_INFO_ERROR_ALREADY_INIT: return GnssAntennaInfoStatus::ERROR_ALREADY_INIT;
+    case ANTENNA_INFO_ERROR_GENERIC:
+    default: return GnssAntennaInfoStatus::ERROR_GENERIC;
+    }
+}
+
+Return<void> GnssAntennaInfo::close(void)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    mGnss->getGnssInterface()->antennaInfoClose();
+
+    return Void();
+}
+
+void GnssAntennaInfo::aiGnssAntennaInfoCb
+        (std::vector<GnssAntennaInformation> gnssAntennaInformations) {
+    if (nullptr != spGnssAntennaInfo) {
+        spGnssAntennaInfo->gnssAntennaInfoCb(gnssAntennaInformations);
+    }
+}
+
+void GnssAntennaInfo::gnssAntennaInfoCb
+        (std::vector<GnssAntennaInformation> gnssAntennaInformations) {
+
+    if (mGnssAntennaInfoCbIface != nullptr) {
+        hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo> antennaInfos;
+
+        // Convert from one structure to another
+        convertGnssAntennaInfo(gnssAntennaInformations, antennaInfos);
+
+        auto r = mGnssAntennaInfoCbIface->gnssAntennaInfoCb(antennaInfos);
+        if (!r.isOk()) {
+            LOC_LOGw("Error antenna info cb %s", r.description().c_str());
+        }
+    } else {
+        LOC_LOGw("setCallback has not been called yet");
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/GnssAntennaInfo.h b/gps/android/2.1/GnssAntennaInfo.h
new file mode 100644
index 0000000..02ddd28
--- /dev/null
+++ b/gps/android/2.1/GnssAntennaInfo.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
+#define ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
+
+#include <android/hardware/gnss/2.1/IGnssAntennaInfo.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_1::IGnssAntennaInfo;
+using ::android::hardware::gnss::V2_1::IGnssAntennaInfoCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct GnssAntennaInfo : public IGnssAntennaInfo {
+    GnssAntennaInfo(Gnss* gnss);
+    ~GnssAntennaInfo();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_1::IGnssAntennaInfo follow.
+     * These declarations were generated from IGnssAntennaInfo.hal.
+     */
+    Return<GnssAntennaInfoStatus>
+            setCallback(const sp<IGnssAntennaInfoCallback>& callback) override;
+    Return<void> close(void) override;
+
+    void gnssAntennaInfoCb(std::vector<GnssAntennaInformation> gnssAntennaInformations);
+
+    static void aiGnssAntennaInfoCb(std::vector<GnssAntennaInformation> gnssAntennaInformations);
+
+ private:
+    struct GnssAntennaInfoDeathRecipient : hidl_death_recipient {
+        GnssAntennaInfoDeathRecipient(sp<GnssAntennaInfo> gnssAntennaInfo) :
+                mGnssAntennaInfo(gnssAntennaInfo) {
+        }
+        ~GnssAntennaInfoDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssAntennaInfo> mGnssAntennaInfo;
+    };
+
+ private:
+    sp<GnssAntennaInfoDeathRecipient> mGnssAntennaInfoDeathRecipient = nullptr;
+    sp<IGnssAntennaInfoCallback> mGnssAntennaInfoCbIface = nullptr;
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSANTENNAINFO_H
diff --git a/gps/android/2.1/GnssBatching.cpp b/gps/android/2.1/GnssBatching.cpp
new file mode 100644
index 0000000..73e3532
--- /dev/null
+++ b/gps/android/2.1/GnssBatching.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssBatchingInterface"
+
+#include <log_util.h>
+#include <BatchingAPIClient.h>
+#include "GnssBatching.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+void GnssBatching::GnssBatchingDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssBatching != nullptr) {
+        mGnssBatching->stop();
+        mGnssBatching->cleanup();
+    }
+}
+
+GnssBatching::GnssBatching() : mApi(nullptr) {
+    mGnssBatchingDeathRecipient = new GnssBatchingDeathRecipient(this);
+}
+
+GnssBatching::~GnssBatching() {
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+Return<bool> GnssBatching::init(const sp<V1_0::IGnssBatchingCallback>& callback) {
+    if (mApi != nullptr) {
+        LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+        mApi->destroy();
+        mApi = nullptr;
+    }
+
+    mApi = new BatchingAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+        return false;
+    }
+
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+    }
+    mGnssBatchingCbIface = callback;
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return true;
+}
+
+Return<uint16_t> GnssBatching::getBatchSize() {
+    uint16_t ret = 0;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->getBatchSize();
+    }
+    return ret;
+}
+
+Return<bool> GnssBatching::start(const IGnssBatching::Options& options) {
+    bool ret = false;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->startSession(options);
+    }
+    return ret;
+}
+
+Return<void> GnssBatching::flush() {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->flushBatchedLocations();
+    }
+    return Void();
+}
+
+Return<bool> GnssBatching::stop() {
+    bool ret = false;
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        ret = mApi->stopSession();
+    }
+    return ret;
+}
+
+Return<void> GnssBatching::cleanup() {
+    if (mApi != nullptr) {
+        mApi->stopSession();
+    }
+    if (mGnssBatchingCbIface != nullptr) {
+        mGnssBatchingCbIface->unlinkToDeath(mGnssBatchingDeathRecipient);
+        mGnssBatchingCbIface = nullptr;
+    }
+    if (mGnssBatchingCbIface_2_0 != nullptr) {
+        mGnssBatchingCbIface_2_0->unlinkToDeath(mGnssBatchingDeathRecipient);
+        mGnssBatchingCbIface_2_0 = nullptr;
+    }
+    return Void();
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnssBatching follow.
+Return<bool> GnssBatching::init_2_0(const sp<V2_0::IGnssBatchingCallback>& callback) {
+    if (mApi != nullptr) {
+        LOC_LOGD("%s]: mApi is NOT nullptr, delete it first", __FUNCTION__);
+        mApi->destroy();
+        mApi = nullptr;
+    }
+
+    mApi = new BatchingAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+        return false;
+    }
+
+    if (mGnssBatchingCbIface_2_0 != nullptr) {
+        mGnssBatchingCbIface_2_0->unlinkToDeath(mGnssBatchingDeathRecipient);
+    }
+    mGnssBatchingCbIface_2_0 = callback;
+    if (mGnssBatchingCbIface_2_0 != nullptr) {
+        mGnssBatchingCbIface_2_0->linkToDeath(mGnssBatchingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/GnssBatching.h b/gps/android/2.1/GnssBatching.h
new file mode 100644
index 0000000..908748f
--- /dev/null
+++ b/gps/android/2.1/GnssBatching.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
+
+#include <android/hardware/gnss/2.0/IGnssBatching.h>
+#include <hidl/Status.h>
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnssBatching;
+using ::android::hardware::gnss::V2_0::IGnssBatchingCallback;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+class BatchingAPIClient;
+struct GnssBatching : public IGnssBatching {
+    GnssBatching();
+    ~GnssBatching();
+
+    // Methods from ::android::hardware::gnss::V1_0::IGnssBatching follow.
+    Return<bool> init(const sp<V1_0::IGnssBatchingCallback>& callback) override;
+    Return<uint16_t> getBatchSize() override;
+    Return<bool> start(const IGnssBatching::Options& options ) override;
+    Return<void> flush() override;
+    Return<bool> stop() override;
+    Return<void> cleanup() override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IGnssBatching follow.
+    Return<bool> init_2_0(const sp<V2_0::IGnssBatchingCallback>& callback) override;
+
+ private:
+    struct GnssBatchingDeathRecipient : hidl_death_recipient {
+        GnssBatchingDeathRecipient(sp<GnssBatching> gnssBatching) :
+            mGnssBatching(gnssBatching) {
+        }
+        ~GnssBatchingDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssBatching> mGnssBatching;
+    };
+
+ private:
+    sp<GnssBatchingDeathRecipient> mGnssBatchingDeathRecipient = nullptr;
+    sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface = nullptr;
+    BatchingAPIClient* mApi = nullptr;
+    sp<V2_0::IGnssBatchingCallback> mGnssBatchingCbIface_2_0 = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSBATCHING_H
diff --git a/gps/android/2.1/GnssConfiguration.cpp b/gps/android/2.1/GnssConfiguration.cpp
new file mode 100644
index 0000000..b6077ae
--- /dev/null
+++ b/gps/android/2.1/GnssConfiguration.cpp
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssConfigurationInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssConfiguration.h"
+#include "ContextBase.h"
+#include <android/hardware/gnss/1.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::GnssConstellationType;
+using namespace loc_core;
+
+GnssConfiguration::GnssConfiguration(Gnss* gnss) : mGnss(gnss) {
+}
+
+// Methods from ::android::hardware::gps::V1_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setSuplEs(bool enabled)  {
+    // deprecated function. Must return false to pass VTS
+    return false;
+}
+
+Return<bool> GnssConfiguration::setSuplVersion(uint32_t version)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT;
+    switch (version) {
+        case 0x00020004:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_4;
+            break;
+        case 0x00020002:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_2;
+            break;
+        case 0x00020000:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_2_0_0;
+            break;
+        case 0x00010000:
+            config.suplVersion = GNSS_CONFIG_SUPL_VERSION_1_0_0;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid version: 0x%x.", __FUNCTION__, version);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setSuplMode(uint8_t mode)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_SUPL_MODE_BIT;
+    switch (mode) {
+        case 0:
+            config.suplModeMask = 0; // STANDALONE ONLY
+            break;
+        case 1:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT;
+            break;
+        case 2:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+            break;
+        case 3:
+            config.suplModeMask = GNSS_CONFIG_SUPL_MODE_MSB_BIT | GNSS_CONFIG_SUPL_MODE_MSA_BIT;
+            break;
+        default:
+            LOC_LOGE("%s]: invalid mode: %d.", __FUNCTION__, mode);
+            return false;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setLppProfile(uint8_t lppProfileMask) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config = {};
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+    config.lppProfileMask = GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE; //default
+
+    if (lppProfileMask & (1<<0)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_BIT;
+    }
+    if (lppProfileMask & (1<<1)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_BIT;
+    }
+    if (lppProfileMask & (1<<2)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_USER_PLANE_OVER_NR5G_SA_BIT;
+    }
+    if (lppProfileMask & (1<<3)) {
+        config.lppProfileMask |= GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_OVER_NR5G_SA_BIT;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGlonassPositioningProtocol(uint8_t protocol) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+
+    config.flags = GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT;
+    if (protocol & (1<<0)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRC_CONTROL_PLANE_BIT;
+    }
+    if (protocol & (1<<1)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_RRLP_USER_PLANE_BIT;
+    }
+    if (protocol & (1<<2)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_USER_PLANE_BIT;
+    }
+    if (protocol & (1<<3)) {
+        config.aGlonassPositionProtocolMask |= GNSS_CONFIG_LLP_CONTROL_PLANE_BIT;
+    }
+
+    return mGnss->updateConfiguration(config);
+}
+
+Return<bool> GnssConfiguration::setGpsLock(uint8_t lock) {
+
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config = {};
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT;
+    switch (lock) {
+    case 0:
+        config.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+        break;
+    case 1:
+        config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO;
+        break;
+    case 2:
+        config.gpsLock = GNSS_CONFIG_GPS_LOCK_NI;
+        break;
+    case 3:
+        config.gpsLock = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
+        break;
+    default:
+        LOC_LOGE("%s]: invalid lock: %d.", __FUNCTION__, lock);
+        return false;
+    }
+
+    mGnss->updateConfiguration(config);
+    // Must return false to pass VTS
+    return false;
+}
+
+Return<bool> GnssConfiguration::setEmergencySuplPdn(bool enabled) {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT;
+    config.emergencyPdnForEmergencySupl = (enabled ?
+            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES :
+            GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO);
+
+    return mGnss->updateConfiguration(config);
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist(
+            const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>& blacklist) {
+
+    ENTRY_LOG_CALLFLOW();
+    if (nullptr == mGnss) {
+        LOC_LOGe("mGnss is null");
+        return false;
+    }
+
+    // blValid is true if blacklist is empty, i.e. clearing the BL;
+    // if blacklist is not empty, blValid is initialied to false, and later
+    // updated in the for loop to become true only if there is at least
+    // one {constellation, svid} in the list that is valid.
+    bool blValid = (0 == blacklist.size());
+    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++) {
+        // Set blValid true if any one source is valid
+        blValid = setBlacklistedSource(source, (GnssConstellationType)blacklist[idx].constellation,
+                blacklist[idx].svid) || blValid;
+        config.blacklistedSvIds.push_back(source);
+    }
+
+    // Update configuration only if blValid is true
+    // i.e. only if atleast one source is valid for blacklisting
+    return (blValid && mGnss->updateConfiguration(config));
+}
+
+bool GnssConfiguration::setBlacklistedSource(
+            GnssSvIdSource& copyToSource, const GnssConstellationType& constellation,
+            const int16_t svid) {
+
+    bool retVal = true;
+    uint16_t svIdOffset = 0;
+    copyToSource.size = sizeof(GnssSvIdSource);
+    copyToSource.svId = svid;
+
+    switch(constellation) {
+    case GnssConstellationType::GPS:
+        copyToSource.constellation = GNSS_SV_TYPE_GPS;
+        LOC_LOGe("GPS SVs can't be blacklisted.");
+        retVal = false;
+        break;
+    case GnssConstellationType::SBAS:
+        copyToSource.constellation = GNSS_SV_TYPE_SBAS;
+        LOC_LOGe("SBAS SVs can't be blacklisted.");
+        retVal = false;
+        break;
+    case GnssConstellationType::GLONASS:
+        copyToSource.constellation = GNSS_SV_TYPE_GLONASS;
+        svIdOffset = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::QZSS:
+        copyToSource.constellation = GNSS_SV_TYPE_QZSS;
+        svIdOffset = 0;
+        break;
+    case GnssConstellationType::BEIDOU:
+        copyToSource.constellation = GNSS_SV_TYPE_BEIDOU;
+        svIdOffset = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::GALILEO:
+        copyToSource.constellation = GNSS_SV_TYPE_GALILEO;
+        svIdOffset = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::IRNSS:
+        copyToSource.constellation = GNSS_SV_TYPE_NAVIC;
+        svIdOffset = 0;
+        break;
+    default:
+        copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
+        LOC_LOGe("Invalid constellation %hhu", constellation);
+        retVal = false;
+        break;
+    }
+
+    if (copyToSource.svId > 0 && svIdOffset > 0) {
+        copyToSource.svId += svIdOffset;
+    }
+
+    return retVal;
+}
+
+bool GnssConfiguration::setBlacklistedSource(
+        GnssSvIdSource& copyToSource,
+        const GnssConfiguration::BlacklistedSource& copyFromSource) {
+
+    bool retVal = true;
+    uint16_t svIdOffset = 0;
+    copyToSource.size = sizeof(GnssSvIdSource);
+    copyToSource.svId = copyFromSource.svid;
+
+    switch(copyFromSource.constellation) {
+    case GnssConstellationType::GPS:
+        copyToSource.constellation = GNSS_SV_TYPE_GPS;
+        LOC_LOGe("GPS SVs can't be blacklisted.");
+        retVal = false;
+        break;
+    case GnssConstellationType::SBAS:
+        copyToSource.constellation = GNSS_SV_TYPE_SBAS;
+        LOC_LOGe("SBAS SVs can't be blacklisted.");
+        retVal = false;
+        break;
+    case GnssConstellationType::GLONASS:
+        copyToSource.constellation = GNSS_SV_TYPE_GLONASS;
+        svIdOffset = GNSS_SV_CONFIG_GLO_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::QZSS:
+        copyToSource.constellation = GNSS_SV_TYPE_QZSS;
+        svIdOffset = GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::BEIDOU:
+        copyToSource.constellation = GNSS_SV_TYPE_BEIDOU;
+        svIdOffset = GNSS_SV_CONFIG_BDS_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::GALILEO:
+        copyToSource.constellation = GNSS_SV_TYPE_GALILEO;
+        svIdOffset = GNSS_SV_CONFIG_GAL_INITIAL_SV_ID - 1;
+        break;
+    case GnssConstellationType::IRNSS:
+        copyToSource.constellation = GNSS_SV_TYPE_NAVIC;
+        svIdOffset = GNSS_SV_CONFIG_NAVIC_INITIAL_SV_ID - 1;
+        break;
+    default:
+        copyToSource.constellation = GNSS_SV_TYPE_UNKNOWN;
+        LOC_LOGe("Invalid constellation %hhu", copyFromSource.constellation);
+        retVal = false;
+        break;
+    }
+
+    if (copyToSource.svId > 0 && svIdOffset > 0) {
+        copyToSource.svId += svIdOffset;
+    }
+
+    return retVal;
+}
+
+// Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setEsExtensionSec(uint32_t emergencyExtensionSeconds) {
+    ENTRY_LOG_CALLFLOW();
+    if (mGnss == nullptr) {
+        LOC_LOGe("mGnss is nullptr");
+        return false;
+    }
+
+    GnssConfig config;
+    memset(&config, 0, sizeof(GnssConfig));
+    config.size = sizeof(GnssConfig);
+    config.flags = GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT;
+    config.emergencyExtensionSeconds = emergencyExtensionSeconds;
+
+    return mGnss->updateConfiguration(config);
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
+Return<bool> GnssConfiguration::setBlacklist_2_1(
+        const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& blacklist) {
+    ENTRY_LOG_CALLFLOW();
+    if (nullptr == mGnss) {
+        LOC_LOGe("mGnss is null");
+        return false;
+    }
+
+    // blValid is true if blacklist is empty, i.e. clearing the BL;
+    // if blacklist is not empty, blValid is initialied to false, and later
+    // updated in the for loop to become true only if there is at least
+    // one {constellation, svid} in the list that is valid.
+    bool blValid = (0 == blacklist.size());
+    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++) {
+        // Set blValid true if any one source is valid
+        blValid = setBlacklistedSource(source, blacklist[idx]) || blValid;
+        config.blacklistedSvIds.push_back(source);
+    }
+
+    // Update configuration only if blValid is true
+    // i.e. only if atleast one source is valid for blacklisting
+    return (blValid && mGnss->updateConfiguration(config));
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/GnssConfiguration.h b/gps/android/2.1/GnssConfiguration.h
new file mode 100644
index 0000000..f000dbd
--- /dev/null
+++ b/gps/android/2.1/GnssConfiguration.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+
+ /* Copyright (C) 2016 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.
+ */
+
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
+#define ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
+
+#include <android/hardware/gnss/2.1/IGnssConfiguration.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::hardware::gnss::V2_0::GnssConstellationType;
+using ::android::sp;
+
+/*
+ * Interface for passing GNSS configuration info from platform to HAL.
+ */
+struct Gnss;
+struct GnssConfiguration : public V2_1::IGnssConfiguration {
+    GnssConfiguration(Gnss* gnss);
+    ~GnssConfiguration() = default;
+
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssConfiguration follow.
+     * These declarations were generated from IGnssConfiguration.hal.
+     */
+    Return<bool> setSuplVersion(uint32_t version) override;
+    Return<bool> setSuplMode(uint8_t mode) override;
+    Return<bool> setSuplEs(bool enabled) override;
+    Return<bool> setLppProfile(uint8_t lppProfileMask) override;
+    Return<bool> setGlonassPositioningProtocol(uint8_t protocol) override;
+    Return<bool> setEmergencySuplPdn(bool enable) override;
+    Return<bool> setGpsLock(uint8_t lock) override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnssConfiguration follow.
+    Return<bool> setBlacklist(
+            const hidl_vec<V1_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IGnssConfiguration follow.
+    Return<bool> setEsExtensionSec(uint32_t emergencyExtensionSeconds) override;
+    // Methods from ::android::hardware::gnss::V2_1::IGnssConfiguration follow.
+    Return<bool> setBlacklist_2_1(
+            const hidl_vec<V2_1::IGnssConfiguration::BlacklistedSource>& blacklist) override;
+
+ private:
+    Gnss* mGnss = nullptr;
+    bool setBlacklistedSource(
+            GnssSvIdSource& copyToSource,
+            const GnssConfiguration::BlacklistedSource& copyFromSource);
+    bool setBlacklistedSource(
+            GnssSvIdSource& copyToSource, const GnssConstellationType& constellation,
+            const int16_t svid);
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
diff --git a/gps/android/2.1/GnssDebug.cpp b/gps/android/2.1/GnssDebug.cpp
new file mode 100644
index 0000000..27ff964
--- /dev/null
+++ b/gps/android/2.1/GnssDebug.cpp
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssDebugInterface"
+
+#include <log/log.h>
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssDebug.h"
+#include "LocationUtil.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::gnss::V2_0::IGnssDebug;
+
+#define GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS (20000000)
+#define GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS   (20000)
+#define GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC     (500)
+#define GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG       (180)
+
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME            (1483228800000LL) // 1/1/2017 00:00 GMT
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN    (999) // 999 ns
+#define GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX    (1.57783680E17) // 5 years in ns
+#define GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC (2.0e5)  // ppm
+
+GnssDebug::GnssDebug(Gnss* gnss) : mGnss(gnss)
+{
+}
+
+/*
+ * This methods requests position, time and satellite ephemeris debug information
+ * from the HAL.
+ *
+ * @return void
+*/
+Return<void> GnssDebug::getDebugData(getDebugData_cb _hidl_cb)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    V1_0::IGnssDebug::DebugData data = { };
+
+    if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+        LOC_LOGE("GnssDebug - Null GNSS interface");
+        _hidl_cb(data);
+        return Void();
+    }
+
+    // get debug report snapshot via hal interface
+    GnssDebugReport reports = { };
+    mGnss->getGnssInterface()->getDebugReport(reports);
+
+    // location block
+    if (reports.mLocation.mValid) {
+        data.position.valid = true;
+        data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+        data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+        data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+        data.position.speedMetersPerSec =
+            (double)(reports.mLocation.mLocation.speed);
+        data.position.bearingDegrees =
+            (double)(reports.mLocation.mLocation.bearing);
+        data.position.horizontalAccuracyMeters =
+            (double)(reports.mLocation.mLocation.accuracy);
+        data.position.verticalAccuracyMeters =
+            reports.mLocation.verticalAccuracyMeters;
+        data.position.speedAccuracyMetersPerSecond =
+            reports.mLocation.speedAccuracyMetersPerSecond;
+        data.position.bearingAccuracyDegrees =
+            reports.mLocation.bearingAccuracyDegrees;
+
+        timeval tv_now, tv_report;
+        tv_report.tv_sec  = reports.mLocation.mUtcReported.tv_sec;
+        tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+        gettimeofday(&tv_now, NULL);
+        data.position.ageSeconds =
+            (tv_now.tv_sec - tv_report.tv_sec) +
+            (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+    }
+    else {
+        data.position.valid = false;
+    }
+
+    if (data.position.horizontalAccuracyMeters <= 0 ||
+        data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+        data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+    }
+    if (data.position.verticalAccuracyMeters <= 0 ||
+        data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+        data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+    }
+    if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+        data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+        data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+    }
+    if (data.position.bearingAccuracyDegrees <= 0 ||
+        data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+        data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+    }
+
+    // time block
+    if (reports.mTime.mValid) {
+        data.time.timeEstimate = reports.mTime.timeEstimate;
+        data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+        data.time.frequencyUncertaintyNsPerSec =
+            reports.mTime.frequencyUncertaintyNsPerSec;
+    }
+
+    if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+        data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+    }
+    if (data.time.timeUncertaintyNs <= 0) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
+    } else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
+    }
+    if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+        data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+        data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+    }
+
+    // satellite data block
+    V1_0::IGnssDebug::SatelliteData s = { };
+    std::vector<V1_0::IGnssDebug::SatelliteData> s_array;
+
+    for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+        memset(&s, 0, sizeof(s));
+        s.svid = reports.mSatelliteInfo[i].svid;
+        convertGnssConstellationType(
+            reports.mSatelliteInfo[i].constellation, s.constellation);
+        convertGnssEphemerisType(
+            reports.mSatelliteInfo[i].mEphemerisType, s.ephemerisType);
+        convertGnssEphemerisSource(
+            reports.mSatelliteInfo[i].mEphemerisSource, s.ephemerisSource);
+        convertGnssEphemerisHealth(
+            reports.mSatelliteInfo[i].mEphemerisHealth, s.ephemerisHealth);
+
+        s.ephemerisAgeSeconds =
+            reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+        s.serverPredictionIsAvailable =
+            reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+        s.serverPredictionAgeSeconds =
+            reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+        s_array.push_back(s);
+    }
+    data.satelliteDataArray = s_array;
+
+    // callback HIDL with collected debug data
+    _hidl_cb(data);
+    return Void();
+}
+
+Return<void> GnssDebug::getDebugData_2_0(getDebugData_2_0_cb _hidl_cb)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    V2_0::IGnssDebug::DebugData data = { };
+
+    if((nullptr == mGnss) || (nullptr == mGnss->getGnssInterface())){
+        LOC_LOGE("GnssDebug - Null GNSS interface");
+        _hidl_cb(data);
+        return Void();
+    }
+
+    // get debug report snapshot via hal interface
+    GnssDebugReport reports = { };
+    mGnss->getGnssInterface()->getDebugReport(reports);
+
+    // location block
+    if (reports.mLocation.mValid) {
+        data.position.valid = true;
+        data.position.latitudeDegrees = reports.mLocation.mLocation.latitude;
+        data.position.longitudeDegrees = reports.mLocation.mLocation.longitude;
+        data.position.altitudeMeters = reports.mLocation.mLocation.altitude;
+
+        data.position.speedMetersPerSec =
+            (double)(reports.mLocation.mLocation.speed);
+        data.position.bearingDegrees =
+            (double)(reports.mLocation.mLocation.bearing);
+        data.position.horizontalAccuracyMeters =
+            (double)(reports.mLocation.mLocation.accuracy);
+        data.position.verticalAccuracyMeters =
+            reports.mLocation.verticalAccuracyMeters;
+        data.position.speedAccuracyMetersPerSecond =
+            reports.mLocation.speedAccuracyMetersPerSecond;
+        data.position.bearingAccuracyDegrees =
+            reports.mLocation.bearingAccuracyDegrees;
+
+        timeval tv_now, tv_report;
+        tv_report.tv_sec  = reports.mLocation.mUtcReported.tv_sec;
+        tv_report.tv_usec = reports.mLocation.mUtcReported.tv_nsec / 1000ULL;
+        gettimeofday(&tv_now, NULL);
+        data.position.ageSeconds =
+            (tv_now.tv_sec - tv_report.tv_sec) +
+            (float)((tv_now.tv_usec - tv_report.tv_usec)) / 1000000;
+    }
+    else {
+        data.position.valid = false;
+    }
+
+    if (data.position.horizontalAccuracyMeters <= 0 ||
+        data.position.horizontalAccuracyMeters > GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS) {
+        data.position.horizontalAccuracyMeters = GNSS_DEBUG_UNKNOWN_HORIZONTAL_ACCURACY_METERS;
+    }
+    if (data.position.verticalAccuracyMeters <= 0 ||
+        data.position.verticalAccuracyMeters > GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS) {
+        data.position.verticalAccuracyMeters = GNSS_DEBUG_UNKNOWN_VERTICAL_ACCURACY_METERS;
+    }
+    if (data.position.speedAccuracyMetersPerSecond <= 0 ||
+        data.position.speedAccuracyMetersPerSecond > GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC) {
+        data.position.speedAccuracyMetersPerSecond = GNSS_DEBUG_UNKNOWN_SPEED_ACCURACY_PER_SEC;
+    }
+    if (data.position.bearingAccuracyDegrees <= 0 ||
+        data.position.bearingAccuracyDegrees > GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG) {
+        data.position.bearingAccuracyDegrees = GNSS_DEBUG_UNKNOWN_BEARING_ACCURACY_DEG;
+    }
+
+    // time block
+    if (reports.mTime.mValid) {
+        data.time.timeEstimate = reports.mTime.timeEstimate;
+        data.time.timeUncertaintyNs = reports.mTime.timeUncertaintyNs;
+        data.time.frequencyUncertaintyNsPerSec =
+            reports.mTime.frequencyUncertaintyNsPerSec;
+    }
+
+    if (data.time.timeEstimate < GNSS_DEBUG_UNKNOWN_UTC_TIME) {
+        data.time.timeEstimate = GNSS_DEBUG_UNKNOWN_UTC_TIME;
+    }
+    if (data.time.timeUncertaintyNs <= 0) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MIN;
+    }
+    else if (data.time.timeUncertaintyNs > GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX) {
+        data.time.timeUncertaintyNs = (float)GNSS_DEBUG_UNKNOWN_UTC_TIME_UNC_MAX;
+    }
+    if (data.time.frequencyUncertaintyNsPerSec <= 0 ||
+        data.time.frequencyUncertaintyNsPerSec > (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC) {
+        data.time.frequencyUncertaintyNsPerSec = (float)GNSS_DEBUG_UNKNOWN_FREQ_UNC_NS_PER_SEC;
+    }
+
+    // satellite data block
+    V2_0::IGnssDebug::SatelliteData s = { };
+    std::vector<V2_0::IGnssDebug::SatelliteData> s_array;
+
+    for (uint32_t i=0; i<reports.mSatelliteInfo.size(); i++) {
+        memset(&s, 0, sizeof(s));
+        s.v1_0.svid = reports.mSatelliteInfo[i].svid;
+        convertGnssConstellationType(
+            reports.mSatelliteInfo[i].constellation, s.constellation);
+        convertGnssEphemerisType(
+            reports.mSatelliteInfo[i].mEphemerisType, s.v1_0.ephemerisType);
+        convertGnssEphemerisSource(
+            reports.mSatelliteInfo[i].mEphemerisSource, s.v1_0.ephemerisSource);
+        convertGnssEphemerisHealth(
+            reports.mSatelliteInfo[i].mEphemerisHealth, s.v1_0.ephemerisHealth);
+
+        s.v1_0.ephemerisAgeSeconds =
+            reports.mSatelliteInfo[i].ephemerisAgeSeconds;
+        s.v1_0.serverPredictionIsAvailable =
+            reports.mSatelliteInfo[i].serverPredictionIsAvailable;
+        s.v1_0.serverPredictionAgeSeconds =
+            reports.mSatelliteInfo[i].serverPredictionAgeSeconds;
+
+        s_array.push_back(s);
+    }
+    data.satelliteDataArray = s_array;
+
+    // callback HIDL with collected debug data
+    _hidl_cb(data);
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/GnssDebug.h b/gps/android/2.1/GnssDebug.h
new file mode 100644
index 0000000..4eaf34a
--- /dev/null
+++ b/gps/android/2.1/GnssDebug.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
+
+
+#include <android/hardware/gnss/2.0/IGnssDebug.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnssDebug;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+/* Interface for GNSS Debug support. */
+struct Gnss;
+struct GnssDebug : public IGnssDebug {
+    GnssDebug(Gnss* gnss);
+    ~GnssDebug() {};
+
+    //  Methods from ::android::hardware::gnss::V1_0::IGnssDebug follow
+    Return<void> getDebugData(getDebugData_cb _hidl_cb) override;
+    //  Methods from ::android::hardware::gnss::V2_0::IGnssDebug follow.
+    Return<void> getDebugData_2_0(getDebugData_2_0_cb _hidl_cb) override;
+
+private:
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSDEBUG_H
diff --git a/gps/android/2.1/GnssGeofencing.cpp b/gps/android/2.1/GnssGeofencing.cpp
new file mode 100644
index 0000000..0ca3e6d
--- /dev/null
+++ b/gps/android/2.1/GnssGeofencing.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "GnssHal_GnssGeofencing"
+
+#include <log_util.h>
+#include <GeofenceAPIClient.h>
+#include "GnssGeofencing.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+void GnssGeofencing::GnssGeofencingDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssGeofencing != nullptr) {
+        mGnssGeofencing->removeAllGeofences();
+    }
+}
+
+GnssGeofencing::GnssGeofencing() : mApi(nullptr) {
+    mGnssGeofencingDeathRecipient = new GnssGeofencingDeathRecipient(this);
+}
+
+GnssGeofencing::~GnssGeofencing() {
+    if (mApi != nullptr) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+Return<void> GnssGeofencing::setCallback(const sp<IGnssGeofenceCallback>& callback)  {
+    if (mApi != nullptr) {
+        LOC_LOGd("mApi is NOT nullptr");
+        return Void();
+    }
+
+    mApi = new GeofenceAPIClient(callback);
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: failed to create mApi", __FUNCTION__);
+    }
+
+    if (mGnssGeofencingCbIface != nullptr) {
+        mGnssGeofencingCbIface->unlinkToDeath(mGnssGeofencingDeathRecipient);
+    }
+    mGnssGeofencingCbIface = callback;
+    if (mGnssGeofencingCbIface != nullptr) {
+        mGnssGeofencingCbIface->linkToDeath(mGnssGeofencingDeathRecipient, 0 /*cookie*/);
+    }
+
+    return Void();
+}
+
+Return<void> GnssGeofencing::addGeofence(
+        int32_t geofenceId,
+        double latitudeDegrees,
+        double longitudeDegrees,
+        double radiusMeters,
+        IGnssGeofenceCallback::GeofenceTransition lastTransition,
+        int32_t monitorTransitions,
+        uint32_t notificationResponsivenessMs,
+        uint32_t unknownTimerMs)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceAdd(
+                geofenceId,
+                latitudeDegrees,
+                longitudeDegrees,
+                radiusMeters,
+                static_cast<int32_t>(lastTransition),
+                monitorTransitions,
+                notificationResponsivenessMs,
+                unknownTimerMs);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::pauseGeofence(int32_t geofenceId)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofencePause(geofenceId);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceResume(geofenceId, monitorTransitions);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::removeGeofence(int32_t geofenceId)  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+    } else {
+        mApi->geofenceRemove(geofenceId);
+    }
+    return Void();
+}
+
+Return<void> GnssGeofencing::removeAllGeofences()  {
+    if (mApi == nullptr) {
+        LOC_LOGD("%s]: mApi is nullptr, do nothing", __FUNCTION__);
+    } else {
+        mApi->geofenceRemoveAll();
+    }
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/GnssGeofencing.h b/gps/android/2.1/GnssGeofencing.h
new file mode 100644
index 0000000..1cdca12
--- /dev/null
+++ b/gps/android/2.1/GnssGeofencing.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
+
+#include <android/hardware/gnss/1.0/IGnssGeofencing.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::IGnssGeofencing;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class GeofenceAPIClient;
+struct GnssGeofencing : public IGnssGeofencing {
+    GnssGeofencing();
+    ~GnssGeofencing();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssGeofencing follow.
+     * These declarations were generated from IGnssGeofencing.hal.
+     */
+    Return<void> setCallback(const sp<IGnssGeofenceCallback>& callback)  override;
+    Return<void> addGeofence(int32_t geofenceId,
+                             double latitudeDegrees,
+                             double longitudeDegrees,
+                             double radiusMeters,
+                             IGnssGeofenceCallback::GeofenceTransition lastTransition,
+                             int32_t monitorTransitions,
+                             uint32_t notificationResponsivenessMs,
+                             uint32_t unknownTimerMs)  override;
+
+    Return<void> pauseGeofence(int32_t geofenceId)  override;
+    Return<void> resumeGeofence(int32_t geofenceId, int32_t monitorTransitions)  override;
+    Return<void> removeGeofence(int32_t geofenceId)  override;
+
+ private:
+    // This method is not part of the IGnss base class.
+    // It is called by GnssGeofencingDeathRecipient to remove all geofences added so far.
+    Return<void> removeAllGeofences();
+
+ private:
+    struct GnssGeofencingDeathRecipient : hidl_death_recipient {
+        GnssGeofencingDeathRecipient(sp<GnssGeofencing> gnssGeofencing) :
+            mGnssGeofencing(gnssGeofencing) {
+        }
+        ~GnssGeofencingDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssGeofencing> mGnssGeofencing;
+    };
+
+ private:
+    sp<GnssGeofencingDeathRecipient> mGnssGeofencingDeathRecipient = nullptr;
+    sp<IGnssGeofenceCallback> mGnssGeofencingCbIface = nullptr;
+    GeofenceAPIClient* mApi = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSGEOFENCING_H
diff --git a/gps/android/2.1/GnssMeasurement.cpp b/gps/android/2.1/GnssMeasurement.cpp
new file mode 100644
index 0000000..af75802
--- /dev/null
+++ b/gps/android/2.1/GnssMeasurement.cpp
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssMeasurementInterface"
+
+#include <log_util.h>
+#include "GnssMeasurement.h"
+#include "MeasurementAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+void GnssMeasurement::GnssMeasurementDeathRecipient::serviceDied(
+        uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    if (mGnssMeasurement != nullptr) {
+        mGnssMeasurement->close();
+    }
+}
+
+GnssMeasurement::GnssMeasurement() {
+    mGnssMeasurementDeathRecipient = new GnssMeasurementDeathRecipient(this);
+    mApi = new MeasurementAPIClient();
+}
+
+GnssMeasurement::~GnssMeasurement() {
+    if (mApi) {
+        mApi->destroy();
+        mApi = nullptr;
+    }
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback(
+        const sp<V1_0::IGnssMeasurementCallback>& callback)  {
+
+    Return<GnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    clearInterfaces();
+
+    mGnssMeasurementCbIface = callback;
+    mGnssMeasurementCbIface->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    return mApi->measurementSetCallback(callback);
+}
+
+void GnssMeasurement::clearInterfaces() {
+    if (mGnssMeasurementCbIface != nullptr) {
+        mGnssMeasurementCbIface->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface = nullptr;
+    }
+    if (mGnssMeasurementCbIface_1_1 != nullptr) {
+        mGnssMeasurementCbIface_1_1->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface_1_1 = nullptr;
+    }
+    if (mGnssMeasurementCbIface_2_0 != nullptr) {
+        mGnssMeasurementCbIface_2_0->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface_2_0 = nullptr;
+    }
+    if (mGnssMeasurementCbIface_2_1 != nullptr) {
+        mGnssMeasurementCbIface_2_1->unlinkToDeath(mGnssMeasurementDeathRecipient);
+        mGnssMeasurementCbIface_2_1 = nullptr;
+    }
+}
+
+Return<void> GnssMeasurement::close()  {
+    if (mApi == nullptr) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    clearInterfaces();
+    mApi->measurementClose();
+
+    return Void();
+}
+
+// Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+Return<GnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_1_1(
+        const sp<V1_1::IGnssMeasurementCallback>& callback, bool enableFullTracking) {
+
+    Return<GnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface_1_1 != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (nullptr == mApi) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    clearInterfaces();
+
+    mGnssMeasurementCbIface_1_1 = callback;
+    mGnssMeasurementCbIface_1_1->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    GnssPowerMode powerMode = enableFullTracking?
+            GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;
+
+    return mApi->measurementSetCallback_1_1(callback, powerMode);
+}
+// Methods from ::android::hardware::gnss::V2_0::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_0(
+        const sp<V2_0::IGnssMeasurementCallback>& callback,
+        bool enableFullTracking) {
+
+    Return<GnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface_2_0 != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (nullptr == mApi) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    clearInterfaces();
+
+    mGnssMeasurementCbIface_2_0 = callback;
+    mGnssMeasurementCbIface_2_0->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    GnssPowerMode powerMode = enableFullTracking ?
+        GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;
+
+    return mApi->measurementSetCallback_2_0(callback, powerMode);
+}
+
+// Methods from ::android::hardware::gnss::V2_1::IGnssMeasurement follow.
+Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> GnssMeasurement::setCallback_2_1(
+        const sp<::android::hardware::gnss::V2_1::IGnssMeasurementCallback>& callback,
+        bool enableFullTracking) {
+    Return<GnssMeasurement::GnssMeasurementStatus> ret =
+        IGnssMeasurement::GnssMeasurementStatus::ERROR_GENERIC;
+    if (mGnssMeasurementCbIface_2_1 != nullptr) {
+        LOC_LOGE("%s]: GnssMeasurementCallback is already set", __FUNCTION__);
+        return IGnssMeasurement::GnssMeasurementStatus::ERROR_ALREADY_INIT;
+    }
+
+    if (callback == nullptr) {
+        LOC_LOGE("%s]: callback is nullptr", __FUNCTION__);
+        return ret;
+    }
+    if (nullptr == mApi) {
+        LOC_LOGE("%s]: mApi is nullptr", __FUNCTION__);
+        return ret;
+    }
+
+    clearInterfaces();
+
+    mGnssMeasurementCbIface_2_1 = callback;
+    mGnssMeasurementCbIface_2_1->linkToDeath(mGnssMeasurementDeathRecipient, 0);
+
+    GnssPowerMode powerMode = enableFullTracking ?
+            GNSS_POWER_MODE_M1 : GNSS_POWER_MODE_M2;
+
+    return mApi->measurementSetCallback_2_1(callback, powerMode);
+
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/GnssMeasurement.h b/gps/android/2.1/GnssMeasurement.h
new file mode 100644
index 0000000..2ac45c6
--- /dev/null
+++ b/gps/android/2.1/GnssMeasurement.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_1_GNSSMEASUREMENT_H
+#define ANDROID_HARDWARE_GNSS_V2_1_GNSSMEASUREMENT_H
+
+#include <android/hardware/gnss/2.1/IGnssMeasurement.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class MeasurementAPIClient;
+struct GnssMeasurement : public V2_1::IGnssMeasurement {
+    GnssMeasurement();
+    ~GnssMeasurement();
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssMeasurement follow.
+     * These declarations were generated from IGnssMeasurement.hal.
+     */
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback(
+        const sp<V1_0::IGnssMeasurementCallback>& callback) override;
+    Return<void> close() override;
+
+    // Methods from ::android::hardware::gnss::V1_1::IGnssMeasurement follow.
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_1_1(
+            const sp<V1_1::IGnssMeasurementCallback>& callback,
+            bool enableFullTracking) override;
+
+    // Methods from ::android::hardware::gnss::V2_0::IGnssMeasurement follow.
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_0(
+            const sp<V2_0::IGnssMeasurementCallback>& callback,
+            bool enableFullTracking) override;
+    // Methods from ::android::hardware::gnss::V2_1::IGnssMeasurement follow.
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> setCallback_2_1(
+            const sp<::android::hardware::gnss::V2_1::IGnssMeasurementCallback>& callback,
+            bool enableFullTracking) override;
+
+ private:
+    struct GnssMeasurementDeathRecipient : hidl_death_recipient {
+        GnssMeasurementDeathRecipient(sp<GnssMeasurement> gnssMeasurement) :
+            mGnssMeasurement(gnssMeasurement) {
+        }
+        ~GnssMeasurementDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssMeasurement> mGnssMeasurement;
+    };
+
+ private:
+    sp<GnssMeasurementDeathRecipient> mGnssMeasurementDeathRecipient = nullptr;
+    sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface = nullptr;
+    sp<V1_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1 = nullptr;
+    sp<V2_0::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_0 = nullptr;
+    sp<V2_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_1 = nullptr;
+    MeasurementAPIClient* mApi;
+    void clearInterfaces();
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_1_GNSSMEASUREMENT_H
diff --git a/gps/android/2.1/GnssNi.cpp b/gps/android/2.1/GnssNi.cpp
new file mode 100644
index 0000000..ba5e8d9
--- /dev/null
+++ b/gps/android/2.1/GnssNi.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "LocSvc_GnssNiInterface"
+
+#include <log_util.h>
+#include "Gnss.h"
+#include "GnssNi.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+void GnssNi::GnssNiDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) {
+    LOC_LOGE("%s] service died. cookie: %llu, who: %p",
+            __FUNCTION__, static_cast<unsigned long long>(cookie), &who);
+    // we do nothing here
+    // Gnss::GnssDeathRecipient will stop the session
+}
+
+GnssNi::GnssNi(Gnss* gnss) : mGnss(gnss) {
+    mGnssNiDeathRecipient = new GnssNiDeathRecipient(this);
+}
+
+// Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+Return<void> GnssNi::setCallback(const sp<IGnssNiCallback>& callback)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    mGnss->setGnssNiCb(callback);
+
+    if (mGnssNiCbIface != nullptr) {
+        mGnssNiCbIface->unlinkToDeath(mGnssNiDeathRecipient);
+    }
+    mGnssNiCbIface = callback;
+    if (mGnssNiCbIface != nullptr) {
+        mGnssNiCbIface->linkToDeath(mGnssNiDeathRecipient, 0 /*cookie*/);
+    }
+
+    return Void();
+}
+
+Return<void> GnssNi::respond(int32_t notifId, IGnssNiCallback::GnssUserResponseType userResponse)  {
+    if (mGnss == nullptr) {
+        LOC_LOGE("%s]: mGnss is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    GnssAPIClient* api = mGnss->getApi();
+    if (api == nullptr) {
+        LOC_LOGE("%s]: api is nullptr", __FUNCTION__);
+        return Void();
+    }
+
+    api->gnssNiRespond(notifId, userResponse);
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/GnssNi.h b/gps/android/2.1/GnssNi.h
new file mode 100644
index 0000000..9a8fb69
--- /dev/null
+++ b/gps/android/2.1/GnssNi.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
+#define ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
+
+#include <android/hardware/gnss/1.0/IGnssNi.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssNi;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+struct Gnss;
+struct GnssNi : public IGnssNi {
+    GnssNi(Gnss* gnss);
+    ~GnssNi() = default;
+
+    /*
+     * Methods from ::android::hardware::gnss::V1_0::IGnssNi follow.
+     * These declarations were generated from IGnssNi.hal.
+     */
+    Return<void> setCallback(const sp<IGnssNiCallback>& callback) override;
+    Return<void> respond(int32_t notifId,
+                         IGnssNiCallback::GnssUserResponseType userResponse) override;
+
+ private:
+    struct GnssNiDeathRecipient : hidl_death_recipient {
+        GnssNiDeathRecipient(sp<GnssNi> gnssNi) : mGnssNi(gnssNi) {
+        }
+        ~GnssNiDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<GnssNi> mGnssNi;
+    };
+
+ private:
+    sp<GnssNiDeathRecipient> mGnssNiDeathRecipient = nullptr;
+    sp<IGnssNiCallback> mGnssNiCbIface = nullptr;
+    Gnss* mGnss = nullptr;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V2_0_GNSSNI_H
diff --git a/gps/android/2.1/GnssVisibilityControl.cpp b/gps/android/2.1/GnssVisibilityControl.cpp
new file mode 100644
index 0000000..5a8c697
--- /dev/null
+++ b/gps/android/2.1/GnssVisibilityControl.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include "GnssVisibilityControl.h"
+#include <location_interface.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace visibility_control {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+static GnssVisibilityControl* spGnssVisibilityControl = nullptr;
+
+static void convertGnssNfwNotification(GnssNfwNotification& in,
+    IGnssVisibilityControlCallback::NfwNotification& out);
+
+GnssVisibilityControl::GnssVisibilityControl(Gnss* gnss) : mGnss(gnss) {
+    spGnssVisibilityControl = this;
+}
+GnssVisibilityControl::~GnssVisibilityControl() {
+    spGnssVisibilityControl = nullptr;
+}
+
+void GnssVisibilityControl::nfwStatusCb(GnssNfwNotification notification) {
+    if (nullptr != spGnssVisibilityControl) {
+        spGnssVisibilityControl->statusCb(notification);
+    }
+}
+
+bool GnssVisibilityControl::isInEmergencySession() {
+    if (nullptr != spGnssVisibilityControl) {
+        return spGnssVisibilityControl->isE911Session();
+    }
+    return false;
+}
+
+static void convertGnssNfwNotification(GnssNfwNotification& in,
+    IGnssVisibilityControlCallback::NfwNotification& out)
+{
+    memset(&out, 0, sizeof(IGnssVisibilityControlCallback::NfwNotification));
+    out.proxyAppPackageName = in.proxyAppPackageName;
+    out.protocolStack = (IGnssVisibilityControlCallback::NfwProtocolStack)in.protocolStack;
+    out.otherProtocolStackName = in.otherProtocolStackName;
+    out.requestor = (IGnssVisibilityControlCallback::NfwRequestor)in.requestor;
+    out.requestorId = in.requestorId;
+    out.responseType = (IGnssVisibilityControlCallback::NfwResponseType)in.responseType;
+    out.inEmergencyMode = in.inEmergencyMode;
+    out.isCachedLocation = in.isCachedLocation;
+}
+
+void GnssVisibilityControl::statusCb(GnssNfwNotification notification) {
+
+    if (mGnssVisibilityControlCbIface != nullptr) {
+        IGnssVisibilityControlCallback::NfwNotification nfwNotification;
+
+        // Convert from one structure to another
+        convertGnssNfwNotification(notification, nfwNotification);
+
+        auto r = mGnssVisibilityControlCbIface->nfwNotifyCb(nfwNotification);
+        if (!r.isOk()) {
+            LOC_LOGw("Error invoking NFW status cb %s", r.description().c_str());
+        }
+    } else {
+        LOC_LOGw("setCallback has not been called yet");
+    }
+}
+
+bool GnssVisibilityControl::isE911Session() {
+
+    if (mGnssVisibilityControlCbIface != nullptr) {
+        auto r = mGnssVisibilityControlCbIface->isInEmergencySession();
+        if (!r.isOk()) {
+            LOC_LOGw("Error invoking NFW status cb %s", r.description().c_str());
+            return false;
+        } else {
+            return (r);
+        }
+    } else {
+        LOC_LOGw("setCallback has not been called yet");
+        return false;
+    }
+}
+
+// Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl follow.
+Return<bool> GnssVisibilityControl::enableNfwLocationAccess(const hidl_vec<::android::hardware::hidl_string>& proxyApps) {
+
+    if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
+        LOC_LOGe("Null GNSS interface");
+        return false;
+    }
+
+    /* If the vector is empty we need to disable all NFW clients
+       If there is at least one app in the vector we need to enable
+       all NFW clients */
+    if (0 == proxyApps.size()) {
+        mGnss->getGnssInterface()->enableNfwLocationAccess(false);
+    } else {
+        mGnss->getGnssInterface()->enableNfwLocationAccess(true);
+    }
+
+    return true;
+}
+/**
+ * Registers the callback for HAL implementation to use.
+ *
+ * @param callback Handle to IGnssVisibilityControlCallback interface.
+ */
+Return<bool> GnssVisibilityControl::setCallback(const ::android::sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback>& callback) {
+
+    if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
+        LOC_LOGe("Null GNSS interface");
+        return false;
+    }
+    mGnssVisibilityControlCbIface = callback;
+
+    NfwCbInfo cbInfo = {};
+    cbInfo.visibilityControlCb = (void*)nfwStatusCb;
+    cbInfo.isInEmergencySession = (void*)isInEmergencySession;
+
+    mGnss->getGnssInterface()->nfwInit(cbInfo);
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace visibility_control
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/GnssVisibilityControl.h b/gps/android/2.1/GnssVisibilityControl.h
new file mode 100644
index 0000000..6794a64
--- /dev/null
+++ b/gps/android/2.1/GnssVisibilityControl.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
+#define ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
+
+#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <gps_extended_c.h>
+#include <location_interface.h>
+#include "Gnss.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace visibility_control {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V2_1::implementation::Gnss;
+
+struct GnssVisibilityControl : public IGnssVisibilityControl {
+    GnssVisibilityControl(Gnss* gnss);
+    ~GnssVisibilityControl();
+
+    // Methods from ::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl follow.
+    Return<bool> enableNfwLocationAccess(const hidl_vec<::android::hardware::hidl_string>& proxyApps) override;
+    /**
+     * Registers the callback for HAL implementation to use.
+     *
+     * @param callback Handle to IGnssVisibilityControlCallback interface.
+     */
+    Return<bool> setCallback(const ::android::sp<::android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControlCallback>& callback) override;
+
+    void statusCb(GnssNfwNotification notification);
+    bool isE911Session();
+
+    /* Data call setup callback passed down to GNSS HAL implementation */
+    static void nfwStatusCb(GnssNfwNotification notification);
+    static bool isInEmergencySession();
+
+private:
+    Gnss* mGnss = nullptr;
+    sp<IGnssVisibilityControlCallback> mGnssVisibilityControlCbIface = nullptr;
+};
+
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace visibility_control
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_0_GnssVisibilityControl_H
diff --git a/gps/android/2.1/MeasurementCorrections.cpp b/gps/android/2.1/MeasurementCorrections.cpp
new file mode 100644
index 0000000..f8f0803
--- /dev/null
+++ b/gps/android/2.1/MeasurementCorrections.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "LocSvc_MeasurementCorrectionsInterface"
+
+#include <log_util.h>
+#include "MeasurementCorrections.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
+using MeasurementCorrectionsV1_0 =
+        ::android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
+using MeasurementCorrectionsV1_1 =
+        ::android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;
+
+static MeasurementCorrections* spMeasurementCorrections = nullptr;
+
+void MeasurementCorrections::GnssMeasurementCorrectionsDeathRecipient::serviceDied(uint64_t cookie,
+        const wp<IBase>& who) {
+    LOC_LOGe("service died. cookie: %llu, who: %p", static_cast<unsigned long long>(cookie), &who);
+    // Gnss::GnssDeathrecipient will stop the session
+    // we inform the adapter that service has died
+    if (nullptr == spMeasurementCorrections) {
+        LOC_LOGe("spMeasurementCorrections is nullptr");
+        return;
+    }
+    if (nullptr == spMeasurementCorrections->mGnss ||
+        nullptr == spMeasurementCorrections->mGnss->getGnssInterface()) {
+        LOC_LOGe("Null GNSS interface");
+        return;
+    }
+    spMeasurementCorrections->mGnss->getGnssInterface()->measCorrClose();
+}
+
+MeasurementCorrections::MeasurementCorrections(Gnss* gnss) : mGnss(gnss) {
+    mGnssMeasurementCorrectionsDeathRecipient = new GnssMeasurementCorrectionsDeathRecipient(this);
+    spMeasurementCorrections = this;
+}
+
+MeasurementCorrections::~MeasurementCorrections() {
+    spMeasurementCorrections = nullptr;
+}
+
+void MeasurementCorrections::measCorrSetCapabilitiesCb(
+        GnssMeasurementCorrectionsCapabilitiesMask capabilities) {
+    if (nullptr != spMeasurementCorrections) {
+        spMeasurementCorrections->setCapabilitiesCb(capabilities);
+    }
+}
+
+void MeasurementCorrections::setCapabilitiesCb(
+    GnssMeasurementCorrectionsCapabilitiesMask capabilities) {
+
+    if (mMeasurementCorrectionsCbIface != nullptr) {
+        uint32_t measCorrCapabilities = 0;
+
+        // Convert from one enum to another
+        if (capabilities & GNSS_MEAS_CORR_LOS_SATS) {
+            measCorrCapabilities |=
+                    IMeasurementCorrectionsCallback::Capabilities::LOS_SATS;
+        }
+        if (capabilities & GNSS_MEAS_CORR_EXCESS_PATH_LENGTH) {
+            measCorrCapabilities |=
+                    IMeasurementCorrectionsCallback::Capabilities::EXCESS_PATH_LENGTH;
+        }
+        if (capabilities & GNSS_MEAS_CORR_REFLECTING_PLANE) {
+            measCorrCapabilities |=
+                    IMeasurementCorrectionsCallback::Capabilities::REFLECTING_PLANE;
+        }
+
+        auto r = mMeasurementCorrectionsCbIface->setCapabilitiesCb(measCorrCapabilities);
+        if (!r.isOk()) {
+            LOC_LOGw("Error invoking setCapabilitiesCb %s", r.description().c_str());
+        }
+    } else {
+        LOC_LOGw("setCallback has not been called yet");
+    }
+}
+
+Return<bool> MeasurementCorrections::setCorrections(
+        const MeasurementCorrectionsV1_0& corrections) {
+
+    GnssMeasurementCorrections gnssMeasurementCorrections = {};
+
+    V2_1::implementation::convertMeasurementCorrections(corrections, gnssMeasurementCorrections);
+
+    return mGnss->getGnssInterface()->measCorrSetCorrections(gnssMeasurementCorrections);
+}
+
+Return<bool> MeasurementCorrections::setCorrections_1_1(
+        const MeasurementCorrectionsV1_1& corrections) {
+
+    GnssMeasurementCorrections gnssMeasurementCorrections = {};
+
+    V2_1::implementation::convertMeasurementCorrections(
+            corrections.v1_0, gnssMeasurementCorrections);
+
+    gnssMeasurementCorrections.hasEnvironmentBearing = corrections.hasEnvironmentBearing;
+    gnssMeasurementCorrections.environmentBearingDegrees =
+            corrections.environmentBearingDegrees;
+    gnssMeasurementCorrections.environmentBearingUncertaintyDegrees =
+            corrections.environmentBearingUncertaintyDegrees;
+
+    for (int i = 0; i < corrections.satCorrections.size(); i++) {
+        GnssSingleSatCorrection gnssSingleSatCorrection = {};
+
+        V2_1::implementation::convertSingleSatCorrections(
+                corrections.satCorrections[i].v1_0, gnssSingleSatCorrection);
+        switch (corrections.satCorrections[i].constellation) {
+        case (::android::hardware::gnss::V2_0::GnssConstellationType::GPS):
+            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_GPS;
+            break;
+        case (::android::hardware::gnss::V2_0::GnssConstellationType::SBAS):
+            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_SBAS;
+            break;
+        case (::android::hardware::gnss::V2_0::GnssConstellationType::GLONASS):
+            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_GLONASS;
+            break;
+        case (::android::hardware::gnss::V2_0::GnssConstellationType::QZSS):
+            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_QZSS;
+            break;
+        case (::android::hardware::gnss::V2_0::GnssConstellationType::BEIDOU):
+            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_BEIDOU;
+            break;
+        case (::android::hardware::gnss::V2_0::GnssConstellationType::GALILEO):
+            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_GALILEO;
+            break;
+        case (::android::hardware::gnss::V2_0::GnssConstellationType::IRNSS):
+            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_NAVIC;
+            break;
+        case (::android::hardware::gnss::V2_0::GnssConstellationType::UNKNOWN):
+        default:
+            gnssSingleSatCorrection.svType = GNSS_SV_TYPE_UNKNOWN;
+            break;
+        }
+        gnssMeasurementCorrections.satCorrections.push_back(gnssSingleSatCorrection);
+    }
+
+    return mGnss->getGnssInterface()->measCorrSetCorrections(gnssMeasurementCorrections);
+}
+
+Return<bool> MeasurementCorrections::setCallback(
+        const sp<V1_0::IMeasurementCorrectionsCallback>& callback) {
+
+    if (nullptr == mGnss || nullptr == mGnss->getGnssInterface()) {
+        LOC_LOGe("Null GNSS interface");
+        return false;
+    }
+    mMeasurementCorrectionsCbIface = callback;
+
+    return mGnss->getGnssInterface()->measCorrInit(measCorrSetCapabilitiesCb);
+}
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace measurement_corrections
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/MeasurementCorrections.h b/gps/android/2.1/MeasurementCorrections.h
new file mode 100644
index 0000000..92fcc6a
--- /dev/null
+++ b/gps/android/2.1/MeasurementCorrections.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_HARDWARE_GNSS_V1_1_MeasurementCorrections_H
+#define ANDROID_HARDWARE_GNSS_V1_1_MeasurementCorrections_H
+
+#include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrectionsCallback.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <gps_extended_c.h>
+#include <location_interface.h>
+#include "Gnss.h"
+#include <LocationUtil.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace measurement_corrections {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+using ::android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrectionsCallback;
+using ::android::hardware::gnss::V2_1::implementation::Gnss;
+using MeasurementCorrectionsV1_0 =
+        ::android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
+using MeasurementCorrectionsV1_1 =
+        ::android::hardware::gnss::measurement_corrections::V1_1::MeasurementCorrections;
+
+struct MeasurementCorrections : public V1_1::IMeasurementCorrections {
+    MeasurementCorrections(Gnss* gnss);
+    ~MeasurementCorrections();
+
+    Return<bool> setCorrections(const MeasurementCorrectionsV1_0& corrections) override;
+
+    // Methods from
+    // ::android::hardware::gnss::measurement_corrections::V1_1::IMeasurementCorrections follow.
+    Return<bool> setCorrections_1_1(const MeasurementCorrectionsV1_1& corrections);
+
+    Return<bool> setCallback(const sp<IMeasurementCorrectionsCallback>& callback) override;
+
+    void setCapabilitiesCb(GnssMeasurementCorrectionsCapabilitiesMask capabilities);
+
+    /* Data call setup callback passed down to GNSS HAL implementation */
+    static void measCorrSetCapabilitiesCb(GnssMeasurementCorrectionsCapabilitiesMask capabilities);
+
+private:
+    struct GnssMeasurementCorrectionsDeathRecipient : hidl_death_recipient {
+        GnssMeasurementCorrectionsDeathRecipient(
+            sp<MeasurementCorrections> gnssMeasurementCorrections) :
+                    mGnssMeasurementCorrections(gnssMeasurementCorrections) {
+        }
+        ~GnssMeasurementCorrectionsDeathRecipient() = default;
+        virtual void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+        sp<MeasurementCorrections> mGnssMeasurementCorrections;
+    };
+    Gnss* mGnss = nullptr;
+    sp<GnssMeasurementCorrectionsDeathRecipient> mGnssMeasurementCorrectionsDeathRecipient =
+            nullptr;
+    sp<IMeasurementCorrectionsCallback> mMeasurementCorrectionsCbIface = nullptr;
+};
+
+
+}  // namespace implementation
+}  // namespace V1_1
+}  // namespace measurement_corrections
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_GNSS_V1_1_MeasurementCorrections_H
diff --git a/gps/android/2.1/android.hardware.gnss@2.1-service-qti.rc b/gps/android/2.1/android.hardware.gnss@2.1-service-qti.rc
new file mode 100644
index 0000000..19e32c4
--- /dev/null
+++ b/gps/android/2.1/android.hardware.gnss@2.1-service-qti.rc
@@ -0,0 +1,4 @@
+service gnss_service /vendor/bin/hw/android.hardware.gnss@2.1-service-qti
+    class hal
+    user gps
+    group system gps radio vendor_qti_diag
diff --git a/gps/android/2.1/android.hardware.gnss@2.1-service-qti.xml b/gps/android/2.1/android.hardware.gnss@2.1-service-qti.xml
new file mode 100755
index 0000000..842fb6e
--- /dev/null
+++ b/gps/android/2.1/android.hardware.gnss@2.1-service-qti.xml
@@ -0,0 +1,36 @@
+<!-- Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of The Linux Foundation nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.gnss</name>
+        <transport>hwbinder</transport>
+        <fqname>@1.1::IGnss/default</fqname>
+        <fqname>@2.1::IGnss/default</fqname>
+    </hal>
+</manifest>
+
diff --git a/gps/android/2.1/location_api/BatchingAPIClient.cpp b/gps/android/2.1/location_api/BatchingAPIClient.cpp
new file mode 100644
index 0000000..0c871b7
--- /dev/null
+++ b/gps/android/2.1/location_api/BatchingAPIClient.cpp
@@ -0,0 +1,292 @@
+/* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_BatchingAPIClient"
+
+#include <inttypes.h>
+#include <log_util.h>
+#include <loc_cfg.h>
+#include <thread>
+#include "LocationUtil.h"
+#include "BatchingAPIClient.h"
+
+#include "limits.h"
+
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::IGnssBatching;
+using ::android::hardware::gnss::V2_0::IGnssBatchingCallback;
+using ::android::hardware::gnss::V2_0::GnssLocation;
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+        LocationCapabilitiesMask mask);
+
+BatchingAPIClient::BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssBatchingCbIface(nullptr),
+    mDefaultId(UINT_MAX),
+    mLocationCapabilitiesMask(0),
+    mGnssBatchingCbIface_2_0(nullptr)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    gnssUpdateCallbacks(callback);
+}
+
+BatchingAPIClient::BatchingAPIClient(const sp<V2_0::IGnssBatchingCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssBatchingCbIface(nullptr),
+    mDefaultId(UINT_MAX),
+    mLocationCapabilitiesMask(0),
+    mGnssBatchingCbIface_2_0(nullptr)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    gnssUpdateCallbacks_2_0(callback);
+}
+
+BatchingAPIClient::~BatchingAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+int BatchingAPIClient::getBatchSize() {
+    int batchSize = locAPIGetBatchSize();
+    LOC_LOGd("batchSize: %d", batchSize);
+    return batchSize;
+}
+
+void BatchingAPIClient::setCallbacks()
+{
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.batchingCb = [this](size_t count, Location* location,
+        BatchingOptions batchOptions) {
+        onBatchingCb(count, location, batchOptions);
+    };
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+void BatchingAPIClient::gnssUpdateCallbacks(const sp<V1_0::IGnssBatchingCallback>& callback)
+{
+    mMutex.lock();
+    mGnssBatchingCbIface = callback;
+    mMutex.unlock();
+
+    if (mGnssBatchingCbIface != nullptr) {
+        setCallbacks();
+    }
+}
+
+void BatchingAPIClient::gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssBatchingCallback>& callback)
+{
+    mMutex.lock();
+    mGnssBatchingCbIface_2_0 = callback;
+    mMutex.unlock();
+
+    if (mGnssBatchingCbIface_2_0 != nullptr) {
+        setCallbacks();
+    }
+}
+
+int BatchingAPIClient::startSession(const IGnssBatching::Options& opts) {
+    mMutex.lock();
+    mState = STARTED;
+    mMutex.unlock();
+    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+    int retVal = -1;
+    LocationOptions options;
+    convertBatchOption(opts, options, mLocationCapabilitiesMask);
+    uint32_t mode = 0;
+    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+        mode = SESSION_MODE_ON_FULL;
+    }
+    if (locAPIStartSession(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+int BatchingAPIClient::updateSessionOptions(const IGnssBatching::Options& opts)
+{
+    LOC_LOGD("%s]: (%lld %d)", __FUNCTION__,
+            static_cast<long long>(opts.periodNanos), static_cast<uint8_t>(opts.flags));
+    int retVal = -1;
+    LocationOptions options;
+    convertBatchOption(opts, options, mLocationCapabilitiesMask);
+
+    uint32_t mode = 0;
+    if (opts.flags == static_cast<uint8_t>(IGnssBatching::Flag::WAKEUP_ON_FIFO_FULL)) {
+        mode = SESSION_MODE_ON_FULL;
+    }
+    if (locAPIUpdateSessionOptions(mDefaultId, mode, options) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+int BatchingAPIClient::stopSession() {
+    mMutex.lock();
+    mState = STOPPING;
+    mMutex.unlock();
+    LOC_LOGD("%s]: ", __FUNCTION__);
+    int retVal = -1;
+    locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
+    if (locAPIStopSession(mDefaultId) == LOCATION_ERROR_SUCCESS) {
+        retVal = 1;
+    }
+    return retVal;
+}
+
+void BatchingAPIClient::getBatchedLocation(int last_n_locations)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, last_n_locations);
+    locAPIGetBatchedLocations(mDefaultId, last_n_locations);
+}
+
+void BatchingAPIClient::flushBatchedLocations() {
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    uint32_t retVal = locAPIGetBatchedLocations(mDefaultId, SIZE_MAX);
+    // when flush a stopped session or one doesn't exist, just report an empty batch.
+    if (LOCATION_ERROR_ID_UNKNOWN == retVal) {
+        BatchingOptions opt = {};
+        ::std::thread thd(&BatchingAPIClient::onBatchingCb, this, 0, nullptr, opt);
+        thd.detach();
+    }
+}
+
+void BatchingAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+    LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
+    mLocationCapabilitiesMask = capabilitiesMask;
+}
+
+void BatchingAPIClient::onBatchingCb(size_t count, Location* location,
+        BatchingOptions /*batchOptions*/) {
+    bool processReport = false;
+    LOC_LOGd("(count: %zu)", count);
+    mMutex.lock();
+    // back to back stop() and flush() could bring twice onBatchingCb(). Each one might come first.
+    // Combine them both (the first goes to cache, the second in location*) before report to FW
+    switch (mState) {
+        case STOPPING:
+            mState = STOPPED;
+            for (size_t i = 0; i < count; i++) {
+                mBatchedLocationInCache.push_back(location[i]);
+            }
+            break;
+        case STARTED:
+        case STOPPED: // flush() always trigger report, even on a stopped session
+            processReport = true;
+            break;
+        default:
+            break;
+    }
+    // report location batch when in STARTED state or flush(), combined with cache in last stop()
+    if (processReport) {
+        auto gnssBatchingCbIface(mGnssBatchingCbIface);
+        auto gnssBatchingCbIface_2_0(mGnssBatchingCbIface_2_0);
+        size_t batchCacheCnt = mBatchedLocationInCache.size();
+        LOC_LOGd("(batchCacheCnt: %zu)", batchCacheCnt);
+        if (gnssBatchingCbIface_2_0 != nullptr) {
+            hidl_vec<V2_0::GnssLocation> locationVec;
+            if (count+batchCacheCnt > 0) {
+                locationVec.resize(count+batchCacheCnt);
+                for (size_t i = 0; i < batchCacheCnt; ++i) {
+                    convertGnssLocation(mBatchedLocationInCache[i], locationVec[i]);
+                }
+                for (size_t i = 0; i < count; i++) {
+                    convertGnssLocation(location[i], locationVec[i+batchCacheCnt]);
+                }
+            }
+            auto r = gnssBatchingCbIface_2_0->gnssLocationBatchCb(locationVec);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssLocationBatchCb 2_0 description=%s",
+                        __func__, r.description().c_str());
+            }
+        } else if (gnssBatchingCbIface != nullptr) {
+            hidl_vec<V1_0::GnssLocation> locationVec;
+            if (count+batchCacheCnt > 0) {
+                locationVec.resize(count+batchCacheCnt);
+                for (size_t i = 0; i < batchCacheCnt; ++i) {
+                    convertGnssLocation(mBatchedLocationInCache[i], locationVec[i]);
+                }
+                for (size_t i = 0; i < count; i++) {
+                    convertGnssLocation(location[i], locationVec[i+batchCacheCnt]);
+                }
+            }
+            auto r = gnssBatchingCbIface->gnssLocationBatchCb(locationVec);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssLocationBatchCb 1.0 description=%s",
+                        __func__, r.description().c_str());
+            }
+        }
+        mBatchedLocationInCache.clear();
+    }
+    mMutex.unlock();
+}
+
+static void convertBatchOption(const IGnssBatching::Options& in, LocationOptions& out,
+        LocationCapabilitiesMask mask)
+{
+    memset(&out, 0, sizeof(LocationOptions));
+    out.size = sizeof(LocationOptions);
+    out.minInterval = (uint32_t)(in.periodNanos / 1000000L);
+    out.minDistance = 0;
+    out.mode = GNSS_SUPL_MODE_STANDALONE;
+    if (mask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+        out.mode = GNSS_SUPL_MODE_MSA;
+    if (mask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+        out.mode = GNSS_SUPL_MODE_MSB;
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/location_api/BatchingAPIClient.h b/gps/android/2.1/location_api/BatchingAPIClient.h
new file mode 100755
index 0000000..2d9ab74
--- /dev/null
+++ b/gps/android/2.1/location_api/BatchingAPIClient.h
@@ -0,0 +1,88 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef BATCHING_API_CLINET_H
+#define BATCHING_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/2.0/IGnssBatching.h>
+#include <android/hardware/gnss/2.0/IGnssBatchingCallback.h>
+#include <pthread.h>
+
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+
+enum BATCHING_STATE { STARTED, STOPPING, STOPPED };
+
+class BatchingAPIClient : public LocationAPIClientBase
+{
+public:
+    BatchingAPIClient(const sp<V1_0::IGnssBatchingCallback>& callback);
+    BatchingAPIClient(const sp<V2_0::IGnssBatchingCallback>& callback);
+    void gnssUpdateCallbacks(const sp<V1_0::IGnssBatchingCallback>& callback);
+    void gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssBatchingCallback>& callback);
+    int getBatchSize();
+    int startSession(const V1_0::IGnssBatching::Options& options);
+    int updateSessionOptions(const V1_0::IGnssBatching::Options& options);
+    int stopSession();
+    void getBatchedLocation(int last_n_locations);
+    void flushBatchedLocations();
+
+    inline LocationCapabilitiesMask getCapabilities() { return mLocationCapabilitiesMask; }
+
+    // callbacks
+    void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+    void onBatchingCb(size_t count, Location* location, BatchingOptions batchOptions) final;
+
+private:
+    ~BatchingAPIClient();
+
+    void setCallbacks();
+    std::mutex mMutex;
+    sp<V1_0::IGnssBatchingCallback> mGnssBatchingCbIface;
+    uint32_t mDefaultId;
+    LocationCapabilitiesMask mLocationCapabilitiesMask;
+    sp<V2_0::IGnssBatchingCallback> mGnssBatchingCbIface_2_0;
+    volatile BATCHING_STATE mState = STOPPED;
+
+    std::vector<Location> mBatchedLocationInCache;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // BATCHING_API_CLINET_H
diff --git a/gps/android/2.1/location_api/GeofenceAPIClient.cpp b/gps/android/2.1/location_api/GeofenceAPIClient.cpp
new file mode 100755
index 0000000..6e63465
--- /dev/null
+++ b/gps/android/2.1/location_api/GeofenceAPIClient.cpp
@@ -0,0 +1,275 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_GeofenceApiClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GeofenceAPIClient.h"
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssGeofenceCallback;
+using ::android::hardware::gnss::V1_0::GnssLocation;
+
+GeofenceAPIClient::GeofenceAPIClient(const sp<IGnssGeofenceCallback>& callback) :
+    LocationAPIClientBase(),
+    mGnssGeofencingCbIface(callback)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+
+    locationCallbacks.geofenceBreachCb = nullptr;
+    if (mGnssGeofencingCbIface != nullptr) {
+        locationCallbacks.geofenceBreachCb =
+            [this](GeofenceBreachNotification geofenceBreachNotification) {
+                onGeofenceBreachCb(geofenceBreachNotification);
+            };
+
+        locationCallbacks.geofenceStatusCb =
+            [this](GeofenceStatusNotification geofenceStatusNotification) {
+                onGeofenceStatusCb(geofenceStatusNotification);
+            };
+    }
+
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+void GeofenceAPIClient::geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+        double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+        uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms)
+{
+    LOC_LOGD("%s]: (%d %f %f %f %d %d %d %d)", __FUNCTION__,
+            geofence_id, latitude, longitude, radius_meters,
+            last_transition, monitor_transitions, notification_responsiveness_ms, unknown_timer_ms);
+
+    GeofenceOption options;
+    memset(&options, 0, sizeof(GeofenceOption));
+    options.size = sizeof(GeofenceOption);
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+        options.breachTypeMask |= GEOFENCE_BREACH_ENTER_BIT;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+        options.breachTypeMask |=  GEOFENCE_BREACH_EXIT_BIT;
+    options.responsiveness = notification_responsiveness_ms;
+
+    GeofenceInfo data;
+    data.size = sizeof(GeofenceInfo);
+    data.latitude = latitude;
+    data.longitude = longitude;
+    data.radius = radius_meters;
+
+    LocationError err = (LocationError)locAPIAddGeofences(1, &geofence_id, &options, &data);
+    if (LOCATION_ERROR_SUCCESS != err) {
+        onAddGeofencesCb(1, &err, &geofence_id);
+    }
+}
+
+void GeofenceAPIClient::geofencePause(uint32_t geofence_id)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+    locAPIPauseGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceResume(uint32_t geofence_id, int32_t monitor_transitions)
+{
+    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, geofence_id, monitor_transitions);
+    GeofenceBreachTypeMask mask = 0;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::ENTERED)
+        mask |= GEOFENCE_BREACH_ENTER_BIT;
+    if (monitor_transitions & IGnssGeofenceCallback::GeofenceTransition::EXITED)
+        mask |=  GEOFENCE_BREACH_EXIT_BIT;
+    locAPIResumeGeofences(1, &geofence_id, &mask);
+}
+
+void GeofenceAPIClient::geofenceRemove(uint32_t geofence_id)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofence_id);
+    locAPIRemoveGeofences(1, &geofence_id);
+}
+
+void GeofenceAPIClient::geofenceRemoveAll()
+{
+    LOC_LOGD("%s]", __FUNCTION__);
+    // TODO locAPIRemoveAllGeofences();
+}
+
+// callbacks
+void GeofenceAPIClient::onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceBreachNotification.count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < geofenceBreachNotification.count; i++) {
+            GnssLocation gnssLocation;
+            convertGnssLocation(geofenceBreachNotification.location, gnssLocation);
+
+            IGnssGeofenceCallback::GeofenceTransition transition;
+            if (geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER)
+                transition = IGnssGeofenceCallback::GeofenceTransition::ENTERED;
+            else if (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT)
+                transition = IGnssGeofenceCallback::GeofenceTransition::EXITED;
+            else {
+                // continue with other breach if transition is
+                // nether GPS_GEOFENCE_ENTERED nor GPS_GEOFENCE_EXITED
+                continue;
+            }
+
+            auto r = mGnssGeofencingCbIface->gnssGeofenceTransitionCb(
+                    geofenceBreachNotification.ids[i], gnssLocation, transition,
+                    static_cast<V1_0::GnssUtcTime>(geofenceBreachNotification.timestamp));
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceTransitionCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, geofenceStatusNotification.available);
+    if (mGnssGeofencingCbIface != nullptr) {
+        IGnssGeofenceCallback::GeofenceAvailability status =
+            IGnssGeofenceCallback::GeofenceAvailability::UNAVAILABLE;
+        if (geofenceStatusNotification.available == GEOFENCE_STATUS_AVAILABILE_YES) {
+            status = IGnssGeofenceCallback::GeofenceAvailability::AVAILABLE;
+        }
+        GnssLocation gnssLocation;
+        memset(&gnssLocation, 0, sizeof(GnssLocation));
+        auto r = mGnssGeofencingCbIface->gnssGeofenceStatusCb(status, gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssGeofenceStatusCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GeofenceAPIClient::onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_EXISTS)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_EXISTS;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceAddCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceAddCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceRemoveCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceRemoveCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofencePauseCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofencePauseCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GeofenceAPIClient::onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids)
+{
+    LOC_LOGD("%s]: (%zu)", __FUNCTION__, count);
+    if (mGnssGeofencingCbIface != nullptr) {
+        for (size_t i = 0; i < count; i++) {
+            IGnssGeofenceCallback::GeofenceStatus status =
+                IGnssGeofenceCallback::GeofenceStatus::ERROR_GENERIC;
+            if (errors[i] == LOCATION_ERROR_SUCCESS)
+                status = IGnssGeofenceCallback::GeofenceStatus::OPERATION_SUCCESS;
+            else if (errors[i] == LOCATION_ERROR_ID_UNKNOWN)
+                status = IGnssGeofenceCallback::GeofenceStatus::ERROR_ID_UNKNOWN;
+            auto r = mGnssGeofencingCbIface->gnssGeofenceResumeCb(ids[i], status);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssGeofenceResumeCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/location_api/GeofenceAPIClient.h b/gps/android/2.1/location_api/GeofenceAPIClient.h
new file mode 100755
index 0000000..9ed289f
--- /dev/null
+++ b/gps/android/2.1/location_api/GeofenceAPIClient.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GEOFENCE_API_CLINET_H
+#define GEOFENCE_API_CLINET_H
+
+
+#include <android/hardware/gnss/1.0/IGnssGeofenceCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+
+class GeofenceAPIClient : public LocationAPIClientBase
+{
+public:
+    GeofenceAPIClient(const sp<V1_0::IGnssGeofenceCallback>& callback);
+
+    void geofenceAdd(uint32_t geofence_id, double latitude, double longitude,
+            double radius_meters, int32_t last_transition, int32_t monitor_transitions,
+            uint32_t notification_responsiveness_ms, uint32_t unknown_timer_ms);
+    void geofencePause(uint32_t geofence_id);
+    void geofenceResume(uint32_t geofence_id, int32_t monitor_transitions);
+    void geofenceRemove(uint32_t geofence_id);
+    void geofenceRemoveAll();
+
+    // callbacks
+    void onGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification) final;
+    void onGeofenceStatusCb(GeofenceStatusNotification geofenceStatusNotification) final;
+    void onAddGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onRemoveGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onPauseGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+    void onResumeGeofencesCb(size_t count, LocationError* errors, uint32_t* ids) final;
+
+private:
+    virtual ~GeofenceAPIClient() = default;
+
+    sp<V1_0::IGnssGeofenceCallback> mGnssGeofencingCbIface;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // GEOFENCE_API_CLINET_H
diff --git a/gps/android/2.1/location_api/GnssAPIClient.cpp b/gps/android/2.1/location_api/GnssAPIClient.cpp
new file mode 100644
index 0000000..07f617d
--- /dev/null
+++ b/gps/android/2.1/location_api/GnssAPIClient.cpp
@@ -0,0 +1,864 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_GnssAPIClient"
+#define SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC (590 * 60 * 60 * 1000) // 590 hours
+
+#include <inttypes.h>
+#include <log_util.h>
+#include <loc_cfg.h>
+
+#include "LocationUtil.h"
+#include "GnssAPIClient.h"
+#include <LocContext.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_1::IGnss;
+using ::android::hardware::gnss::V2_1::IGnssCallback;
+using ::android::hardware::gnss::V1_0::IGnssNiCallback;
+using ::android::hardware::gnss::V2_0::GnssLocation;
+
+static void convertGnssSvStatus(GnssSvNotification& in, V1_0::IGnssCallback::GnssSvStatus& out);
+static void convertGnssSvStatus(GnssSvNotification& in,
+        hidl_vec<V2_0::IGnssCallback::GnssSvInfo>& out);
+static void convertGnssSvStatus(GnssSvNotification& in,
+        hidl_vec<V2_1::IGnssCallback::GnssSvInfo>& out);
+
+GnssAPIClient::GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+        const sp<V1_0::IGnssNiCallback>& niCb) :
+    LocationAPIClientBase(),
+    mGnssCbIface(nullptr),
+    mGnssNiCbIface(nullptr),
+    mControlClient(new LocationAPIControlClient()),
+    mLocationCapabilitiesMask(0),
+    mLocationCapabilitiesCached(false),
+    mTracking(false),
+    mGnssCbIface_2_0(nullptr)
+{
+    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+    initLocationOptions();
+    gnssUpdateCallbacks(gpsCb, niCb);
+}
+
+GnssAPIClient::GnssAPIClient(const sp<V2_0::IGnssCallback>& gpsCb) :
+    LocationAPIClientBase(),
+    mGnssCbIface(nullptr),
+    mGnssNiCbIface(nullptr),
+    mControlClient(new LocationAPIControlClient()),
+    mLocationCapabilitiesMask(0),
+    mLocationCapabilitiesCached(false),
+    mTracking(false),
+    mGnssCbIface_2_0(nullptr)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &gpsCb);
+
+    initLocationOptions();
+    gnssUpdateCallbacks_2_0(gpsCb);
+}
+
+GnssAPIClient::GnssAPIClient(const sp<V2_1::IGnssCallback>& gpsCb) :
+    LocationAPIClientBase(),
+    mGnssCbIface(nullptr),
+    mGnssNiCbIface(nullptr),
+    mControlClient(new LocationAPIControlClient()),
+    mLocationCapabilitiesMask(0),
+    mLocationCapabilitiesCached(false),
+    mTracking(false),
+    mGnssCbIface_2_1(nullptr)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &gpsCb);
+
+    initLocationOptions();
+    gnssUpdateCallbacks_2_1(gpsCb);
+}
+
+GnssAPIClient::~GnssAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    if (mControlClient) {
+        delete mControlClient;
+        mControlClient = nullptr;
+    }
+}
+
+void GnssAPIClient::initLocationOptions()
+{
+    // set default LocationOptions.
+    memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+    mTrackingOptions.size = sizeof(TrackingOptions);
+    mTrackingOptions.minInterval = 1000;
+    mTrackingOptions.minDistance = 0;
+    mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+}
+
+void GnssAPIClient::setCallbacks()
+{
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.trackingCb = [this](Location location) {
+        onTrackingCb(location);
+    };
+
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    if (mGnssNiCbIface != nullptr) {
+        loc_core::ContextBase* context =
+                loc_core::LocContext::getLocContext(loc_core::LocContext::mLocationHalName);
+        if (!context->hasAgpsExtendedCapabilities()) {
+            LOC_LOGD("Registering NI CB");
+            locationCallbacks.gnssNiCb = [this](uint32_t id, GnssNiNotification gnssNiNotify) {
+                onGnssNiCb(id, gnssNiNotify);
+            };
+        }
+    }
+
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssSvCb = [this](GnssSvNotification gnssSvNotification) {
+        onGnssSvCb(gnssSvNotification);
+    };
+
+    locationCallbacks.gnssNmeaCb = nullptr;
+    locationCallbacks.gnssNmeaCb = [this](GnssNmeaNotification gnssNmeaNotification) {
+        onGnssNmeaCb(gnssNmeaNotification);
+    };
+
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+
+    locAPISetCallbacks(locationCallbacks);
+}
+
+// for GpsInterface
+void GnssAPIClient::gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+    const sp<IGnssNiCallback>& niCb)
+{
+    LOC_LOGD("%s]: (%p %p)", __FUNCTION__, &gpsCb, &niCb);
+
+    mMutex.lock();
+    mGnssCbIface = gpsCb;
+    mGnssNiCbIface = niCb;
+    mMutex.unlock();
+
+    if (mGnssCbIface != nullptr || mGnssNiCbIface != nullptr) {
+        setCallbacks();
+    }
+}
+
+void GnssAPIClient::gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssCallback>& gpsCb)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &gpsCb);
+
+    mMutex.lock();
+    mGnssCbIface_2_0 = gpsCb;
+    mMutex.unlock();
+
+    if (mGnssCbIface_2_0 != nullptr) {
+        setCallbacks();
+    }
+}
+
+void GnssAPIClient::gnssUpdateCallbacks_2_1(const sp<V2_1::IGnssCallback>& gpsCb)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &gpsCb);
+
+    mMutex.lock();
+    mGnssCbIface_2_1 = gpsCb;
+    mMutex.unlock();
+
+    if (mGnssCbIface_2_1 != nullptr) {
+        setCallbacks();
+    }
+}
+
+bool GnssAPIClient::gnssStart()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+
+    mMutex.lock();
+    mTracking = true;
+    mMutex.unlock();
+
+    bool retVal = true;
+    locAPIStartTracking(mTrackingOptions);
+    return retVal;
+}
+
+bool GnssAPIClient::gnssStop()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+
+    mMutex.lock();
+    mTracking = false;
+    mMutex.unlock();
+
+    bool retVal = true;
+    locAPIStopTracking();
+    return retVal;
+}
+
+bool GnssAPIClient::gnssSetPositionMode(IGnss::GnssPositionMode mode,
+        IGnss::GnssPositionRecurrence recurrence, uint32_t minIntervalMs,
+        uint32_t preferredAccuracyMeters, uint32_t preferredTimeMs,
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LOC_LOGD("%s]: (%d %d %d %d %d %d %d)", __FUNCTION__,
+            (int)mode, recurrence, minIntervalMs, preferredAccuracyMeters,
+            preferredTimeMs, (int)powerMode, timeBetweenMeasurement);
+    bool retVal = true;
+    memset(&mTrackingOptions, 0, sizeof(TrackingOptions));
+    mTrackingOptions.size = sizeof(TrackingOptions);
+    mTrackingOptions.minInterval = minIntervalMs;
+    if (IGnss::GnssPositionMode::MS_ASSISTED == mode ||
+            IGnss::GnssPositionRecurrence::RECURRENCE_SINGLE == recurrence) {
+        // We set a very large interval to simulate SINGLE mode. Once we report a fix,
+        // the caller should take the responsibility to stop the session.
+        // For MSA, we always treat it as SINGLE mode.
+        mTrackingOptions.minInterval = SINGLE_SHOT_MIN_TRACKING_INTERVAL_MSEC;
+    }
+    if (mode == IGnss::GnssPositionMode::STANDALONE)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_STANDALONE;
+    else if (mode == IGnss::GnssPositionMode::MS_BASED)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_MSB;
+    else if (mode ==  IGnss::GnssPositionMode::MS_ASSISTED)
+        mTrackingOptions.mode = GNSS_SUPL_MODE_MSA;
+    else {
+        LOC_LOGD("%s]: invalid GnssPositionMode: %d", __FUNCTION__, (int)mode);
+        retVal = false;
+    }
+    if (GNSS_POWER_MODE_INVALID != powerMode) {
+        mTrackingOptions.powerMode = powerMode;
+        mTrackingOptions.tbm = timeBetweenMeasurement;
+    }
+    locAPIUpdateTrackingOptions(mTrackingOptions);
+    return retVal;
+}
+
+// for GpsNiInterface
+void GnssAPIClient::gnssNiRespond(int32_t notifId,
+        IGnssNiCallback::GnssUserResponseType userResponse)
+{
+    LOC_LOGD("%s]: (%d %d)", __FUNCTION__, notifId, static_cast<int>(userResponse));
+    GnssNiResponse data;
+    switch (userResponse) {
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT:
+        data = GNSS_NI_RESPONSE_ACCEPT;
+        break;
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY:
+        data = GNSS_NI_RESPONSE_DENY;
+        break;
+    case IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP:
+        data = GNSS_NI_RESPONSE_NO_RESPONSE;
+        break;
+    default:
+        data = GNSS_NI_RESPONSE_IGNORE;
+        break;
+    }
+
+    locAPIGnssNiResponse(notifId, data);
+}
+
+// these apis using LocationAPIControlClient
+void GnssAPIClient::gnssDeleteAidingData(IGnss::GnssAidingData aidingDataFlags)
+{
+    LOC_LOGD("%s]: (%02hx)", __FUNCTION__, aidingDataFlags);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    GnssAidingData data;
+    memset(&data, 0, sizeof (GnssAidingData));
+    data.sv.svTypeMask = GNSS_AIDING_DATA_SV_TYPE_GPS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT |
+        GNSS_AIDING_DATA_SV_TYPE_NAVIC_BIT;
+    data.posEngineMask = STANDARD_POSITIONING_ENGINE;
+
+    if (aidingDataFlags == IGnss::GnssAidingData::DELETE_ALL)
+        data.deleteAll = true;
+    else {
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_EPHEMERIS)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_EPHEMERIS_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_ALMANAC)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_ALMANAC_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_POSITION)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_POSITION_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_TIME)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_TIME_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_IONO)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_IONOSPHERE_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_UTC)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_UTC_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_HEALTH)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_HEALTH_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVDIR)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_DIRECTION_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SVSTEER)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_STEER_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_SADATA)
+            data.sv.svMask |= GNSS_AIDING_DATA_SV_SA_DATA_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_RTI)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_RTI_BIT;
+        if (aidingDataFlags & IGnss::GnssAidingData::DELETE_CELLDB_INFO)
+            data.common.mask |= GNSS_AIDING_DATA_COMMON_CELLDB_BIT;
+    }
+    mControlClient->locAPIGnssDeleteAidingData(data);
+}
+
+void GnssAPIClient::gnssEnable(LocationTechnologyType techType)
+{
+    LOC_LOGD("%s]: (%0d)", __FUNCTION__, techType);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIEnable(techType);
+}
+
+void GnssAPIClient::gnssDisable()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIDisable();
+}
+
+void GnssAPIClient::gnssConfigurationUpdate(const GnssConfig& gnssConfig)
+{
+    LOC_LOGD("%s]: (%02x)", __FUNCTION__, gnssConfig.flags);
+    if (mControlClient == nullptr) {
+        return;
+    }
+    mControlClient->locAPIGnssUpdateConfig(gnssConfig);
+}
+
+void GnssAPIClient::requestCapabilities() {
+    // only send capablities if it's already cached, otherwise the first time LocationAPI
+    // is initialized, capabilities will be sent by LocationAPI
+    if (mLocationCapabilitiesCached) {
+        onCapabilitiesCb(mLocationCapabilitiesMask);
+    }
+}
+
+// callbacks
+void GnssAPIClient::onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask)
+{
+    LOC_LOGD("%s]: (%" PRIu64 ")", __FUNCTION__, capabilitiesMask);
+    mLocationCapabilitiesMask = capabilitiesMask;
+    mLocationCapabilitiesCached = true;
+
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    auto gnssCbIface_2_1(mGnssCbIface_2_1);
+    mMutex.unlock();
+
+    if (gnssCbIface_2_1 != nullptr ||gnssCbIface_2_0 != nullptr || gnssCbIface != nullptr) {
+
+        uint32_t antennaInfoVectorSize = 0;
+        uint32_t data = 0;
+        loc_param_s_type ant_info_vector_table[] =
+        {
+            { "ANTENNA_INFO_VECTOR_SIZE", &antennaInfoVectorSize, NULL, 'n' }
+        };
+        UTIL_READ_CONF(LOC_PATH_ANT_CORR, ant_info_vector_table);
+
+        if (0 != antennaInfoVectorSize) {
+            data |= V2_1::IGnssCallback::Capabilities::ANTENNA_INFO;
+        }
+
+        if ((capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT) ||
+                (capabilitiesMask & LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT))
+            data |= IGnssCallback::Capabilities::SCHEDULING;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GEOFENCE_BIT)
+            data |= V1_0::IGnssCallback::Capabilities::GEOFENCING;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT)
+            data |= V1_0::IGnssCallback::Capabilities::MEASUREMENTS;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSB_BIT)
+            data |= IGnssCallback::Capabilities::MSB;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MSA_BIT)
+            data |= IGnssCallback::Capabilities::MSA;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT)
+            data |= IGnssCallback::Capabilities::LOW_POWER_MODE;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT)
+            data |= IGnssCallback::Capabilities::SATELLITE_BLACKLIST;
+        if (capabilitiesMask & LOCATION_CAPABILITIES_MEASUREMENTS_CORRECTION_BIT)
+            data |= V2_0::IGnssCallback::Capabilities::MEASUREMENT_CORRECTIONS;
+
+        IGnssCallback::GnssSystemInfo gnssInfo = { .yearOfHw = 2015 };
+
+        if (capabilitiesMask & LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT) {
+            gnssInfo.yearOfHw++; // 2016
+            if (capabilitiesMask & LOCATION_CAPABILITIES_DEBUG_NMEA_BIT) {
+                gnssInfo.yearOfHw++; // 2017
+                if (capabilitiesMask & LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT ||
+                    capabilitiesMask & LOCATION_CAPABILITIES_AGPM_BIT) {
+                    gnssInfo.yearOfHw++; // 2018
+                    if (capabilitiesMask & LOCATION_CAPABILITIES_PRIVACY_BIT) {
+                        gnssInfo.yearOfHw++; // 2019
+                        if (capabilitiesMask & LOCATION_CAPABILITIES_MEASUREMENTS_CORRECTION_BIT) {
+                            gnssInfo.yearOfHw++; // 2020
+                        }
+                    }
+                }
+            }
+        }
+        LOC_LOGV("%s:%d] set_system_info_cb (%d)", __FUNCTION__, __LINE__, gnssInfo.yearOfHw);
+
+        if (gnssCbIface_2_1 != nullptr) {
+            auto r = gnssCbIface_2_1->gnssSetCapabilitiesCb_2_1(data);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetCapabilitiesCb_2_1 description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface_2_1->gnssSetSystemInfoCb(gnssInfo);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssCbIface_2_0 != nullptr) {
+            auto r = gnssCbIface_2_0->gnssSetCapabilitiesCb_2_0(data);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetCapabilitiesCb_2_0 description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface_2_0->gnssSetSystemInfoCb(gnssInfo);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssCbIface != nullptr) {
+            auto r = gnssCbIface->gnssSetCapabilitesCb(data);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetCapabilitesCb description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface->gnssSetSystemInfoCb(gnssInfo);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssSetSystemInfoCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+
+    }
+
+}
+
+void GnssAPIClient::onTrackingCb(Location location)
+{
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    auto gnssCbIface_2_1(mGnssCbIface_2_1);
+    bool isTracking = mTracking;
+    mMutex.unlock();
+
+    LOC_LOGD("%s]: (flags: %02x isTracking: %d)", __FUNCTION__, location.flags, isTracking);
+
+    if (!isTracking) {
+        return;
+    }
+
+    if (gnssCbIface_2_1 != nullptr) {
+        V2_0::GnssLocation gnssLocation;
+        convertGnssLocation(location, gnssLocation);
+        auto r = gnssCbIface_2_1->gnssLocationCb_2_0(gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationCb_2_0 description=%s",
+                __func__, r.description().c_str());
+        }
+    } else if (gnssCbIface_2_0 != nullptr) {
+        V2_0::GnssLocation gnssLocation;
+        convertGnssLocation(location, gnssLocation);
+        auto r = gnssCbIface_2_0->gnssLocationCb_2_0(gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationCb_2_0 description=%s",
+                __func__, r.description().c_str());
+        }
+    } else if (gnssCbIface != nullptr) {
+        V1_0::GnssLocation gnssLocation;
+        convertGnssLocation(location, gnssLocation);
+        auto r = gnssCbIface->gnssLocationCb(gnssLocation);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssLocationCb description=%s",
+                __func__, r.description().c_str());
+        }
+    } else {
+        LOC_LOGW("%s] No GNSS Interface ready for gnssLocationCb ", __FUNCTION__);
+    }
+
+}
+
+void GnssAPIClient::onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification)
+{
+    LOC_LOGD("%s]: (id: %d)", __FUNCTION__, id);
+    mMutex.lock();
+    auto gnssNiCbIface(mGnssNiCbIface);
+    mMutex.unlock();
+
+    if (gnssNiCbIface == nullptr) {
+        LOC_LOGE("%s]: mGnssNiCbIface is nullptr", __FUNCTION__);
+        return;
+    }
+
+    IGnssNiCallback::GnssNiNotification notificationGnss = {};
+
+    notificationGnss.notificationId = id;
+
+    if (gnssNiNotification.type == GNSS_NI_TYPE_VOICE)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::VOICE;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_SUPL)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_SUPL;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_CONTROL_PLANE)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::UMTS_CTRL_PLANE;
+    else if (gnssNiNotification.type == GNSS_NI_TYPE_EMERGENCY_SUPL)
+        notificationGnss.niType = IGnssNiCallback::GnssNiType::EMERGENCY_SUPL;
+
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_NOTIFICATION_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_NOTIFY;
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_VERIFICATION_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::NEED_VERIFY;
+    if (gnssNiNotification.options & GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT)
+        notificationGnss.notifyFlags |= IGnssNiCallback::GnssNiNotifyFlags::PRIVACY_OVERRIDE;
+
+    notificationGnss.timeoutSec = gnssNiNotification.timeout;
+
+    if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_ACCEPT)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_ACCEPT;
+    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_DENY)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_DENY;
+    else if (gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_NO_RESPONSE ||
+            gnssNiNotification.timeoutResponse == GNSS_NI_RESPONSE_IGNORE)
+        notificationGnss.defaultResponse = IGnssNiCallback::GnssUserResponseType::RESPONSE_NORESP;
+
+    notificationGnss.requestorId = gnssNiNotification.requestor;
+
+    notificationGnss.notificationMessage = gnssNiNotification.message;
+
+    if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+    else if (gnssNiNotification.requestorEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+        notificationGnss.requestorIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+    if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_NONE)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_NONE;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_GSM_DEFAULT)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_GSM_DEFAULT;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UTF8)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UTF8;
+    else if (gnssNiNotification.messageEncoding == GNSS_NI_ENCODING_TYPE_UCS2)
+        notificationGnss.notificationIdEncoding =
+            IGnssNiCallback::GnssNiEncodingType::ENC_SUPL_UCS2;
+
+    gnssNiCbIface->niNotifyCb(notificationGnss);
+}
+
+void GnssAPIClient::onGnssSvCb(GnssSvNotification gnssSvNotification)
+{
+    LOC_LOGD("%s]: (count: %u)", __FUNCTION__, gnssSvNotification.count);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    auto gnssCbIface_2_1(mGnssCbIface_2_1);
+    mMutex.unlock();
+
+    if (gnssCbIface_2_1 != nullptr) {
+        hidl_vec<V2_1::IGnssCallback::GnssSvInfo> svInfoList;
+        convertGnssSvStatus(gnssSvNotification, svInfoList);
+        auto r = gnssCbIface_2_1->gnssSvStatusCb_2_1(svInfoList);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSvStatusCb_2_1 description=%s",
+                __func__, r.description().c_str());
+        }
+    } else if (gnssCbIface_2_0 != nullptr) {
+        hidl_vec<V2_0::IGnssCallback::GnssSvInfo> svInfoList;
+        convertGnssSvStatus(gnssSvNotification, svInfoList);
+        auto r = gnssCbIface_2_0->gnssSvStatusCb_2_0(svInfoList);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSvStatusCb_2_0 description=%s",
+                __func__, r.description().c_str());
+        }
+    } else if (gnssCbIface != nullptr) {
+        V1_0::IGnssCallback::GnssSvStatus svStatus;
+        convertGnssSvStatus(gnssSvNotification, svStatus);
+        auto r = gnssCbIface->gnssSvStatusCb(svStatus);
+        if (!r.isOk()) {
+            LOC_LOGE("%s] Error from gnssSvStatusCb description=%s",
+                __func__, r.description().c_str());
+        }
+    }
+}
+
+void GnssAPIClient::onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification)
+{
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    auto gnssCbIface_2_1(mGnssCbIface_2_1);
+    mMutex.unlock();
+
+    if (gnssCbIface != nullptr || gnssCbIface_2_0 != nullptr| gnssCbIface_2_1 != nullptr) {
+        const std::string s(gnssNmeaNotification.nmea);
+        std::stringstream ss(s);
+        std::string each;
+        while(std::getline(ss, each, '\n')) {
+            each += '\n';
+            android::hardware::hidl_string nmeaString;
+            nmeaString.setToExternal(each.c_str(), each.length());
+            if (gnssCbIface_2_1 != nullptr) {
+                auto r = gnssCbIface_2_1->gnssNmeaCb(
+                        static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+                if (!r.isOk()) {
+                    LOC_LOGE("%s] Error from gnssCbIface_2_1 nmea=%s length=%u description=%s",
+                             __func__, gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+                             r.description().c_str());
+                }
+            } else if (gnssCbIface_2_0 != nullptr) {
+                auto r = gnssCbIface_2_0->gnssNmeaCb(
+                        static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+                if (!r.isOk()) {
+                    LOC_LOGE("%s] Error from gnssCbIface_2_0 nmea=%s length=%u description=%s",
+                             __func__, gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+                             r.description().c_str());
+                }
+            } else if (gnssCbIface != nullptr) {
+                auto r = gnssCbIface->gnssNmeaCb(
+                        static_cast<V1_0::GnssUtcTime>(gnssNmeaNotification.timestamp), nmeaString);
+                if (!r.isOk()) {
+                    LOC_LOGE("%s] Error from gnssNmeaCb nmea=%s length=%u description=%s",
+                             __func__, gnssNmeaNotification.nmea, gnssNmeaNotification.length,
+                             r.description().c_str());
+                }
+            }
+        }
+    }
+}
+
+void GnssAPIClient::onStartTrackingCb(LocationError error)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    auto gnssCbIface_2_1(mGnssCbIface_2_1);
+    mMutex.unlock();
+
+    if (error == LOCATION_ERROR_SUCCESS) {
+        if (gnssCbIface_2_1 != nullptr) {
+            auto r = gnssCbIface_2_1->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2_0 ENGINE_ON description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface_2_1->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2_0 SESSION_BEGIN description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssCbIface_2_0 != nullptr) {
+            auto r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2_0 ENGINE_ON description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2_0 SESSION_BEGIN description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssCbIface != nullptr) {
+            auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_ON);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb ENGINE_ON description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_BEGIN);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb SESSION_BEGIN description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+void GnssAPIClient::onStopTrackingCb(LocationError error)
+{
+    LOC_LOGD("%s]: (%d)", __FUNCTION__, error);
+    mMutex.lock();
+    auto gnssCbIface(mGnssCbIface);
+    auto gnssCbIface_2_0(mGnssCbIface_2_0);
+    auto gnssCbIface_2_1(mGnssCbIface_2_1);
+    mMutex.unlock();
+
+    if (error == LOCATION_ERROR_SUCCESS) {
+        if (gnssCbIface_2_1 != nullptr) {
+            auto r = gnssCbIface_2_1->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2_0 SESSION_END description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface_2_1->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2_0 ENGINE_OFF description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssCbIface_2_0 != nullptr) {
+            auto r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2_0 SESSION_END description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface_2_0->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb 2_0 ENGINE_OFF description=%s",
+                    __func__, r.description().c_str());
+            }
+
+        } else if (gnssCbIface != nullptr) {
+            auto r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::SESSION_END);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb SESSION_END description=%s",
+                    __func__, r.description().c_str());
+            }
+            r = gnssCbIface->gnssStatusCb(IGnssCallback::GnssStatusValue::ENGINE_OFF);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssStatusCb ENGINE_OFF description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in, V1_0::IGnssCallback::GnssSvStatus& out)
+{
+    memset(&out, 0, sizeof(IGnssCallback::GnssSvStatus));
+    out.numSvs = in.count;
+    if (out.numSvs > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+        LOC_LOGW("%s]: Too many satellites %u. Clamps to %d.",
+                __FUNCTION__,  out.numSvs, V1_0::GnssMax::SVS_COUNT);
+        out.numSvs = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+    }
+    for (size_t i = 0; i < out.numSvs; i++) {
+        convertGnssSvid(in.gnssSvs[i], out.gnssSvList[i].svid);
+        convertGnssConstellationType(in.gnssSvs[i].type, out.gnssSvList[i].constellation);
+        out.gnssSvList[i].cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+        out.gnssSvList[i].elevationDegrees = in.gnssSvs[i].elevation;
+        out.gnssSvList[i].azimuthDegrees = in.gnssSvs[i].azimuth;
+        out.gnssSvList[i].carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+        out.gnssSvList[i].svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+            out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+            out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+            out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+            out.gnssSvList[i].svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+    }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in,
+        hidl_vec<V2_0::IGnssCallback::GnssSvInfo>& out)
+{
+    out.resize(in.count);
+    for (size_t i = 0; i < in.count; i++) {
+        convertGnssSvid(in.gnssSvs[i], out[i].v1_0.svid);
+        out[i].v1_0.cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+        out[i].v1_0.elevationDegrees = in.gnssSvs[i].elevation;
+        out[i].v1_0.azimuthDegrees = in.gnssSvs[i].azimuth;
+        out[i].v1_0.carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+        out[i].v1_0.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+            out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+            out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+            out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+            out[i].v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+
+        convertGnssConstellationType(in.gnssSvs[i].type, out[i].constellation);
+    }
+}
+
+static void convertGnssSvStatus(GnssSvNotification& in,
+        hidl_vec<V2_1::IGnssCallback::GnssSvInfo>& out)
+{
+    out.resize(in.count);
+    for (size_t i = 0; i < in.count; i++) {
+        convertGnssSvid(in.gnssSvs[i], out[i].v2_0.v1_0.svid);
+        out[i].v2_0.v1_0.cN0Dbhz = in.gnssSvs[i].cN0Dbhz;
+        out[i].v2_0.v1_0.elevationDegrees = in.gnssSvs[i].elevation;
+        out[i].v2_0.v1_0.azimuthDegrees = in.gnssSvs[i].azimuth;
+        out[i].v2_0.v1_0.carrierFrequencyHz = in.gnssSvs[i].carrierFrequencyHz;
+        out[i].v2_0.v1_0.svFlag = static_cast<uint8_t>(IGnssCallback::GnssSvFlags::NONE);
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_EPHEMER_BIT)
+            out[i].v2_0.v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_EPHEMERIS_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_ALMANAC_BIT)
+            out[i].v2_0.v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_ALMANAC_DATA;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_USED_IN_FIX_BIT)
+            out[i].v2_0.v1_0.svFlag |= IGnssCallback::GnssSvFlags::USED_IN_FIX;
+        if (in.gnssSvs[i].gnssSvOptionsMask & GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT)
+            out[i].v2_0.v1_0.svFlag |= IGnssCallback::GnssSvFlags::HAS_CARRIER_FREQUENCY;
+
+        convertGnssConstellationType(in.gnssSvs[i].type, out[i].v2_0.constellation);
+        out[i].basebandCN0DbHz = in.gnssSvs[i].basebandCarrierToNoiseDbHz;
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/location_api/GnssAPIClient.h b/gps/android/2.1/location_api/GnssAPIClient.h
new file mode 100755
index 0000000..c4dbe9a
--- /dev/null
+++ b/gps/android/2.1/location_api/GnssAPIClient.h
@@ -0,0 +1,118 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef GNSS_API_CLINET_H
+#define GNSS_API_CLINET_H
+
+
+#include <mutex>
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <android/hardware/gnss/2.1/IGnssCallback.h>
+#include <LocationAPIClientBase.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+
+class GnssAPIClient : public LocationAPIClientBase
+{
+public:
+    GnssAPIClient(const sp<V1_0::IGnssCallback>& gpsCb,
+            const sp<V1_0::IGnssNiCallback>& niCb);
+    GnssAPIClient(const sp<V2_0::IGnssCallback>& gpsCb);
+    GnssAPIClient(const sp<V2_1::IGnssCallback>& gpsCb);
+    GnssAPIClient(const GnssAPIClient&) = delete;
+    GnssAPIClient& operator=(const GnssAPIClient&) = delete;
+
+    // for GpsInterface
+    void gnssUpdateCallbacks(const sp<V1_0::IGnssCallback>& gpsCb,
+            const sp<V1_0::IGnssNiCallback>& niCb);
+    void gnssUpdateCallbacks_2_0(const sp<V2_0::IGnssCallback>& gpsCb);
+    void gnssUpdateCallbacks_2_1(const sp<V2_1::IGnssCallback>& gpsCb);
+    bool gnssStart();
+    bool gnssStop();
+    bool gnssSetPositionMode(V1_0::IGnss::GnssPositionMode mode,
+            V1_0::IGnss::GnssPositionRecurrence recurrence,
+            uint32_t minIntervalMs,
+            uint32_t preferredAccuracyMeters,
+            uint32_t preferredTimeMs,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = 0);
+
+    // for GpsNiInterface
+    void gnssNiRespond(int32_t notifId, V1_0::IGnssNiCallback::GnssUserResponseType userResponse);
+
+    // these apis using LocationAPIControlClient
+    void gnssDeleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags);
+    void gnssEnable(LocationTechnologyType techType);
+    void gnssDisable();
+    void gnssConfigurationUpdate(const GnssConfig& gnssConfig);
+
+    inline LocationCapabilitiesMask gnssGetCapabilities() const {
+        return mLocationCapabilitiesMask;
+    }
+    void requestCapabilities();
+
+    // callbacks we are interested in
+    void onCapabilitiesCb(LocationCapabilitiesMask capabilitiesMask) final;
+    void onTrackingCb(Location location) final;
+    void onGnssNiCb(uint32_t id, GnssNiNotification gnssNiNotification) final;
+    void onGnssSvCb(GnssSvNotification gnssSvNotification) final;
+    void onGnssNmeaCb(GnssNmeaNotification gnssNmeaNotification) final;
+
+    void onStartTrackingCb(LocationError error) final;
+    void onStopTrackingCb(LocationError error) final;
+
+private:
+    virtual ~GnssAPIClient();
+    void setCallbacks();
+    void initLocationOptions();
+
+    sp<V1_0::IGnssCallback> mGnssCbIface;
+    sp<V1_0::IGnssNiCallback> mGnssNiCbIface;
+    std::mutex mMutex;
+    LocationAPIControlClient* mControlClient;
+    LocationCapabilitiesMask mLocationCapabilitiesMask;
+    bool mLocationCapabilitiesCached;
+    TrackingOptions mTrackingOptions;
+    bool mTracking;
+    sp<V2_0::IGnssCallback> mGnssCbIface_2_0;
+    sp<V2_1::IGnssCallback> mGnssCbIface_2_1;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // GNSS_API_CLINET_H
diff --git a/gps/android/2.1/location_api/LocationUtil.cpp b/gps/android/2.1/location_api/LocationUtil.cpp
new file mode 100644
index 0000000..5154e70
--- /dev/null
+++ b/gps/android/2.1/location_api/LocationUtil.cpp
@@ -0,0 +1,405 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <LocationUtil.h>
+#include <log_util.h>
+#include <inttypes.h>
+#include <loc_misc_utils.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V2_0::GnssLocation;
+using ::android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
+using ::android::hardware::gnss::V2_0::GnssConstellationType;
+using ::android::hardware::gnss::V1_0::GnssLocationFlags;
+using ::android::hardware::gnss::measurement_corrections::V1_0::GnssSingleSatCorrectionFlags;
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out)
+{
+    memset(&out, 0, sizeof(V1_0::GnssLocation));
+    if (in.flags & LOCATION_HAS_LAT_LONG_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_LAT_LONG;
+        out.latitudeDegrees = in.latitude;
+        out.longitudeDegrees = in.longitude;
+    }
+    if (in.flags & LOCATION_HAS_ALTITUDE_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE;
+        out.altitudeMeters = in.altitude;
+    }
+    if (in.flags & LOCATION_HAS_SPEED_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
+        out.speedMetersPerSec = in.speed;
+    }
+    if (in.flags & LOCATION_HAS_BEARING_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
+        out.bearingDegrees = in.bearing;
+    }
+    if (in.flags & LOCATION_HAS_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
+        out.horizontalAccuracyMeters = in.accuracy;
+    }
+    if (in.flags & LOCATION_HAS_VERTICAL_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
+        out.verticalAccuracyMeters = in.verticalAccuracy;
+    }
+    if (in.flags & LOCATION_HAS_SPEED_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED_ACCURACY;
+        out.speedAccuracyMetersPerSecond = in.speedAccuracy;
+    }
+    if (in.flags & LOCATION_HAS_BEARING_ACCURACY_BIT) {
+        out.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING_ACCURACY;
+        out.bearingAccuracyDegrees = in.bearingAccuracy;
+    }
+
+    out.timestamp = static_cast<V1_0::GnssUtcTime>(in.timestamp);
+}
+
+void convertGnssLocation(Location& in, V2_0::GnssLocation& out)
+{
+    memset(&out, 0, sizeof(V2_0::GnssLocation));
+    convertGnssLocation(in, out.v1_0);
+
+    if (in.flags & LOCATION_HAS_ELAPSED_REAL_TIME) {
+        out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIMESTAMP_NS;
+        out.elapsedRealtime.timestampNs = in.elapsedRealTime;
+        out.elapsedRealtime.flags |= ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS;
+        out.elapsedRealtime.timeUncertaintyNs = in.elapsedRealTimeUnc;
+        LOC_LOGd("out.elapsedRealtime.timestampNs=%" PRIi64 ""
+                 " out.elapsedRealtime.timeUncertaintyNs=%" PRIi64 ""
+                 " out.elapsedRealtime.flags=0x%X",
+                 out.elapsedRealtime.timestampNs,
+                 out.elapsedRealtime.timeUncertaintyNs, out.elapsedRealtime.flags);
+    }
+}
+
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_LAT_LONG) {
+        out.flags |= LOCATION_HAS_LAT_LONG_BIT;
+        out.latitude = in.latitudeDegrees;
+        out.longitude = in.longitudeDegrees;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_ALTITUDE) {
+        out.flags |= LOCATION_HAS_ALTITUDE_BIT;
+        out.altitude = in.altitudeMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED) {
+        out.flags |= LOCATION_HAS_SPEED_BIT;
+        out.speed = in.speedMetersPerSec;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING) {
+        out.flags |= LOCATION_HAS_BEARING_BIT;
+        out.bearing = in.bearingDegrees;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_HORIZONTAL_ACCURACY) {
+        out.flags |= LOCATION_HAS_ACCURACY_BIT;
+        out.accuracy = in.horizontalAccuracyMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_VERTICAL_ACCURACY) {
+        out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+        out.verticalAccuracy = in.verticalAccuracyMeters;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_SPEED_ACCURACY) {
+        out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+        out.speedAccuracy = in.speedAccuracyMetersPerSecond;
+    }
+    if (in.gnssLocationFlags & GnssLocationFlags::HAS_BEARING_ACCURACY) {
+        out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+        out.bearingAccuracy = in.bearingAccuracyDegrees;
+    }
+
+    out.timestamp = static_cast<uint64_t>(in.timestamp);
+}
+
+void convertGnssLocation(const V2_0::GnssLocation& in, Location& out)
+{
+    memset(&out, 0, sizeof(out));
+    convertGnssLocation(in.v1_0, out);
+}
+
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out)
+{
+    switch(in) {
+        case GNSS_SV_TYPE_GPS:
+            out = V1_0::GnssConstellationType::GPS;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = V1_0::GnssConstellationType::SBAS;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            out = V1_0::GnssConstellationType::GLONASS;
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = V1_0::GnssConstellationType::QZSS;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = V1_0::GnssConstellationType::BEIDOU;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = V1_0::GnssConstellationType::GALILEO;
+            break;
+        case GNSS_SV_TYPE_UNKNOWN:
+        default:
+            out = V1_0::GnssConstellationType::UNKNOWN;
+            break;
+    }
+}
+
+void convertGnssConstellationType(GnssSvType& in, V2_0::GnssConstellationType& out)
+{
+    switch(in) {
+        case GNSS_SV_TYPE_GPS:
+            out = V2_0::GnssConstellationType::GPS;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = V2_0::GnssConstellationType::SBAS;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            out = V2_0::GnssConstellationType::GLONASS;
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = V2_0::GnssConstellationType::QZSS;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = V2_0::GnssConstellationType::BEIDOU;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = V2_0::GnssConstellationType::GALILEO;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = V2_0::GnssConstellationType::IRNSS;
+            break;
+        case GNSS_SV_TYPE_UNKNOWN:
+        default:
+            out = V2_0::GnssConstellationType::UNKNOWN;
+            break;
+    }
+}
+
+void convertGnssSvid(GnssSv& in, int16_t& out)
+{
+    switch (in.type) {
+        case GNSS_SV_TYPE_GPS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            if (!isGloSlotUnknown(in.svId)) { // OSN is known
+                out = in.svId - GLO_SV_PRN_MIN + 1;
+            } else { // OSN is not known, report FCN
+                out = in.gloFrequency + 92;
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = in.svId - BDS_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = in.svId - GAL_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = in.svId - NAVIC_SV_PRN_MIN + 1;
+            break;
+        default:
+            out = in.svId;
+            break;
+    }
+}
+
+void convertGnssSvid(GnssMeasurementsData& in, int16_t& out)
+{
+    switch (in.svType) {
+        case GNSS_SV_TYPE_GPS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_SBAS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            if (!isGloSlotUnknown(in.svId)) { // OSN is known
+                out = in.svId - GLO_SV_PRN_MIN + 1;
+            } else { // OSN is not known, report FCN
+                out = in.gloFrequency + 92;
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            out = in.svId;
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            out = in.svId - BDS_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            out = in.svId - GAL_SV_PRN_MIN + 1;
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            out = in.svId - NAVIC_SV_PRN_MIN + 1;
+            break;
+        default:
+            out = in.svId;
+            break;
+    }
+}
+
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out)
+{
+    switch(in) {
+        case GNSS_EPH_TYPE_EPHEMERIS:
+            out = GnssDebug::SatelliteEphemerisType::EPHEMERIS;
+            break;
+        case GNSS_EPH_TYPE_ALMANAC:
+            out = GnssDebug::SatelliteEphemerisType::ALMANAC_ONLY;
+            break;
+        case GNSS_EPH_TYPE_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisType::NOT_AVAILABLE;
+            break;
+    }
+}
+
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out)
+{
+    switch(in) {
+        case GNSS_EPH_SOURCE_DEMODULATED:
+            out = GnssDebug::SatelliteEphemerisSource::DEMODULATED;
+            break;
+        case GNSS_EPH_SOURCE_SUPL_PROVIDED:
+            out = GnssDebug::SatelliteEphemerisSource::SUPL_PROVIDED;
+            break;
+        case GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED:
+            out = GnssDebug::SatelliteEphemerisSource::OTHER_SERVER_PROVIDED;
+            break;
+        case GNSS_EPH_SOURCE_LOCAL:
+        case GNSS_EPH_SOURCE_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisSource::OTHER;
+            break;
+    }
+}
+
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out)
+{
+    switch(in) {
+        case GNSS_EPH_HEALTH_GOOD:
+            out = GnssDebug::SatelliteEphemerisHealth::GOOD;
+            break;
+        case GNSS_EPH_HEALTH_BAD:
+            out = GnssDebug::SatelliteEphemerisHealth::BAD;
+            break;
+        case GNSS_EPH_HEALTH_UNKNOWN:
+        default:
+            out = GnssDebug::SatelliteEphemerisHealth::UNKNOWN;
+            break;
+    }
+}
+
+void convertSingleSatCorrections(const SingleSatCorrection& in, GnssSingleSatCorrection& out)
+{
+    out.flags = GNSS_MEAS_CORR_UNKNOWN_BIT;
+    if (in.singleSatCorrectionFlags & (GnssSingleSatCorrectionFlags::HAS_SAT_IS_LOS_PROBABILITY)) {
+        out.flags |= GNSS_MEAS_CORR_HAS_SAT_IS_LOS_PROBABILITY_BIT;
+    }
+    if (in.singleSatCorrectionFlags & (GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH)) {
+        out.flags |= GNSS_MEAS_CORR_HAS_EXCESS_PATH_LENGTH_BIT;
+    }
+    if (in.singleSatCorrectionFlags & (GnssSingleSatCorrectionFlags::HAS_EXCESS_PATH_LENGTH_UNC)) {
+        out.flags |= GNSS_MEAS_CORR_HAS_EXCESS_PATH_LENGTH_UNC_BIT;
+    }
+    if (in.singleSatCorrectionFlags & (GnssSingleSatCorrectionFlags::HAS_REFLECTING_PLANE)) {
+        out.flags |= GNSS_MEAS_CORR_HAS_REFLECTING_PLANE_BIT;
+    }
+    switch (in.constellation) {
+    case (::android::hardware::gnss::V1_0::GnssConstellationType::GPS):
+        out.svType = GNSS_SV_TYPE_GPS;
+        break;
+    case (::android::hardware::gnss::V1_0::GnssConstellationType::SBAS):
+        out.svType = GNSS_SV_TYPE_SBAS;
+        break;
+    case (::android::hardware::gnss::V1_0::GnssConstellationType::GLONASS):
+        out.svType = GNSS_SV_TYPE_GLONASS;
+        break;
+    case (::android::hardware::gnss::V1_0::GnssConstellationType::QZSS):
+        out.svType = GNSS_SV_TYPE_QZSS;
+        break;
+    case (::android::hardware::gnss::V1_0::GnssConstellationType::BEIDOU):
+        out.svType = GNSS_SV_TYPE_BEIDOU;
+        break;
+    case (::android::hardware::gnss::V1_0::GnssConstellationType::GALILEO):
+        out.svType = GNSS_SV_TYPE_GALILEO;
+        break;
+    case (::android::hardware::gnss::V1_0::GnssConstellationType::UNKNOWN):
+    default:
+        out.svType = GNSS_SV_TYPE_UNKNOWN;
+        break;
+    }
+    out.svId = in.svid;
+    out.carrierFrequencyHz = in.carrierFrequencyHz;
+    out.probSatIsLos = in.probSatIsLos;
+    out.excessPathLengthMeters = in.excessPathLengthMeters;
+    out.excessPathLengthUncertaintyMeters = in.excessPathLengthUncertaintyMeters;
+
+    out.reflectingPlane.latitudeDegrees = in.reflectingPlane.latitudeDegrees;
+    out.reflectingPlane.longitudeDegrees = in.reflectingPlane.longitudeDegrees;
+    out.reflectingPlane.altitudeMeters = in.reflectingPlane.altitudeMeters;
+    out.reflectingPlane.azimuthDegrees = in.reflectingPlane.azimuthDegrees;
+}
+
+void convertMeasurementCorrections(const MeasurementCorrectionsV1_0& in,
+                                   GnssMeasurementCorrections& out)
+{
+    memset(&out, 0, sizeof(GnssMeasurementCorrections));
+    out.latitudeDegrees = in.latitudeDegrees;
+    out.longitudeDegrees = in.longitudeDegrees;
+    out.altitudeMeters = in.altitudeMeters;
+    out.horizontalPositionUncertaintyMeters = in.horizontalPositionUncertaintyMeters;
+    out.verticalPositionUncertaintyMeters = in.verticalPositionUncertaintyMeters;
+    out.toaGpsNanosecondsOfWeek = in.toaGpsNanosecondsOfWeek;
+
+    for (int i = 0; i < in.satCorrections.size(); i++) {
+        GnssSingleSatCorrection gnssSingleSatCorrection = {};
+
+        convertSingleSatCorrections(in.satCorrections[i], gnssSingleSatCorrection);
+        out.satCorrections.push_back(gnssSingleSatCorrection);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/location_api/LocationUtil.h b/gps/android/2.1/location_api/LocationUtil.h
new file mode 100644
index 0000000..2d95a2d
--- /dev/null
+++ b/gps/android/2.1/location_api/LocationUtil.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOCATION_UTIL_H
+#define LOCATION_UTIL_H
+
+#include <android/hardware/gnss/2.0/types.h>
+#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
+#include <LocationAPI.h>
+#include <GnssDebug.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using MeasurementCorrectionsV1_0 =
+        ::android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
+using ::android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
+
+void convertGnssLocation(Location& in, V1_0::GnssLocation& out);
+void convertGnssLocation(Location& in, V2_0::GnssLocation& out);
+void convertGnssLocation(const V1_0::GnssLocation& in, Location& out);
+void convertGnssLocation(const V2_0::GnssLocation& in, Location& out);
+void convertGnssConstellationType(GnssSvType& in, V1_0::GnssConstellationType& out);
+void convertGnssConstellationType(GnssSvType& in, V2_0::GnssConstellationType& out);
+void convertGnssSvid(GnssSv& in, int16_t& out);
+void convertGnssSvid(GnssMeasurementsData& in, int16_t& out);
+void convertGnssEphemerisType(GnssEphemerisType& in, GnssDebug::SatelliteEphemerisType& out);
+void convertGnssEphemerisSource(GnssEphemerisSource& in, GnssDebug::SatelliteEphemerisSource& out);
+void convertGnssEphemerisHealth(GnssEphemerisHealth& in, GnssDebug::SatelliteEphemerisHealth& out);
+void convertSingleSatCorrections(const SingleSatCorrection& in, GnssSingleSatCorrection& out);
+void convertMeasurementCorrections(const MeasurementCorrectionsV1_0& in,
+                                   GnssMeasurementCorrections& out);
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // LOCATION_UTIL_H
diff --git a/gps/android/2.1/location_api/MeasurementAPIClient.cpp b/gps/android/2.1/location_api/MeasurementAPIClient.cpp
new file mode 100644
index 0000000..0028074
--- /dev/null
+++ b/gps/android/2.1/location_api/MeasurementAPIClient.cpp
@@ -0,0 +1,642 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_MeasurementAPIClient"
+
+#include <log_util.h>
+#include <loc_cfg.h>
+#include <inttypes.h>
+
+#include "LocationUtil.h"
+#include "MeasurementAPIClient.h"
+#include <loc_misc_utils.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::hardware::gnss::V1_0::IGnssMeasurement;
+using ::android::hardware::gnss::V2_0::IGnssMeasurementCallback;
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+        V1_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+        V1_1::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssData_2_0(GnssMeasurementsNotification& in,
+        V2_0::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssData_2_1(GnssMeasurementsNotification& in,
+        V2_1::IGnssMeasurementCallback::GnssData& out);
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+        V1_0::IGnssMeasurementCallback::GnssMeasurement& out);
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out);
+static void convertGnssClock_2_1(GnssMeasurementsClock& in,
+        V2_1::IGnssMeasurementCallback::GnssClock& out);
+static void convertGnssMeasurementsCodeType(GnssMeasurementsCodeType& inCodeType,
+        char* inOtherCodeTypeName,
+        ::android::hardware::hidl_string& out);
+static void convertGnssMeasurementsAccumulatedDeltaRangeState(GnssMeasurementsAdrStateMask& in,
+        ::android::hardware::hidl_bitfield
+                <V1_1::IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState>& out);
+static void convertGnssMeasurementsState(GnssMeasurementsStateMask& in,
+        ::android::hardware::hidl_bitfield
+                <V2_0::IGnssMeasurementCallback::GnssMeasurementState>& out);
+static void convertElapsedRealtimeNanos(GnssMeasurementsNotification& in,
+        ::android::hardware::gnss::V2_0::ElapsedRealtime& elapsedRealtimeNanos);
+
+MeasurementAPIClient::MeasurementAPIClient() :
+    mGnssMeasurementCbIface(nullptr),
+    mGnssMeasurementCbIface_1_1(nullptr),
+    mGnssMeasurementCbIface_2_0(nullptr),
+    mGnssMeasurementCbIface_2_1(nullptr),
+    mTracking(false)
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+MeasurementAPIClient::~MeasurementAPIClient()
+{
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+}
+
+void MeasurementAPIClient::clearInterfaces()
+{
+    mGnssMeasurementCbIface = nullptr;
+    mGnssMeasurementCbIface_1_1 = nullptr;
+    mGnssMeasurementCbIface_2_0 = nullptr;
+    mGnssMeasurementCbIface_2_1 = nullptr;
+}
+
+// for GpsInterface
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback(const sp<V1_0::IGnssMeasurementCallback>& callback)
+{
+    LOC_LOGD("%s]: (%p)", __FUNCTION__, &callback);
+
+    mMutex.lock();
+    clearInterfaces();
+    mGnssMeasurementCbIface = callback;
+    mMutex.unlock();
+
+    return startTracking();
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback_1_1(
+        const sp<V1_1::IGnssMeasurementCallback>& callback,
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LOC_LOGD("%s]: (%p) (powermode: %d) (tbm: %d)",
+            __FUNCTION__, &callback, (int)powerMode, timeBetweenMeasurement);
+
+    mMutex.lock();
+    clearInterfaces();
+    mGnssMeasurementCbIface_1_1 = callback;
+    mMutex.unlock();
+
+    return startTracking(powerMode, timeBetweenMeasurement);
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::measurementSetCallback_2_0(
+    const sp<V2_0::IGnssMeasurementCallback>& callback,
+    GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LOC_LOGD("%s]: (%p) (powermode: %d) (tbm: %d)",
+        __FUNCTION__, &callback, (int)powerMode, timeBetweenMeasurement);
+
+    mMutex.lock();
+    clearInterfaces();
+    mGnssMeasurementCbIface_2_0 = callback;
+    mMutex.unlock();
+
+    return startTracking(powerMode, timeBetweenMeasurement);
+}
+
+Return<IGnssMeasurement::GnssMeasurementStatus> MeasurementAPIClient::measurementSetCallback_2_1(
+        const sp<V2_1::IGnssMeasurementCallback>& callback,
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement) {
+    LOC_LOGD("%s]: (%p) (powermode: %d) (tbm: %d)",
+        __FUNCTION__, &callback, (int)powerMode, timeBetweenMeasurement);
+
+    mMutex.lock();
+    clearInterfaces();
+    mGnssMeasurementCbIface_2_1 = callback;
+    mMutex.unlock();
+
+    return startTracking(powerMode, timeBetweenMeasurement);
+}
+Return<IGnssMeasurement::GnssMeasurementStatus>
+MeasurementAPIClient::startTracking(
+        GnssPowerMode powerMode, uint32_t timeBetweenMeasurement)
+{
+    LocationCallbacks locationCallbacks;
+    memset(&locationCallbacks, 0, sizeof(LocationCallbacks));
+    locationCallbacks.size = sizeof(LocationCallbacks);
+
+    locationCallbacks.trackingCb = nullptr;
+    locationCallbacks.batchingCb = nullptr;
+    locationCallbacks.geofenceBreachCb = nullptr;
+    locationCallbacks.geofenceStatusCb = nullptr;
+    locationCallbacks.gnssLocationInfoCb = nullptr;
+    locationCallbacks.gnssNiCb = nullptr;
+    locationCallbacks.gnssSvCb = nullptr;
+    locationCallbacks.gnssNmeaCb = nullptr;
+
+    locationCallbacks.gnssMeasurementsCb = nullptr;
+    if (mGnssMeasurementCbIface_2_1 != nullptr ||
+        mGnssMeasurementCbIface_2_0 != nullptr ||
+        mGnssMeasurementCbIface_1_1 != nullptr ||
+        mGnssMeasurementCbIface != nullptr) {
+        locationCallbacks.gnssMeasurementsCb =
+            [this](GnssMeasurementsNotification gnssMeasurementsNotification) {
+                onGnssMeasurementsCb(gnssMeasurementsNotification);
+            };
+    }
+
+    locAPISetCallbacks(locationCallbacks);
+
+    TrackingOptions options = {};
+    memset(&options, 0, sizeof(TrackingOptions));
+    options.size = sizeof(TrackingOptions);
+    options.minInterval = 1000;
+    options.mode = GNSS_SUPL_MODE_STANDALONE;
+    if (GNSS_POWER_MODE_INVALID != powerMode) {
+        options.powerMode = powerMode;
+        options.tbm = timeBetweenMeasurement;
+    }
+
+    mTracking = true;
+    LOC_LOGD("%s]: start tracking session", __FUNCTION__);
+    locAPIStartTracking(options);
+    return IGnssMeasurement::GnssMeasurementStatus::SUCCESS;
+}
+
+// for GpsMeasurementInterface
+void MeasurementAPIClient::measurementClose() {
+    LOC_LOGD("%s]: ()", __FUNCTION__);
+    mTracking = false;
+    locAPIStopTracking();
+}
+
+// callbacks
+void MeasurementAPIClient::onGnssMeasurementsCb(
+        GnssMeasurementsNotification gnssMeasurementsNotification)
+{
+    LOC_LOGD("%s]: (count: %u active: %d)",
+            __FUNCTION__, gnssMeasurementsNotification.count, mTracking);
+    if (mTracking) {
+        mMutex.lock();
+        sp<V1_0::IGnssMeasurementCallback> gnssMeasurementCbIface = nullptr;
+        sp<V1_1::IGnssMeasurementCallback> gnssMeasurementCbIface_1_1 = nullptr;
+        sp<V2_0::IGnssMeasurementCallback> gnssMeasurementCbIface_2_0 = nullptr;
+        sp<V2_1::IGnssMeasurementCallback> gnssMeasurementCbIface_2_1 = nullptr;
+        if (mGnssMeasurementCbIface_2_1 != nullptr) {
+            gnssMeasurementCbIface_2_1 = mGnssMeasurementCbIface_2_1;
+        } else if (mGnssMeasurementCbIface_2_0 != nullptr) {
+            gnssMeasurementCbIface_2_0 = mGnssMeasurementCbIface_2_0;
+        } else if (mGnssMeasurementCbIface_1_1 != nullptr) {
+            gnssMeasurementCbIface_1_1 = mGnssMeasurementCbIface_1_1;
+        } else if (mGnssMeasurementCbIface != nullptr) {
+            gnssMeasurementCbIface = mGnssMeasurementCbIface;
+        }
+        mMutex.unlock();
+
+        if (gnssMeasurementCbIface_2_1 != nullptr) {
+            V2_1::IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData_2_1(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface_2_1->gnssMeasurementCb_2_1(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssMeasurementCbIface_2_0 != nullptr) {
+            V2_0::IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData_2_0(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface_2_0->gnssMeasurementCb_2_0(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssMeasurementCbIface_1_1 != nullptr) {
+            V1_1::IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData_1_1(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface_1_1->gnssMeasurementCb(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from gnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        } else if (gnssMeasurementCbIface != nullptr) {
+            V1_0::IGnssMeasurementCallback::GnssData gnssData;
+            convertGnssData(gnssMeasurementsNotification, gnssData);
+            auto r = gnssMeasurementCbIface->GnssMeasurementCb(gnssData);
+            if (!r.isOk()) {
+                LOC_LOGE("%s] Error from GnssMeasurementCb description=%s",
+                    __func__, r.description().c_str());
+            }
+        }
+    }
+}
+
+static void convertGnssMeasurement(GnssMeasurementsData& in,
+        V1_0::IGnssMeasurementCallback::GnssMeasurement& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in.flags & GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SNR;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_FREQUENCY;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_CYCLES;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT)
+        out.flags |= IGnssMeasurementCallback::GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL;
+    convertGnssSvid(in, out.svid);
+    convertGnssConstellationType(in.svType, out.constellation);
+    out.timeOffsetNs = in.timeOffsetNs;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+    if (in.stateMask & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+    if (in.stateMask &  GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+        out.state |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+    out.receivedSvTimeInNs = in.receivedSvTimeNs;
+    out.receivedSvTimeUncertaintyInNs = in.receivedSvTimeUncertaintyNs;
+    out.cN0DbHz = in.carrierToNoiseDbHz;
+    out.pseudorangeRateMps = in.pseudorangeRateMps;
+    out.pseudorangeRateUncertaintyMps = in.pseudorangeRateUncertaintyMps;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+    if (in.adrStateMask & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+        out.accumulatedDeltaRangeState |=
+            IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+    out.accumulatedDeltaRangeM = in.adrMeters;
+    out.accumulatedDeltaRangeUncertaintyM = in.adrUncertaintyMeters;
+    out.carrierFrequencyHz = in.carrierFrequencyHz;
+    out.carrierCycles = in.carrierCycles;
+    out.carrierPhase = in.carrierPhase;
+    out.carrierPhaseUncertainty = in.carrierPhaseUncertainty;
+    uint8_t indicator =
+        static_cast<uint8_t>(IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_UNKNOWN);
+    if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_PRESENT)
+        indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATOR_PRESENT;
+    if (in.multipathIndicator & GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_NOT_PRESENT)
+        indicator |= IGnssMeasurementCallback::GnssMultipathIndicator::INDICATIOR_NOT_PRESENT;
+    out.multipathIndicator =
+        static_cast<IGnssMeasurementCallback::GnssMultipathIndicator>(indicator);
+    out.snrDb = in.signalToNoiseRatioDb;
+    out.agcLevelDb = in.agcLevelDb;
+}
+
+static void convertGnssClock(GnssMeasurementsClock& in, IGnssMeasurementCallback::GnssClock& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_LEAP_SECOND_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_LEAP_SECOND;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_TIME_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_FULL_BIAS_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_FULL_BIAS;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_BIAS_UNCERTAINTY;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT;
+    if (in.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_UNCERTAINTY_BIT)
+        out.gnssClockFlags |= IGnssMeasurementCallback::GnssClockFlags::HAS_DRIFT_UNCERTAINTY;
+    out.leapSecond = in.leapSecond;
+    out.timeNs = in.timeNs;
+    out.timeUncertaintyNs = in.timeUncertaintyNs;
+    out.fullBiasNs = in.fullBiasNs;
+    out.biasNs = in.biasNs;
+    out.biasUncertaintyNs = in.biasUncertaintyNs;
+    out.driftNsps = in.driftNsps;
+    out.driftUncertaintyNsps = in.driftUncertaintyNsps;
+    out.hwClockDiscontinuityCount = in.hwClockDiscontinuityCount;
+}
+
+static void convertGnssClock_2_1(GnssMeasurementsClock& in,
+        V2_1::IGnssMeasurementCallback::GnssClock& out)
+{
+    memset(&out, 0, sizeof(out));
+    convertGnssClock(in, out.v1_0);
+    convertGnssConstellationType(in.referenceSignalTypeForIsb.svType,
+            out.referenceSignalTypeForIsb.constellation);
+    out.referenceSignalTypeForIsb.carrierFrequencyHz =
+            in.referenceSignalTypeForIsb.carrierFrequencyHz;
+    convertGnssMeasurementsCodeType(in.referenceSignalTypeForIsb.codeType,
+            in.referenceSignalTypeForIsb.otherCodeTypeName,
+            out.referenceSignalTypeForIsb.codeType);
+}
+
+static void convertGnssData(GnssMeasurementsNotification& in,
+        V1_0::IGnssMeasurementCallback::GnssData& out)
+{
+    memset(&out, 0, sizeof(out));
+    out.measurementCount = in.count;
+    if (out.measurementCount > static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT)) {
+        LOC_LOGW("%s]: Too many measurement %u. Clamps to %d.",
+                __FUNCTION__,  out.measurementCount, V1_0::GnssMax::SVS_COUNT);
+        out.measurementCount = static_cast<uint32_t>(V1_0::GnssMax::SVS_COUNT);
+    }
+    for (size_t i = 0; i < out.measurementCount; i++) {
+        convertGnssMeasurement(in.measurements[i], out.measurements[i]);
+    }
+    convertGnssClock(in.clock, out.clock);
+}
+
+static void convertGnssData_1_1(GnssMeasurementsNotification& in,
+        V1_1::IGnssMeasurementCallback::GnssData& out)
+{
+    memset(&out, 0, sizeof(out));
+    out.measurements.resize(in.count);
+    for (size_t i = 0; i < in.count; i++) {
+        convertGnssMeasurement(in.measurements[i], out.measurements[i].v1_0);
+        convertGnssMeasurementsAccumulatedDeltaRangeState(in.measurements[i].adrStateMask,
+                out.measurements[i].accumulatedDeltaRangeState);
+    }
+    convertGnssClock(in.clock, out.clock);
+}
+
+static void convertGnssData_2_0(GnssMeasurementsNotification& in,
+        V2_0::IGnssMeasurementCallback::GnssData& out)
+{
+    memset(&out, 0, sizeof(out));
+    out.measurements.resize(in.count);
+    for (size_t i = 0; i < in.count; i++) {
+        convertGnssMeasurement(in.measurements[i], out.measurements[i].v1_1.v1_0);
+        convertGnssConstellationType(in.measurements[i].svType, out.measurements[i].constellation);
+        convertGnssMeasurementsCodeType(in.measurements[i].codeType,
+            in.measurements[i].otherCodeTypeName,
+            out.measurements[i].codeType);
+        convertGnssMeasurementsAccumulatedDeltaRangeState(in.measurements[i].adrStateMask,
+                out.measurements[i].v1_1.accumulatedDeltaRangeState);
+        convertGnssMeasurementsState(in.measurements[i].stateMask, out.measurements[i].state);
+    }
+    convertGnssClock(in.clock, out.clock);
+    convertElapsedRealtimeNanos(in, out.elapsedRealtime);
+}
+
+static void convertGnssMeasurementsCodeType(GnssMeasurementsCodeType& inCodeType,
+        char* inOtherCodeTypeName, ::android::hardware::hidl_string& out)
+{
+    memset(&out, 0, sizeof(out));
+    switch(inCodeType) {
+        case GNSS_MEASUREMENTS_CODE_TYPE_A:
+            out = "A";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_B:
+            out = "B";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_C:
+            out = "C";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_I:
+            out = "I";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_L:
+            out = "L";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_M:
+            out = "M";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_P:
+            out = "P";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_Q:
+            out = "Q";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_S:
+            out = "S";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_W:
+            out = "W";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_X:
+            out = "X";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_Y:
+            out = "Y";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_Z:
+            out = "Z";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_N:
+            out = "N";
+            break;
+        case GNSS_MEASUREMENTS_CODE_TYPE_OTHER:
+        default:
+            out = inOtherCodeTypeName;
+            break;
+    }
+}
+
+static void convertGnssMeasurementsAccumulatedDeltaRangeState(GnssMeasurementsAdrStateMask& in,
+        ::android::hardware::hidl_bitfield
+                <V1_1::IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState>& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT)
+        out |= IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_VALID;
+    if (in & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT)
+        out |= IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_RESET;
+    if (in & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT)
+        out |= IGnssMeasurementCallback::GnssAccumulatedDeltaRangeState::ADR_STATE_CYCLE_SLIP;
+    if (in & GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_HALF_CYCLE_RESOLVED_BIT)
+        out |= IGnssMeasurementCallback::
+                GnssAccumulatedDeltaRangeState::ADR_STATE_HALF_CYCLE_RESOLVED;
+}
+
+static void convertGnssMeasurementsState(GnssMeasurementsStateMask& in,
+        ::android::hardware::hidl_bitfield
+                <V2_0::IGnssMeasurementCallback::GnssMeasurementState>& out)
+{
+    memset(&out, 0, sizeof(out));
+    if (in & GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_CODE_LOCK;
+    if (in & GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BIT_SYNC;
+    if (in & GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SUBFRAME_SYNC;
+    if (in & GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_DECODED;
+    if (in & GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_MSEC_AMBIGUOUS;
+    if (in & GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SYMBOL_SYNC;
+    if (in & GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_STRING_SYNC;
+    if (in & GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_DECODED;
+    if (in & GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_BIT_SYNC;
+    if (in & GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_BDS_D2_SUBFRAME_SYNC;
+    if (in & GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1BC_CODE_LOCK;
+    if (in & GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1C_2ND_CODE_LOCK;
+    if (in & GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GAL_E1B_PAGE_SYNC;
+    if (in & GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_SBAS_SYNC;
+    if (in & GNSS_MEASUREMENTS_STATE_TOW_KNOWN_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_TOW_KNOWN;
+    if (in & GNSS_MEASUREMENTS_STATE_GLO_TOD_KNOWN_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_GLO_TOD_KNOWN;
+    if (in & GNSS_MEASUREMENTS_STATE_2ND_CODE_LOCK_BIT)
+        out |= IGnssMeasurementCallback::GnssMeasurementState::STATE_2ND_CODE_LOCK;
+}
+
+static void convertGnssData_2_1(GnssMeasurementsNotification& in,
+        V2_1::IGnssMeasurementCallback::GnssData& out)
+{
+    memset(&out, 0, sizeof(out));
+    out.measurements.resize(in.count);
+    for (size_t i = 0; i < in.count; i++) {
+        out.measurements[i].flags = 0;
+        convertGnssMeasurement(in.measurements[i], out.measurements[i].v2_0.v1_1.v1_0);
+        convertGnssConstellationType(in.measurements[i].svType,
+                out.measurements[i].v2_0.constellation);
+        convertGnssMeasurementsCodeType(in.measurements[i].codeType,
+                in.measurements[i].otherCodeTypeName,
+                out.measurements[i].v2_0.codeType);
+        convertGnssMeasurementsAccumulatedDeltaRangeState(in.measurements[i].adrStateMask,
+                out.measurements[i].v2_0.v1_1.accumulatedDeltaRangeState);
+        convertGnssMeasurementsState(in.measurements[i].stateMask,
+                out.measurements[i].v2_0.state);
+        out.measurements[i].basebandCN0DbHz = in.measurements[i].basebandCarrierToNoiseDbHz;
+
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT) {
+            out.measurements[i].flags |=
+                V2_1::IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SNR;
+        }
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT) {
+            out.measurements[i].flags |=
+                V2_1::IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_FREQUENCY;
+        }
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT) {
+            out.measurements[i].flags |=
+                V2_1::IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_CYCLES;
+        }
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT) {
+            out.measurements[i].flags |=
+                V2_1::IGnssMeasurementCallback::GnssMeasurementFlags::HAS_CARRIER_PHASE;
+        }
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT) {
+            out.measurements[i].flags |=
+                V2_1::IGnssMeasurementCallback::
+                        GnssMeasurementFlags::HAS_CARRIER_PHASE_UNCERTAINTY;
+        }
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT) {
+            out.measurements[i].flags |=
+                V2_1::IGnssMeasurementCallback::GnssMeasurementFlags::HAS_AUTOMATIC_GAIN_CONTROL;
+        }
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_FULL_ISB_BIT) {
+            out.measurements[i].fullInterSignalBiasNs = in.measurements[i].fullInterSignalBiasNs;
+            out.measurements[i].flags |=
+                    V2_1::IGnssMeasurementCallback::GnssMeasurementFlags::HAS_FULL_ISB;
+        }
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_FULL_ISB_UNCERTAINTY_BIT) {
+            out.measurements[i].fullInterSignalBiasUncertaintyNs =
+                    in.measurements[i].fullInterSignalBiasUncertaintyNs;
+            out.measurements[i].flags |=
+                    V2_1::IGnssMeasurementCallback::
+                            GnssMeasurementFlags::HAS_FULL_ISB_UNCERTAINTY;
+        }
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_SATELLITE_ISB_BIT) {
+            out.measurements[i].satelliteInterSignalBiasNs =
+                    in.measurements[i].satelliteInterSignalBiasNs;
+            out.measurements[i].flags |=
+                    V2_1::IGnssMeasurementCallback::GnssMeasurementFlags::HAS_SATELLITE_ISB;
+        }
+        if (in.measurements[i].flags & GNSS_MEASUREMENTS_DATA_SATELLITE_ISB_UNCERTAINTY_BIT) {
+            out.measurements[i].satelliteInterSignalBiasUncertaintyNs =
+                    in.measurements[i].satelliteInterSignalBiasUncertaintyNs;
+            out.measurements[i].flags |=
+                    V2_1::IGnssMeasurementCallback::
+                            GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY;
+        }
+    }
+    convertGnssClock_2_1(in.clock, out.clock);
+    convertElapsedRealtimeNanos(in, out.elapsedRealtime);
+}
+
+static void convertElapsedRealtimeNanos(GnssMeasurementsNotification& in,
+        ::android::hardware::gnss::V2_0::ElapsedRealtime& elapsedRealtime)
+{
+    if (in.clock.flags & GNSS_MEASUREMENTS_CLOCK_FLAGS_ELAPSED_REAL_TIME_BIT) {
+        elapsedRealtime.flags |= V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS;
+        elapsedRealtime.timestampNs = in.clock.elapsedRealTime;
+        elapsedRealtime.flags |= V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS;
+        elapsedRealtime.timeUncertaintyNs = in.clock.elapsedRealTimeUnc;
+        LOC_LOGd("elapsedRealtime.timestampNs=%" PRIi64 ""
+                 " elapsedRealtime.timeUncertaintyNs=%" PRIi64 " elapsedRealtime.flags=0x%X",
+                 elapsedRealtime.timestampNs,
+                 elapsedRealtime.timeUncertaintyNs, elapsedRealtime.flags);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
diff --git a/gps/android/2.1/location_api/MeasurementAPIClient.h b/gps/android/2.1/location_api/MeasurementAPIClient.h
new file mode 100644
index 0000000..3e8805b
--- /dev/null
+++ b/gps/android/2.1/location_api/MeasurementAPIClient.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MEASUREMENT_API_CLINET_H
+#define MEASUREMENT_API_CLINET_H
+
+#include <mutex>
+#include <android/hardware/gnss/2.1/IGnssMeasurement.h>
+//#include <android/hardware/gnss/1.1/IGnssMeasurementCallback.h>
+#include <android/hardware/gnss/2.1/IGnssMeasurementCallback.h>
+#include <LocationAPIClientBase.h>
+#include <hidl/Status.h>
+#include <gps_extended_c.h>
+
+namespace android {
+namespace hardware {
+namespace gnss {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+
+class MeasurementAPIClient : public LocationAPIClientBase
+{
+public:
+    MeasurementAPIClient();
+    MeasurementAPIClient(const MeasurementAPIClient&) = delete;
+    MeasurementAPIClient& operator=(const MeasurementAPIClient&) = delete;
+
+    // for GpsMeasurementInterface
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback(
+            const sp<V1_0::IGnssMeasurementCallback>& callback);
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback_1_1(
+            const sp<V1_1::IGnssMeasurementCallback>& callback,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback_2_0(
+            const sp<V2_0::IGnssMeasurementCallback>& callback,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+    Return<V1_0::IGnssMeasurement::GnssMeasurementStatus> measurementSetCallback_2_1(
+            const sp<V2_1::IGnssMeasurementCallback>& callback,
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+    void measurementClose();
+    Return<IGnssMeasurement::GnssMeasurementStatus> startTracking(
+            GnssPowerMode powerMode = GNSS_POWER_MODE_INVALID,
+            uint32_t timeBetweenMeasurement = GPS_DEFAULT_FIX_INTERVAL_MS);
+
+    // callbacks we are interested in
+    void onGnssMeasurementsCb(GnssMeasurementsNotification gnssMeasurementsNotification) final;
+
+private:
+    virtual ~MeasurementAPIClient();
+
+    std::mutex mMutex;
+    sp<V1_0::IGnssMeasurementCallback> mGnssMeasurementCbIface;
+    sp<V1_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_1_1;
+    sp<V2_0::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_0;
+    sp<V2_1::IGnssMeasurementCallback> mGnssMeasurementCbIface_2_1;
+    bool mTracking;
+    void clearInterfaces();
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace gnss
+}  // namespace hardware
+}  // namespace android
+#endif // MEASUREMENT_API_CLINET_H
diff --git a/gps/android/2.1/service.cpp b/gps/android/2.1/service.cpp
new file mode 100755
index 0000000..c5f040b
--- /dev/null
+++ b/gps/android/2.1/service.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Not a Contribution
+ */
+/*
+ * Copyright (C) 2016 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 "android.hardware.gnss@2.1-service-qti"
+
+#include <android/hardware/gnss/2.1/IGnss.h>
+#include <hidl/LegacySupport.h>
+#include "loc_cfg.h"
+#include "loc_misc_utils.h"
+
+extern "C" {
+#include "vndfwk-detect.h"
+}
+
+#ifdef ARCH_ARM_32
+#define DEFAULT_HW_BINDER_MEM_SIZE 65536
+#endif
+
+using android::hardware::gnss::V2_1::IGnss;
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::registerPassthroughServiceImplementation;
+using android::hardware::joinRpcThreadpool;
+
+using android::status_t;
+using android::OK;
+
+typedef int vendorEnhancedServiceMain(int /* argc */, char* /* argv */ []);
+
+int main() {
+
+    ALOGI("%s", __FUNCTION__);
+
+    int vendorInfo = getVendorEnhancedInfo();
+    bool vendorEnhanced = ( 1 == vendorInfo || 3 == vendorInfo );
+    setVendorEnhanced(vendorEnhanced);
+
+#ifdef ARCH_ARM_32
+    android::hardware::ProcessState::initWithMmapSize((size_t)(DEFAULT_HW_BINDER_MEM_SIZE));
+#endif
+    configureRpcThreadpool(1, true);
+    status_t status;
+
+    status = registerPassthroughServiceImplementation<IGnss>();
+    if (status == OK) {
+    #ifdef LOC_HIDL_VERSION
+        #define VENDOR_ENHANCED_LIB "vendor.qti.gnss@" LOC_HIDL_VERSION "-service.so"
+
+        void* libHandle = NULL;
+        vendorEnhancedServiceMain* vendorEnhancedMainMethod = (vendorEnhancedServiceMain*)
+                dlGetSymFromLib(libHandle, VENDOR_ENHANCED_LIB, "main");
+        if (NULL != vendorEnhancedMainMethod) {
+            (*vendorEnhancedMainMethod)(0, NULL);
+        }
+    #else
+        ALOGI("LOC_HIDL_VERSION not defined.");
+    #endif
+        joinRpcThreadpool();
+    } else {
+        ALOGE("Error while registering IGnss 2.1 service: %d", status);
+    }
+
+    return 0;
+}
diff --git a/gps/android/Android.mk b/gps/android/Android.mk
new file mode 100644
index 0000000..aa2f4b5
--- /dev/null
+++ b/gps/android/Android.mk
@@ -0,0 +1,2 @@
+LOCAL_PATH := $(call my-dir)
+include $(call all-subdir-makefiles)
diff --git a/gps/android/utils/Android.bp b/gps/android/utils/Android.bp
new file mode 100644
index 0000000..20fea88
--- /dev/null
+++ b/gps/android/utils/Android.bp
@@ -0,0 +1,37 @@
+cc_library_static {
+
+    name: "liblocbatterylistener",
+    vendor: true,
+
+
+
+    cflags: GNSS_CFLAGS + ["-DBATTERY_LISTENER_ENABLED"],
+    local_include_dirs: ["."],
+
+    srcs: ["battery_listener.cpp"],
+
+    shared_libs: [
+        "liblog",
+        "libhidlbase",
+        "libcutils",
+        "libutils",
+        "android.hardware.health@1.0",
+        "android.hardware.health@2.0",
+        "android.hardware.health@2.1",
+        "android.hardware.power@1.2",
+        "libbase",
+    ],
+
+    static_libs: ["libhealthhalutils"],
+
+    header_libs: [
+        "libgps.utils_headers",
+        "libloc_pla_headers",
+    ],
+}
+
+cc_library_headers {
+
+    name: "liblocbatterylistener_headers",
+    export_include_dirs: ["."],
+}
diff --git a/gps/android/utils/battery_listener.cpp b/gps/android/utils/battery_listener.cpp
new file mode 100644
index 0000000..9cbfabd
--- /dev/null
+++ b/gps/android/utils/battery_listener.cpp
@@ -0,0 +1,280 @@
+/*
+* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "battery_listener.h"
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LocSvc_BatteryListener"
+#define LOG_NDEBUG 0
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+#include <healthhalutils/HealthHalUtils.h>
+#include <hidl/HidlTransportSupport.h>
+#include <thread>
+#include <log_util.h>
+
+using android::hardware::interfacesEqual;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V2_1::HealthInfo;
+using android::hardware::health::V2_1::IHealthInfoCallback;
+using android::hardware::health::V2_1::IHealth;
+using android::hardware::health::V2_0::Result;
+using android::hidl::manager::V1_0::IServiceManager;
+using namespace std::literals::chrono_literals;
+
+static bool sIsBatteryListened = false;
+namespace android {
+
+#define GET_HEALTH_SVC_RETRY_CNT 5
+#define GET_HEALTH_SVC_WAIT_TIME_MS 500
+
+struct BatteryListenerImpl : public hardware::health::V2_1::IHealthInfoCallback,
+                             public hardware::hidl_death_recipient {
+    typedef std::function<void(bool)> cb_fn_t;
+    BatteryListenerImpl(cb_fn_t cb);
+    virtual ~BatteryListenerImpl ();
+    virtual hardware::Return<void> healthInfoChanged(
+            const hardware::health::V2_0::HealthInfo& info);
+    virtual hardware::Return<void> healthInfoChanged_2_1(
+            const hardware::health::V2_1::HealthInfo& info);
+    virtual void serviceDied(uint64_t cookie,
+                             const wp<hidl::base::V1_0::IBase>& who);
+    bool isCharging() {
+        std::lock_guard<std::mutex> _l(mLock);
+        return statusToBool(mStatus);
+    }
+  private:
+    sp<hardware::health::V2_1::IHealth> mHealth;
+    status_t init();
+    BatteryStatus mStatus;
+    cb_fn_t mCb;
+    std::mutex mLock;
+    std::condition_variable mCond;
+    std::unique_ptr<std::thread> mThread;
+    bool mDone;
+    bool statusToBool(const BatteryStatus &s) const {
+        return (s == BatteryStatus::CHARGING) ||
+               (s ==  BatteryStatus::FULL);
+    }
+};
+
+status_t BatteryListenerImpl::init()
+{
+    int tries = 0;
+
+    if (mHealth != NULL)
+        return INVALID_OPERATION;
+
+    do {
+        mHealth = IHealth::getService();
+        if (mHealth != NULL)
+            break;
+        usleep(GET_HEALTH_SVC_WAIT_TIME_MS * 1000);
+        tries++;
+    } while(tries < GET_HEALTH_SVC_RETRY_CNT);
+
+    if (mHealth == NULL) {
+        LOC_LOGe("no health service found, retries %d", tries);
+        return NO_INIT;
+    } else {
+        LOC_LOGi("Get health service in %d tries", tries);
+    }
+    mStatus = BatteryStatus::UNKNOWN;
+    auto ret = mHealth->getChargeStatus([&](Result r, BatteryStatus status) {
+        if (r != Result::SUCCESS) {
+            LOC_LOGe("batterylistener: cannot get battery status");
+            return;
+        }
+        mStatus = status;
+    });
+    if (!ret.isOk()) {
+        LOC_LOGe("batterylistener: get charge status transaction error");
+    }
+    if (mStatus == BatteryStatus::UNKNOWN) {
+        LOC_LOGw("batterylistener: init: invalid battery status");
+    }
+    mDone = false;
+    mThread = std::make_unique<std::thread>([this]() {
+            std::unique_lock<std::mutex> l(mLock);
+            BatteryStatus local_status = mStatus;
+            while (!mDone) {
+                if (local_status == mStatus) {
+                    mCond.wait(l);
+                    continue;
+                }
+                local_status = mStatus;
+                switch (local_status) {
+                    // NOT_CHARGING is a special event that indicates, a battery is connected,
+                    // but not charging. This is seen for approx a second
+                    // after charger is plugged in. A charging event is eventually received.
+                    // We must try to avoid an unnecessary cb to HAL
+                    // only to call it again shortly.
+                    // An option to deal with this transient event would be to ignore this.
+                    // Or process this event with a slight delay (i.e cancel this event
+                    // if a different event comes in within a timeout
+                    case BatteryStatus::NOT_CHARGING : {
+                        auto mStatusnot_ncharging =
+                                [this, local_status]() { return mStatus != local_status; };
+                        mCond.wait_for(l, 3s, mStatusnot_ncharging);
+                        if (mStatusnot_ncharging()) // i.e event changed
+                            break;
+                        [[clang::fallthrough]]; //explicit fall-through between switch labels
+                    }
+                    default:
+                        bool c = statusToBool(local_status);
+                        LOC_LOGi("healthInfo cb thread: cb %s", c ? "CHARGING" : "NOT CHARGING");
+                        l.unlock();
+                        mCb(c);
+                        l.lock();
+                        break;
+                }
+            }
+    });
+    auto reg = mHealth->registerCallback(this);
+    if (!reg.isOk()) {
+        LOC_LOGe("Transaction error in registeringCb to HealthHAL death: %s",
+                reg.description().c_str());
+    }
+
+    auto linked = mHealth->linkToDeath(this, 0 /* cookie */);
+    if (!linked.isOk() || linked == false) {
+        LOC_LOGe("Transaction error in linking to HealthHAL death: %s",
+                linked.description().c_str());
+    }
+    return NO_ERROR;
+}
+
+BatteryListenerImpl::BatteryListenerImpl(cb_fn_t cb) :
+        mCb(cb)
+{
+    init();
+}
+
+BatteryListenerImpl::~BatteryListenerImpl()
+{
+    {
+        std::lock_guard<std::mutex> _l(mLock);
+        if (mHealth != NULL)
+            mHealth->unregisterCallback(this);
+            auto r = mHealth->unlinkToDeath(this);
+            if (!r.isOk() || r == false) {
+                LOC_LOGe("Transaction error in unregister to HealthHAL death: %s",
+                        r.description().c_str());
+            }
+    }
+    mDone = true;
+    mThread->join();
+}
+
+void BatteryListenerImpl::serviceDied(uint64_t cookie __unused,
+                                     const wp<hidl::base::V1_0::IBase>& who)
+{
+    {
+        std::lock_guard<std::mutex> _l(mLock);
+        if (mHealth == NULL || !interfacesEqual(mHealth, who.promote())) {
+            LOC_LOGe("health not initialized or unknown interface died");
+            return;
+        }
+        LOC_LOGi("health service died, reinit");
+        mDone = true;
+    }
+    mHealth = NULL;
+    mCond.notify_one();
+    mThread->join();
+    std::lock_guard<std::mutex> _l(mLock);
+    init();
+}
+
+// this callback seems to be a SYNC callback and so
+// waits for return before next event is issued.
+// therefore we need not have a queue to process
+// NOT_CHARGING and CHARGING concurrencies.
+// Replace single var by a list if this assumption is broken
+Return<void> BatteryListenerImpl::healthInfoChanged(
+        const hardware::health::V2_0::HealthInfo& info) {
+    LOC_LOGv("healthInfoChanged: %d", info.legacy.batteryStatus);
+    std::unique_lock<std::mutex> l(mLock);
+    if (info.legacy.batteryStatus != mStatus) {
+        mStatus = info.legacy.batteryStatus;
+        mCond.notify_one();
+    }
+    return Void();
+}
+
+Return<void> BatteryListenerImpl::healthInfoChanged_2_1(
+        const hardware::health::V2_1::HealthInfo& info) {
+    LOC_LOGv("healthInfoChanged_2_1: %d", info.legacy.legacy.batteryStatus);
+    healthInfoChanged(info.legacy);
+    return Void();
+}
+
+static sp<BatteryListenerImpl> batteryListener;
+
+bool batteryPropertiesListenerIsCharging() {
+    return batteryListener->isCharging();
+}
+
+status_t batteryPropertiesListenerInit(BatteryListenerImpl::cb_fn_t cb) {
+    batteryListener = new BatteryListenerImpl(cb);
+    bool isCharging = batteryPropertiesListenerIsCharging();
+    LOC_LOGv("charging status: %s charging", isCharging ? "" : "not");;
+    if (isCharging) {
+        cb(isCharging);
+    }
+    return NO_ERROR;
+}
+
+status_t batteryPropertiesListenerDeinit() {
+    batteryListener.clear();
+    return OK;
+}
+
+} // namespace android
+
+void loc_extn_battery_properties_listener_init(battery_status_change_fn_t fn) {
+    LOC_LOGv("loc_extn_battery_properties_listener_init entry");
+    if (!sIsBatteryListened) {
+        std::thread t1(android::batteryPropertiesListenerInit,
+                [=](bool charging) { fn(charging); });
+        t1.detach();
+        sIsBatteryListened = true;
+    }
+}
+
+void loc_extn_battery_properties_listener_deinit() {
+    android::batteryPropertiesListenerDeinit();
+}
+
+bool loc_extn_battery_properties_is_charging() {
+    return android::batteryPropertiesListenerIsCharging();
+}
diff --git a/gps/android/utils/battery_listener.h b/gps/android/utils/battery_listener.h
new file mode 100644
index 0000000..bb6b715
--- /dev/null
+++ b/gps/android/utils/battery_listener.h
@@ -0,0 +1,32 @@
+/*
+* Copyright (c) 2019, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+typedef void (* battery_status_change_fn_t)(bool);
+void loc_extn_battery_properties_listener_init(battery_status_change_fn_t fn);
+void loc_extn_battery_properties_listener_deinit();
+bool loc_extn_battery_properties_is_charging();
diff --git a/gps/batching/Android.bp b/gps/batching/Android.bp
new file mode 100644
index 0000000..ce794d1
--- /dev/null
+++ b/gps/batching/Android.bp
@@ -0,0 +1,31 @@
+
+cc_library_shared {
+
+    name: "libbatching",
+    vendor: true,
+
+
+
+    shared_libs: [
+        "libutils",
+        "libcutils",
+        "liblog",
+        "libloc_core",
+        "libgps.utils",
+        "libdl",
+    ],
+
+    srcs: [
+        "location_batching.cpp",
+        "BatchingAdapter.cpp",
+    ],
+
+    header_libs: [
+        "libgps.utils_headers",
+        "libloc_core_headers",
+        "libloc_pla_headers",
+        "liblocation_api_headers",
+    ],
+
+    cflags: GNSS_CFLAGS,
+}
diff --git a/gps/batching/BatchingAdapter.cpp b/gps/batching/BatchingAdapter.cpp
new file mode 100644
index 0000000..4f1a43c
--- /dev/null
+++ b/gps/batching/BatchingAdapter.cpp
@@ -0,0 +1,1051 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_BatchingAdapter"
+
+#include <loc_pla.h>
+#include <log_util.h>
+#include <LocContext.h>
+#include <BatchingAdapter.h>
+
+using namespace loc_core;
+
+BatchingAdapter::BatchingAdapter() :
+    LocAdapterBase(0,
+                   LocContext::getLocContext(LocContext::mLocationHalName),
+                   false, nullptr, true),
+    mOngoingTripDistance(0),
+    mOngoingTripTBFInterval(0),
+    mTripWithOngoingTBFDropped(false),
+    mTripWithOngoingTripDistanceDropped(false),
+    mBatchingTimeout(0),
+    mBatchingAccuracy(1),
+    mBatchSize(0),
+    mTripBatchSize(0)
+{
+    LOC_LOGD("%s]: Constructor", __func__);
+    readConfigCommand();
+    setConfigCommand();
+
+    // at last step, let us inform adapater base that we are done
+    // with initialization, e.g.: ready to process handleEngineUpEvent
+    doneInit();
+}
+
+void
+BatchingAdapter::readConfigCommand()
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    struct MsgReadConfig : public LocMsg {
+        BatchingAdapter& mAdapter;
+        inline MsgReadConfig(BatchingAdapter& adapter) :
+            LocMsg(),
+            mAdapter(adapter) {}
+        inline virtual void proc() const {
+            uint32_t batchingTimeout = 0;
+            uint32_t batchingAccuracy = 0;
+            uint32_t batchSize = 0;
+            uint32_t tripBatchSize = 0;
+            static const loc_param_s_type flp_conf_param_table[] =
+            {
+                {"BATCH_SIZE", &batchSize, NULL, 'n'},
+                {"OUTDOOR_TRIP_BATCH_SIZE", &tripBatchSize, NULL, 'n'},
+                {"BATCH_SESSION_TIMEOUT", &batchingTimeout, NULL, 'n'},
+                {"ACCURACY", &batchingAccuracy, NULL, 'n'},
+            };
+            UTIL_READ_CONF(LOC_PATH_FLP_CONF, flp_conf_param_table);
+
+            LOC_LOGD("%s]: batchSize %u tripBatchSize %u batchingAccuracy %u batchingTimeout %u ",
+                     __func__, batchSize, tripBatchSize, batchingAccuracy, batchingTimeout);
+
+             mAdapter.setBatchSize(batchSize);
+             mAdapter.setTripBatchSize(tripBatchSize);
+             mAdapter.setBatchingTimeout(batchingTimeout);
+             mAdapter.setBatchingAccuracy(batchingAccuracy);
+        }
+    };
+
+    sendMsg(new MsgReadConfig(*this));
+
+}
+
+void
+BatchingAdapter::setConfigCommand()
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    struct MsgSetConfig : public LocMsg {
+        BatchingAdapter& mAdapter;
+        LocApiBase& mApi;
+        inline MsgSetConfig(BatchingAdapter& adapter,
+                            LocApiBase& api) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api) {}
+        inline virtual void proc() const {
+            mApi.setBatchSize(mAdapter.getBatchSize());
+            mApi.setTripBatchSize(mAdapter.getTripBatchSize());
+        }
+    };
+
+    sendMsg(new MsgSetConfig(*this, *mLocApi));
+}
+
+void
+BatchingAdapter::stopClientSessions(LocationAPI* client)
+{
+    LOC_LOGD("%s]: client %p", __func__, client);
+
+    typedef struct pairKeyBatchMode {
+        LocationAPI* client;
+        uint32_t id;
+        BatchingMode batchingMode;
+        inline pairKeyBatchMode(LocationAPI* _client, uint32_t _id, BatchingMode _bMode) :
+            client(_client), id(_id), batchingMode(_bMode) {}
+    } pairKeyBatchMode;
+    std::vector<pairKeyBatchMode> vBatchingClient;
+    for (auto it : mBatchingSessions) {
+        if (client == it.first.client) {
+            vBatchingClient.emplace_back(it.first.client, it.first.id, it.second.batchingMode);
+        }
+    }
+    for (auto keyBatchingMode : vBatchingClient) {
+        if (keyBatchingMode.batchingMode != BATCHING_MODE_TRIP) {
+            stopBatching(keyBatchingMode.client, keyBatchingMode.id);
+        } else {
+            stopTripBatchingMultiplex(keyBatchingMode.client, keyBatchingMode.id);
+        }
+    }
+}
+
+void
+BatchingAdapter::updateClientsEventMask()
+{
+    LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        // we don't register LOC_API_ADAPTER_BIT_BATCH_FULL until we
+        // start batching with ROUTINE or TRIP option
+        if (it->second.batchingCb != nullptr) {
+            mask |= LOC_API_ADAPTER_BIT_BATCH_STATUS;
+        }
+    }
+    if (autoReportBatchingSessionsCount() > 0) {
+        mask |= LOC_API_ADAPTER_BIT_BATCH_FULL;
+    }
+    updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
+}
+
+void
+BatchingAdapter::handleEngineUpEvent()
+{
+    struct MsgSSREvent : public LocMsg {
+        BatchingAdapter& mAdapter;
+        LocApiBase& mApi;
+        inline MsgSSREvent(BatchingAdapter& adapter,
+                           LocApiBase& api) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api) {}
+        virtual void proc() const {
+            mAdapter.setEngineCapabilitiesKnown(true);
+            mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+            mApi.setBatchSize(mAdapter.getBatchSize());
+            mApi.setTripBatchSize(mAdapter.getTripBatchSize());
+            mAdapter.restartSessions();
+            for (auto msg: mAdapter.mPendingMsgs) {
+                mAdapter.sendMsg(msg);
+            }
+            mAdapter.mPendingMsgs.clear();
+        }
+    };
+
+    sendMsg(new MsgSSREvent(*this, *mLocApi));
+}
+
+void
+BatchingAdapter::restartSessions()
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    if (autoReportBatchingSessionsCount() > 0) {
+        updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+                      LOC_REGISTRATION_MASK_ENABLED);
+    }
+    for (auto it = mBatchingSessions.begin();
+              it != mBatchingSessions.end(); ++it) {
+        if (it->second.batchingMode != BATCHING_MODE_TRIP) {
+            mLocApi->startBatching(it->first.id, it->second,
+                                    getBatchingAccuracy(), getBatchingTimeout(),
+                                    new LocApiResponse(*getContext(),
+                                    [] (LocationError /*err*/) {}));
+        }
+    }
+
+    if (mTripSessions.size() > 0) {
+        // restart outdoor trip batching session if any.
+        mOngoingTripDistance = 0;
+        mOngoingTripTBFInterval = 0;
+
+        // record the min trip distance and min tbf interval of all ongoing sessions
+        for (auto tripSession : mTripSessions) {
+
+            TripSessionStatus &tripSessStatus = tripSession.second;
+
+            if ((0 == mOngoingTripDistance) ||
+                (mOngoingTripDistance >
+                 (tripSessStatus.tripDistance - tripSessStatus.accumulatedDistanceThisTrip))) {
+                mOngoingTripDistance = tripSessStatus.tripDistance -
+                    tripSessStatus.accumulatedDistanceThisTrip;
+            }
+
+            if ((0 == mOngoingTripTBFInterval) ||
+                (mOngoingTripTBFInterval > tripSessStatus.tripTBFInterval)) {
+                mOngoingTripTBFInterval = tripSessStatus.tripTBFInterval;
+            }
+
+            // reset the accumulatedDistanceOngoingBatch for each session
+            tripSessStatus.accumulatedDistanceOngoingBatch = 0;
+
+        }
+
+        mLocApi->startOutdoorTripBatching(mOngoingTripDistance, mOngoingTripTBFInterval,
+                getBatchingTimeout(), new LocApiResponse(*getContext(), [this] (LocationError err) {
+            if (LOCATION_ERROR_SUCCESS != err) {
+                mOngoingTripDistance = 0;
+                mOngoingTripTBFInterval = 0;
+            }
+            printTripReport();
+        }));
+    }
+}
+
+bool
+BatchingAdapter::hasBatchingCallback(LocationAPI* client)
+{
+    auto it = mClientData.find(client);
+    return (it != mClientData.end() && it->second.batchingCb);
+}
+
+bool
+BatchingAdapter::isBatchingSession(LocationAPI* client, uint32_t sessionId)
+{
+    LocationSessionKey key(client, sessionId);
+    return (mBatchingSessions.find(key) != mBatchingSessions.end());
+}
+
+bool
+BatchingAdapter::isTripSession(uint32_t sessionId) {
+    return (mTripSessions.find(sessionId) != mTripSessions.end());
+}
+
+void
+BatchingAdapter::saveBatchingSession(LocationAPI* client, uint32_t sessionId,
+        const BatchingOptions& batchingOptions)
+{
+    LocationSessionKey key(client, sessionId);
+    mBatchingSessions[key] = batchingOptions;
+}
+
+void
+BatchingAdapter::eraseBatchingSession(LocationAPI* client, uint32_t sessionId)
+{
+    LocationSessionKey key(client, sessionId);
+    auto it = mBatchingSessions.find(key);
+    if (it != mBatchingSessions.end()) {
+        mBatchingSessions.erase(it);
+    }
+}
+
+void
+BatchingAdapter::reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId)
+{
+    LOC_LOGD("%s]: client %p id %u err %u", __func__, client, sessionId, err);
+
+    auto it = mClientData.find(client);
+    if (it != mClientData.end() &&
+        it->second.responseCb != nullptr) {
+        it->second.responseCb(err, sessionId);
+    } else {
+        LOC_LOGE("%s]: client %p id %u not found in data", __func__, client, sessionId);
+    }
+}
+
+uint32_t
+BatchingAdapter::autoReportBatchingSessionsCount()
+{
+    uint32_t count = 0;
+    for (auto batchingSession: mBatchingSessions) {
+        if (batchingSession.second.batchingMode != BATCHING_MODE_NO_AUTO_REPORT) {
+            count++;
+        }
+    }
+    count += mTripSessions.size();
+    return count;
+}
+
+uint32_t
+BatchingAdapter::startBatchingCommand(
+        LocationAPI* client, BatchingOptions& batchOptions)
+{
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u Batching Mode %d",
+             __func__, client, sessionId, batchOptions.minInterval, batchOptions.minDistance,
+             batchOptions.mode,batchOptions.batchingMode);
+
+    struct MsgStartBatching : public LocMsg {
+        BatchingAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        uint32_t mSessionId;
+        BatchingOptions mBatchingOptions;
+        inline MsgStartBatching(BatchingAdapter& adapter,
+                               LocApiBase& api,
+                               LocationAPI* client,
+                               uint32_t sessionId,
+                               BatchingOptions batchOptions) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mSessionId(sessionId),
+            mBatchingOptions(batchOptions) {}
+        inline virtual void proc() const {
+            if (!mAdapter.isEngineCapabilitiesKnown()) {
+                mAdapter.mPendingMsgs.push_back(new MsgStartBatching(*this));
+                return;
+            }
+            LocationError err = LOCATION_ERROR_SUCCESS;
+
+            if (!mAdapter.hasBatchingCallback(mClient)) {
+                err = LOCATION_ERROR_CALLBACK_MISSING;
+            } else if (0 == mBatchingOptions.size) {
+                err = LOCATION_ERROR_INVALID_PARAMETER;
+            } else if (!ContextBase::isMessageSupported(
+                       LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING)) {
+                err = LOCATION_ERROR_NOT_SUPPORTED;
+            }
+            if (LOCATION_ERROR_SUCCESS == err) {
+                if (mBatchingOptions.batchingMode == BATCHING_MODE_ROUTINE ||
+                    mBatchingOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
+                    mAdapter.startBatching(mClient, mSessionId, mBatchingOptions);
+                } else if (mBatchingOptions.batchingMode == BATCHING_MODE_TRIP) {
+                    mAdapter.startTripBatchingMultiplex(mClient, mSessionId, mBatchingOptions);
+                } else {
+                    mAdapter.reportResponse(mClient, LOCATION_ERROR_INVALID_PARAMETER, mSessionId);
+                }
+            }
+        }
+    };
+
+    sendMsg(new MsgStartBatching(*this, *mLocApi, client, sessionId, batchOptions));
+
+    return sessionId;
+}
+
+void
+BatchingAdapter::startBatching(LocationAPI* client, uint32_t sessionId,
+        const BatchingOptions& batchingOptions)
+{
+    if (batchingOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT &&
+        0 == autoReportBatchingSessionsCount()) {
+        // if there is currenty no batching sessions interested in batch full event, then this
+        // new session will need to register for batch full event
+        updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+                      LOC_REGISTRATION_MASK_ENABLED);
+    }
+
+    // Assume start will be OK, remove session if not
+    saveBatchingSession(client, sessionId, batchingOptions);
+    mLocApi->startBatching(sessionId, batchingOptions, getBatchingAccuracy(), getBatchingTimeout(),
+            new LocApiResponse(*getContext(),
+            [this, client, sessionId, batchingOptions] (LocationError err) {
+        if (LOCATION_ERROR_SUCCESS != err) {
+            eraseBatchingSession(client, sessionId);
+        }
+
+        if (LOCATION_ERROR_SUCCESS != err &&
+            batchingOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT &&
+            0 == autoReportBatchingSessionsCount()) {
+            // if we fail to start batching and we have already registered batch full event
+            // we need to undo that since no sessions are now interested in batch full event
+            updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+                          LOC_REGISTRATION_MASK_DISABLED);
+        }
+
+        reportResponse(client, err, sessionId);
+    }));
+}
+
+void
+BatchingAdapter::updateBatchingOptionsCommand(LocationAPI* client, uint32_t id,
+        BatchingOptions& batchOptions)
+{
+    LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u batchMode %u",
+             __func__, client, id, batchOptions.minInterval,
+             batchOptions.minDistance, batchOptions.mode,
+             batchOptions.batchingMode);
+
+    struct MsgUpdateBatching : public LocMsg {
+        BatchingAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        uint32_t mSessionId;
+        BatchingOptions mBatchOptions;
+        inline MsgUpdateBatching(BatchingAdapter& adapter,
+                                LocApiBase& api,
+                                LocationAPI* client,
+                                uint32_t sessionId,
+                                BatchingOptions batchOptions) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mSessionId(sessionId),
+            mBatchOptions(batchOptions) {}
+        inline virtual void proc() const {
+            if (!mAdapter.isEngineCapabilitiesKnown()) {
+                mAdapter.mPendingMsgs.push_back(new MsgUpdateBatching(*this));
+                return;
+            }
+            LocationError err = LOCATION_ERROR_SUCCESS;
+            if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
+                err = LOCATION_ERROR_ID_UNKNOWN;
+            } else if ((0 == mBatchOptions.size) ||
+                       (mBatchOptions.batchingMode > BATCHING_MODE_NO_AUTO_REPORT)) {
+                err = LOCATION_ERROR_INVALID_PARAMETER;
+            }
+            if (LOCATION_ERROR_SUCCESS == err) {
+                if (!mAdapter.isTripSession(mSessionId)) {
+                    mAdapter.stopBatching(mClient, mSessionId, true, mBatchOptions);
+                } else {
+                    mAdapter.stopTripBatchingMultiplex(mClient, mSessionId, true, mBatchOptions);
+                }
+           }
+        }
+    };
+
+    sendMsg(new MsgUpdateBatching(*this, *mLocApi, client, id, batchOptions));
+}
+
+void
+BatchingAdapter::stopBatchingCommand(LocationAPI* client, uint32_t id)
+{
+    LOC_LOGD("%s]: client %p id %u", __func__, client, id);
+
+    struct MsgStopBatching : public LocMsg {
+        BatchingAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        uint32_t mSessionId;
+        inline MsgStopBatching(BatchingAdapter& adapter,
+                               LocApiBase& api,
+                               LocationAPI* client,
+                               uint32_t sessionId) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mSessionId(sessionId) {}
+        inline virtual void proc() const {
+            if (!mAdapter.isEngineCapabilitiesKnown()) {
+                mAdapter.mPendingMsgs.push_back(new MsgStopBatching(*this));
+                return;
+            }
+            LocationError err = LOCATION_ERROR_SUCCESS;
+            if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
+                err = LOCATION_ERROR_ID_UNKNOWN;
+            }
+            if (LOCATION_ERROR_SUCCESS == err) {
+                if (mAdapter.isTripSession(mSessionId)) {
+                    mAdapter.stopTripBatchingMultiplex(mClient, mSessionId);
+                } else {
+                    mAdapter.stopBatching(mClient, mSessionId);
+                }
+            }
+        }
+    };
+
+    sendMsg(new MsgStopBatching(*this, *mLocApi, client, id));
+}
+
+void
+BatchingAdapter::stopBatching(LocationAPI* client, uint32_t sessionId, bool restartNeeded,
+        const BatchingOptions& batchOptions)
+{
+    LocationSessionKey key(client, sessionId);
+    auto it = mBatchingSessions.find(key);
+    if (it != mBatchingSessions.end()) {
+        auto flpOptions = it->second;
+        // Assume stop will be OK, restore session if not
+        eraseBatchingSession(client, sessionId);
+        mLocApi->stopBatching(sessionId,
+                new LocApiResponse(*getContext(),
+                [this, client, sessionId, flpOptions, restartNeeded, batchOptions]
+                (LocationError err) {
+            if (LOCATION_ERROR_SUCCESS != err) {
+                saveBatchingSession(client, sessionId, batchOptions);
+            } else {
+                // if stopBatching is success, unregister for batch full event if this was the last
+                // batching session that is interested in batch full event
+                if (0 == autoReportBatchingSessionsCount() &&
+                    flpOptions.batchingMode != BATCHING_MODE_NO_AUTO_REPORT) {
+                    updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+                                  LOC_REGISTRATION_MASK_DISABLED);
+                }
+
+                if (restartNeeded) {
+                    if (batchOptions.batchingMode == BATCHING_MODE_ROUTINE ||
+                            batchOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
+                        startBatching(client, sessionId, batchOptions);
+                    } else if (batchOptions.batchingMode == BATCHING_MODE_TRIP) {
+                        startTripBatchingMultiplex(client, sessionId, batchOptions);
+                    }
+                }
+            }
+            reportResponse(client, err, sessionId);
+        }));
+    }
+}
+
+void
+BatchingAdapter::getBatchedLocationsCommand(LocationAPI* client, uint32_t id, size_t count)
+{
+    LOC_LOGD("%s]: client %p id %u count %zu", __func__, client, id, count);
+
+    struct MsgGetBatchedLocations : public LocMsg {
+        BatchingAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        uint32_t mSessionId;
+        size_t mCount;
+        inline MsgGetBatchedLocations(BatchingAdapter& adapter,
+                                     LocApiBase& api,
+                                     LocationAPI* client,
+                                     uint32_t sessionId,
+                                     size_t count) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mSessionId(sessionId),
+            mCount(count) {}
+        inline virtual void proc() const {
+            if (!mAdapter.isEngineCapabilitiesKnown()) {
+                mAdapter.mPendingMsgs.push_back(new MsgGetBatchedLocations(*this));
+                return;
+            }
+            LocationError err = LOCATION_ERROR_SUCCESS;
+            if (!mAdapter.hasBatchingCallback(mClient)) {
+                err = LOCATION_ERROR_CALLBACK_MISSING;
+            } else if (!mAdapter.isBatchingSession(mClient, mSessionId)) {
+                err = LOCATION_ERROR_ID_UNKNOWN;
+            }
+            if (LOCATION_ERROR_SUCCESS == err) {
+                if (mAdapter.isTripSession(mSessionId)) {
+                    mApi.getBatchedTripLocations(mCount, 0,
+                            new LocApiResponse(*mAdapter.getContext(),
+                            [&mAdapter = mAdapter, mSessionId = mSessionId,
+                            mClient = mClient] (LocationError err) {
+                        mAdapter.reportResponse(mClient, err, mSessionId);
+                    }));
+                } else {
+                    mApi.getBatchedLocations(mCount, new LocApiResponse(*mAdapter.getContext(),
+                            [&mAdapter = mAdapter, mSessionId = mSessionId,
+                            mClient = mClient] (LocationError err) {
+                        mAdapter.reportResponse(mClient, err, mSessionId);
+                    }));
+                }
+            } else {
+                mAdapter.reportResponse(mClient, err, mSessionId);
+            }
+        }
+    };
+
+    sendMsg(new MsgGetBatchedLocations(*this, *mLocApi, client, id, count));
+}
+
+void
+BatchingAdapter::reportLocationsEvent(const Location* locations, size_t count,
+        BatchingMode batchingMode)
+{
+    LOC_LOGD("%s]: count %zu batchMode %d", __func__, count, batchingMode);
+
+    struct MsgReportLocations : public LocMsg {
+        BatchingAdapter& mAdapter;
+        Location* mLocations;
+        size_t mCount;
+        BatchingMode mBatchingMode;
+        inline MsgReportLocations(BatchingAdapter& adapter,
+                                  const Location* locations,
+                                  size_t count,
+                                  BatchingMode batchingMode) :
+            LocMsg(),
+            mAdapter(adapter),
+            mLocations(new Location[count]),
+            mCount(count),
+            mBatchingMode(batchingMode)
+        {
+            if (nullptr == mLocations) {
+                LOC_LOGE("%s]: new failed to allocate mLocations", __func__);
+                return;
+            }
+            for (size_t i=0; i < mCount; ++i) {
+                mLocations[i] = locations[i];
+            }
+        }
+        inline virtual ~MsgReportLocations() {
+            if (nullptr != mLocations)
+                delete[] mLocations;
+        }
+        inline virtual void proc() const {
+            mAdapter.reportLocations(mLocations, mCount, mBatchingMode);
+        }
+    };
+
+    sendMsg(new MsgReportLocations(*this, locations, count, batchingMode));
+}
+
+void
+BatchingAdapter::reportLocations(Location* locations, size_t count, BatchingMode batchingMode)
+{
+    BatchingOptions batchOptions = {sizeof(BatchingOptions), batchingMode};
+
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        if (nullptr != it->second.batchingCb) {
+            it->second.batchingCb(count, locations, batchOptions);
+        }
+    }
+}
+
+void
+BatchingAdapter::reportCompletedTripsEvent(uint32_t accumulated_distance)
+{
+    struct MsgReportCompletedTrips : public LocMsg {
+        BatchingAdapter& mAdapter;
+        uint32_t mAccumulatedDistance;
+        inline MsgReportCompletedTrips(BatchingAdapter& adapter,
+                                  uint32_t accumulated_distance) :
+            LocMsg(),
+            mAdapter(adapter),
+            mAccumulatedDistance(accumulated_distance)
+        {
+        }
+        inline virtual ~MsgReportCompletedTrips() {
+        }
+        inline virtual void proc() const {
+
+            // Check if any trips are completed
+            std::list<uint32_t> completedTripsList;
+            completedTripsList.clear();
+
+            for(auto itt = mAdapter.mTripSessions.begin(); itt != mAdapter.mTripSessions.end();)
+            {
+                TripSessionStatus &tripSession = itt->second;
+
+                tripSession.accumulatedDistanceThisTrip =
+                        tripSession.accumulatedDistanceOnTripRestart
+                        + (mAccumulatedDistance - tripSession.accumulatedDistanceOngoingBatch);
+                if (tripSession.tripDistance <= tripSession.accumulatedDistanceThisTrip) {
+                    // trip is completed
+                    completedTripsList.push_back(itt->first);
+                    itt = mAdapter.mTripSessions.erase(itt);
+
+                    if (tripSession.tripTBFInterval == mAdapter.mOngoingTripTBFInterval) {
+                        // trip with ongoing TBF interval is completed
+                        mAdapter.mTripWithOngoingTBFDropped = true;
+                    }
+
+                    if (tripSession.tripDistance == mAdapter.mOngoingTripDistance) {
+                        // trip with ongoing trip distance is completed
+                        mAdapter.mTripWithOngoingTripDistanceDropped = true;
+                    }
+                } else {
+                    itt++;
+                }
+            }
+
+            if (completedTripsList.size() > 0) {
+                mAdapter.reportBatchStatusChange(BATCHING_STATUS_TRIP_COMPLETED,
+                        completedTripsList);
+                mAdapter.restartTripBatching(false, mAccumulatedDistance, 0);
+            } else {
+                mAdapter.printTripReport();
+            }
+        }
+    };
+
+    LOC_LOGD("%s]: Accumulated Distance so far: %u",
+               __func__,  accumulated_distance);
+
+    sendMsg(new MsgReportCompletedTrips(*this, accumulated_distance));
+}
+
+void
+BatchingAdapter::reportBatchStatusChange(BatchingStatus batchStatus,
+        std::list<uint32_t> & completedTripsList)
+{
+    BatchingStatusInfo batchStatusInfo =
+            {sizeof(BatchingStatusInfo), batchStatus};
+
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        if (nullptr != it->second.batchingStatusCb) {
+            it->second.batchingStatusCb(batchStatusInfo, completedTripsList);
+        }
+    }
+}
+
+void
+BatchingAdapter::reportBatchStatusChangeEvent(BatchingStatus batchStatus)
+{
+    struct MsgReportBatchStatus : public LocMsg {
+        BatchingAdapter& mAdapter;
+        BatchingStatus mBatchStatus;
+        inline MsgReportBatchStatus(BatchingAdapter& adapter,
+                BatchingStatus batchStatus) :
+            LocMsg(),
+            mAdapter(adapter),
+            mBatchStatus(batchStatus)
+        {
+        }
+        inline virtual ~MsgReportBatchStatus() {
+        }
+        inline virtual void proc() const {
+            std::list<uint32_t> tempList;
+            tempList.clear();
+            mAdapter.reportBatchStatusChange(mBatchStatus, tempList);
+        }
+    };
+
+    sendMsg(new MsgReportBatchStatus(*this, batchStatus));
+}
+
+void
+BatchingAdapter::startTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
+        const BatchingOptions& batchingOptions)
+{
+    if (mTripSessions.size() == 0) {
+        // if there is currenty no batching sessions interested in batch full event, then this
+        // new session will need to register for batch full event
+        if (0 == autoReportBatchingSessionsCount()) {
+            updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+                          LOC_REGISTRATION_MASK_ENABLED);
+        }
+
+        // Assume start will be OK, remove session if not
+        saveBatchingSession(client, sessionId, batchingOptions);
+
+        mTripSessions[sessionId] = { 0, 0, 0, batchingOptions.minDistance,
+                batchingOptions.minInterval};
+        mLocApi->startOutdoorTripBatching(batchingOptions.minDistance,
+                batchingOptions.minInterval, getBatchingTimeout(), new LocApiResponse(*getContext(),
+                [this, client, sessionId, batchingOptions] (LocationError err) {
+            if (err == LOCATION_ERROR_SUCCESS) {
+                mOngoingTripDistance = batchingOptions.minDistance;
+                mOngoingTripTBFInterval = batchingOptions.minInterval;
+                LOC_LOGD("%s] New Trip started ...", __func__);
+                printTripReport();
+            } else {
+                eraseBatchingSession(client, sessionId);
+                mTripSessions.erase(sessionId);
+                // if we fail to start batching and we have already registered batch full event
+                // we need to undo that since no sessions are now interested in batch full event
+                if (0 == autoReportBatchingSessionsCount()) {
+                    updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+                                  LOC_REGISTRATION_MASK_DISABLED);
+                }
+            }
+            reportResponse(client, err, sessionId);
+        }));
+    } else {
+        // query accumulated distance
+        mLocApi->queryAccumulatedTripDistance(
+                new LocApiResponseData<LocApiBatchData>(*getContext(),
+                [this, batchingOptions, sessionId, client]
+                (LocationError err, LocApiBatchData data) {
+            uint32_t accumulatedDistanceOngoingBatch = 0;
+            uint32_t numOfBatchedPositions = 0;
+            uint32_t ongoingTripDistance = mOngoingTripDistance;
+            uint32_t ongoingTripInterval = mOngoingTripTBFInterval;
+            bool needsRestart = false;
+
+            // check if TBF of new session is lesser than ongoing TBF interval
+            if (ongoingTripInterval > batchingOptions.minInterval) {
+                ongoingTripInterval = batchingOptions.minInterval;
+                needsRestart = true;
+            }
+            accumulatedDistanceOngoingBatch = data.accumulatedDistance;
+            numOfBatchedPositions = data.numOfBatchedPositions;
+            TripSessionStatus newTripSession = { accumulatedDistanceOngoingBatch, 0, 0,
+                                                 batchingOptions.minDistance,
+                                                 batchingOptions.minInterval};
+            if (err != LOCATION_ERROR_SUCCESS) {
+                // unable to query accumulated distance, assume remaining distance in
+                // ongoing batch is mongoingTripDistance.
+                if (batchingOptions.minDistance < ongoingTripDistance) {
+                    ongoingTripDistance = batchingOptions.minDistance;
+                    needsRestart = true;
+                }
+            } else {
+                // compute the remaining distance
+                uint32_t ongoing_trip_remaining_distance = ongoingTripDistance -
+                        accumulatedDistanceOngoingBatch;
+
+                // check if new trip distance is lesser than the ongoing batch remaining distance
+                if (batchingOptions.minDistance < ongoing_trip_remaining_distance) {
+                    ongoingTripDistance = batchingOptions.minDistance;
+                    needsRestart = true;
+                } else if (needsRestart == true) {
+                    // needsRestart is anyways true , may be because of lesser TBF of new session.
+                    ongoingTripDistance = ongoing_trip_remaining_distance;
+                }
+                mTripSessions[sessionId] = newTripSession;
+                LOC_LOGD("%s] New Trip started ...", __func__);
+                printTripReport();
+            }
+
+            if (needsRestart) {
+                mOngoingTripDistance = ongoingTripDistance;
+                mOngoingTripTBFInterval = ongoingTripInterval;
+
+                // reset the accumulatedDistanceOngoingBatch for each session,
+                // and record the total accumulated distance so far for the session.
+                for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
+                    TripSessionStatus &tripSessStatus = itt->second;
+                    tripSessStatus.accumulatedDistanceOngoingBatch = 0;
+                    tripSessStatus.accumulatedDistanceOnTripRestart =
+                            tripSessStatus.accumulatedDistanceThisTrip;
+                }
+                mLocApi->reStartOutdoorTripBatching(ongoingTripDistance, ongoingTripInterval,
+                        getBatchingTimeout(), new LocApiResponse(*getContext(),
+                        [this, client, sessionId] (LocationError err) {
+                    if (err != LOCATION_ERROR_SUCCESS) {
+                        LOC_LOGE("%s] New Trip restart failed!", __func__);
+                    }
+                    reportResponse(client, err, sessionId);
+                }));
+            } else {
+                reportResponse(client, LOCATION_ERROR_SUCCESS, sessionId);
+            }
+        }));
+    }
+}
+
+void
+BatchingAdapter::stopTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
+        bool restartNeeded, const BatchingOptions& batchOptions)
+{
+    LocationError err = LOCATION_ERROR_SUCCESS;
+
+    if (mTripSessions.size() == 1) {
+        mLocApi->stopOutdoorTripBatching(true, new LocApiResponse(*getContext(),
+                [this, restartNeeded, client, sessionId, batchOptions]
+                (LocationError err) {
+            if (LOCATION_ERROR_SUCCESS == err) {
+                // if stopOutdoorTripBatching is success, unregister for batch full event if this
+                // was the last batching session that is interested in batch full event
+                if (1 == autoReportBatchingSessionsCount()) {
+                    updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+                                  LOC_REGISTRATION_MASK_DISABLED);
+                }
+            }
+            stopTripBatchingMultiplexCommon(err, client, sessionId, restartNeeded, batchOptions);
+        }));
+        return;
+    }
+
+    stopTripBatchingMultiplexCommon(err, client, sessionId, restartNeeded, batchOptions);
+}
+
+void
+BatchingAdapter::stopTripBatchingMultiplexCommon(LocationError err, LocationAPI* client,
+        uint32_t sessionId, bool restartNeeded, const BatchingOptions& batchOptions)
+{
+    auto itt = mTripSessions.find(sessionId);
+    TripSessionStatus tripSess = itt->second;
+    if (tripSess.tripTBFInterval == mOngoingTripTBFInterval) {
+        // trip with ongoing trip interval is stopped
+        mTripWithOngoingTBFDropped = true;
+    }
+
+    if (tripSess.tripDistance == mOngoingTripDistance) {
+        // trip with ongoing trip distance is stopped
+        mTripWithOngoingTripDistanceDropped = true;
+    }
+
+    mTripSessions.erase(sessionId);
+
+    if (mTripSessions.size() == 0) {
+        mOngoingTripDistance = 0;
+        mOngoingTripTBFInterval = 0;
+    } else {
+        restartTripBatching(true);
+    }
+
+    if (restartNeeded) {
+        eraseBatchingSession(client, sessionId);
+        if (batchOptions.batchingMode == BATCHING_MODE_ROUTINE ||
+                batchOptions.batchingMode == BATCHING_MODE_NO_AUTO_REPORT) {
+            startBatching(client, sessionId, batchOptions);
+        } else if (batchOptions.batchingMode == BATCHING_MODE_TRIP) {
+            startTripBatchingMultiplex(client, sessionId, batchOptions);
+        }
+    }
+    reportResponse(client, err, sessionId);
+}
+
+
+void
+BatchingAdapter::restartTripBatching(bool queryAccumulatedDistance, uint32_t accDist,
+        uint32_t numbatchedPos)
+{
+    // does batch need restart with new trip distance / TBF interval
+    uint32_t minRemainingDistance = 0;
+    uint32_t minTBFInterval = 0;
+
+    // if no more trips left, stop the ongoing trip
+    if (mTripSessions.size() == 0) {
+        mLocApi->stopOutdoorTripBatching(true, new LocApiResponse(*getContext(),
+                                               [] (LocationError /*err*/) {}));
+        mOngoingTripDistance = 0;
+        mOngoingTripTBFInterval = 0;
+        // unregister for batch full event if there are no more
+        // batching session that is interested in batch full event
+        if (0 == autoReportBatchingSessionsCount()) {
+                updateEvtMask(LOC_API_ADAPTER_BIT_BATCH_FULL,
+                              LOC_REGISTRATION_MASK_DISABLED);
+        }
+        return;
+    }
+
+    // record the min trip distance and min tbf interval of all ongoing sessions
+    for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
+
+        TripSessionStatus tripSessStatus = itt->second;
+
+        if ((minRemainingDistance == 0) ||
+                (minRemainingDistance > (tripSessStatus.tripDistance
+                - tripSessStatus.accumulatedDistanceThisTrip))) {
+            minRemainingDistance = tripSessStatus.tripDistance -
+                    tripSessStatus.accumulatedDistanceThisTrip;
+        }
+
+        if ((minTBFInterval == 0) ||
+            (minTBFInterval > tripSessStatus.tripTBFInterval)) {
+            minTBFInterval = tripSessStatus.tripTBFInterval;
+        }
+    }
+
+    mLocApi->queryAccumulatedTripDistance(
+            new LocApiResponseData<LocApiBatchData>(*getContext(),
+            [this, queryAccumulatedDistance, minRemainingDistance, minTBFInterval, accDist,
+            numbatchedPos] (LocationError /*err*/, LocApiBatchData data) {
+        bool needsRestart = false;
+
+        uint32_t ongoingTripDistance = mOngoingTripDistance;
+        uint32_t ongoingTripInterval = mOngoingTripTBFInterval;
+        uint32_t accumulatedDistance = accDist;
+        uint32_t numOfBatchedPositions = numbatchedPos;
+
+        if (queryAccumulatedDistance) {
+            accumulatedDistance = data.accumulatedDistance;
+            numOfBatchedPositions = data.numOfBatchedPositions;
+        }
+
+        if ((!mTripWithOngoingTripDistanceDropped) &&
+                (ongoingTripDistance - accumulatedDistance != 0)) {
+            // if ongoing trip is already not completed still,
+            // check the min distance against the remaining distance
+            if (minRemainingDistance <
+                    (ongoingTripDistance - accumulatedDistance)) {
+                ongoingTripDistance = minRemainingDistance;
+                needsRestart = true;
+            }
+        } else if (minRemainingDistance != 0) {
+            // else if ongoing trip is already completed / dropped,
+            // use the minRemainingDistance of ongoing sessions
+            ongoingTripDistance = minRemainingDistance;
+            needsRestart = true;
+        }
+
+         if ((minTBFInterval < ongoingTripInterval) ||
+                    ((minTBFInterval != ongoingTripInterval) &&
+                    (mTripWithOngoingTBFDropped))) {
+            ongoingTripInterval = minTBFInterval;
+            needsRestart = true;
+        }
+
+        if (needsRestart) {
+            mLocApi->reStartOutdoorTripBatching(ongoingTripDistance, ongoingTripInterval,
+                    getBatchingTimeout(), new LocApiResponse(*getContext(),
+                    [this, accumulatedDistance, ongoingTripDistance, ongoingTripInterval]
+                    (LocationError err) {
+
+                if (err == LOCATION_ERROR_SUCCESS) {
+                    for(auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
+                        TripSessionStatus &tripSessStatus = itt->second;
+                        tripSessStatus.accumulatedDistanceThisTrip =
+                                tripSessStatus.accumulatedDistanceOnTripRestart +
+                                (accumulatedDistance -
+                                 tripSessStatus.accumulatedDistanceOngoingBatch);
+
+                        tripSessStatus.accumulatedDistanceOngoingBatch = 0;
+                        tripSessStatus.accumulatedDistanceOnTripRestart =
+                                tripSessStatus.accumulatedDistanceThisTrip;
+                    }
+
+                    mOngoingTripDistance = ongoingTripDistance;
+                    mOngoingTripTBFInterval = ongoingTripInterval;
+                }
+            }));
+        }
+    }));
+}
+
+void
+BatchingAdapter::printTripReport()
+{
+    IF_LOC_LOGD {
+        LOC_LOGD("Ongoing Trip Distance = %u, Ongoing Trip TBF Interval = %u",
+                mOngoingTripDistance, mOngoingTripTBFInterval);
+
+        for (auto itt = mTripSessions.begin(); itt != mTripSessions.end(); itt++) {
+            TripSessionStatus tripSessStatus = itt->second;
+
+            LOC_LOGD("tripDistance:%u tripTBFInterval:%u"
+                    " trip accumulated Distance:%u"
+                    " trip accumualted distance ongoing batch:%u"
+                    " trip accumulated distance on trip restart %u \r\n",
+                    tripSessStatus.tripDistance, tripSessStatus.tripTBFInterval,
+                    tripSessStatus.accumulatedDistanceThisTrip,
+                    tripSessStatus.accumulatedDistanceOngoingBatch,
+                    tripSessStatus.accumulatedDistanceOnTripRestart);
+        }
+    }
+}
diff --git a/gps/batching/BatchingAdapter.h b/gps/batching/BatchingAdapter.h
new file mode 100644
index 0000000..66f7c5f
--- /dev/null
+++ b/gps/batching/BatchingAdapter.h
@@ -0,0 +1,152 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef BATCHING_ADAPTER_H
+#define BATCHING_ADAPTER_H
+
+#include <LocAdapterBase.h>
+#include <LocContext.h>
+#include <LocationAPI.h>
+#include <map>
+
+using namespace loc_core;
+
+class BatchingAdapter : public LocAdapterBase {
+
+    /* ==== BATCHING ======================================================================= */
+    typedef struct {
+        uint32_t accumulatedDistanceOngoingBatch;
+        uint32_t accumulatedDistanceThisTrip;
+        uint32_t accumulatedDistanceOnTripRestart;
+        uint32_t tripDistance;
+        uint32_t tripTBFInterval;
+    } TripSessionStatus;
+    typedef std::map<uint32_t, TripSessionStatus> TripSessionStatusMap;
+    typedef std::map<LocationSessionKey, BatchingOptions> BatchingSessionMap;
+
+    BatchingSessionMap mBatchingSessions;
+    TripSessionStatusMap mTripSessions;
+    uint32_t mOngoingTripDistance;
+    uint32_t mOngoingTripTBFInterval;
+    bool mTripWithOngoingTBFDropped;
+    bool mTripWithOngoingTripDistanceDropped;
+
+    void startTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
+                                    const BatchingOptions& batchingOptions);
+    void stopTripBatchingMultiplex(LocationAPI* client, uint32_t sessionId,
+                                   bool restartNeeded,
+                                   const BatchingOptions& batchOptions);
+    inline void stopTripBatchingMultiplex(LocationAPI* client, uint32_t id) {
+        BatchingOptions batchOptions;
+        stopTripBatchingMultiplex(client, id, false, batchOptions);
+    };
+    void stopTripBatchingMultiplexCommon(LocationError err,
+                                         LocationAPI* client,
+                                         uint32_t sessionId,
+                                         bool restartNeeded,
+                                         const BatchingOptions& batchOptions);
+    void restartTripBatching(bool queryAccumulatedDistance, uint32_t accDist = 0,
+                             uint32_t numbatchedPos = 0);
+    void printTripReport();
+
+    /* ==== CONFIGURATION ================================================================== */
+    uint32_t mBatchingTimeout;
+    uint32_t mBatchingAccuracy;
+    size_t mBatchSize;
+    size_t mTripBatchSize;
+
+protected:
+
+    /* ==== CLIENT ========================================================================= */
+    virtual void updateClientsEventMask();
+    virtual void stopClientSessions(LocationAPI* client);
+
+public:
+    BatchingAdapter();
+    virtual ~BatchingAdapter() {}
+
+    /* ==== SSR ============================================================================ */
+    /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+    virtual void handleEngineUpEvent();
+    /* ======== UTILITIES ================================================================== */
+    void restartSessions();
+
+    /* ==== BATCHING ======================================================================= */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    uint32_t startBatchingCommand(LocationAPI* client, BatchingOptions &batchOptions);
+    void updateBatchingOptionsCommand(
+            LocationAPI* client, uint32_t id, BatchingOptions& batchOptions);
+    void stopBatchingCommand(LocationAPI* client, uint32_t id);
+    void getBatchedLocationsCommand(LocationAPI* client, uint32_t id, size_t count);
+    /* ======== RESPONSES ================================================================== */
+    void reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId);
+    /* ======== UTILITIES ================================================================== */
+    bool hasBatchingCallback(LocationAPI* client);
+    bool isBatchingSession(LocationAPI* client, uint32_t sessionId);
+    bool isTripSession(uint32_t sessionId);
+    void saveBatchingSession(LocationAPI* client, uint32_t sessionId,
+                             const BatchingOptions& batchingOptions);
+    void eraseBatchingSession(LocationAPI* client, uint32_t sessionId);
+    uint32_t autoReportBatchingSessionsCount();
+    void startBatching(LocationAPI* client, uint32_t sessionId,
+                       const BatchingOptions& batchingOptions);
+    void stopBatching(LocationAPI* client, uint32_t sessionId, bool restartNeeded,
+                      const BatchingOptions& batchOptions);
+    void stopBatching(LocationAPI* client, uint32_t sessionId) {
+        BatchingOptions batchOptions;
+        stopBatching(client, sessionId, false, batchOptions);
+    };
+
+    /* ==== REPORTS ======================================================================== */
+    /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+    void reportLocationsEvent(const Location* locations, size_t count,
+            BatchingMode batchingMode);
+    void reportCompletedTripsEvent(uint32_t accumulatedDistance);
+    void reportBatchStatusChangeEvent(BatchingStatus batchStatus);
+    /* ======== UTILITIES ================================================================== */
+    void reportLocations(Location* locations, size_t count, BatchingMode batchingMode);
+    void reportBatchStatusChange(BatchingStatus batchStatus,
+            std::list<uint32_t> & completedTripsList);
+
+    /* ==== CONFIGURATION ================================================================== */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    void readConfigCommand();
+    void setConfigCommand();
+    /* ======== UTILITIES ================================================================== */
+    void setBatchSize(size_t batchSize) { mBatchSize = batchSize; }
+    size_t getBatchSize() { return mBatchSize; }
+    void setTripBatchSize(size_t batchSize) { mTripBatchSize = batchSize; }
+    size_t getTripBatchSize() { return mTripBatchSize; }
+    void setBatchingTimeout(uint32_t batchingTimeout) { mBatchingTimeout = batchingTimeout; }
+    uint32_t getBatchingTimeout() { return mBatchingTimeout; }
+    void setBatchingAccuracy(uint32_t accuracy) { mBatchingAccuracy = accuracy; }
+    uint32_t getBatchingAccuracy() { return mBatchingAccuracy; }
+
+};
+
+#endif /* BATCHING_ADAPTER_H */
diff --git a/gps/batching/Makefile.am b/gps/batching/Makefile.am
new file mode 100644
index 0000000..d5cba39
--- /dev/null
+++ b/gps/batching/Makefile.am
@@ -0,0 +1,44 @@
+AM_CFLAGS = \
+     $(GPSUTILS_CFLAGS) \
+     $(LOCCORE_CFLAGS) \
+     -I./ \
+     -std=c++1y \
+     -D__func__=__PRETTY_FUNCTION__ \
+     -fno-short-enums
+
+ACLOCAL_AMFLAGS = -I m4
+
+requiredlibs = \
+        $(GPSUTILS_LIBS) \
+        $(LOCCORE_LIBS) \
+        -llog
+
+h_sources = \
+    BatchingAdapter.h
+
+libbatching_la_SOURCES = \
+    location_batching.cpp \
+    BatchingAdapter.cpp
+
+if USE_GLIB
+libbatching_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+libbatching_la_LDFLAGS = -lstdc++ -g -Wl,-z,defs -lpthread $(requiredlibs) @GLIB_LIBS@ -shared -version-info 1:0:0
+libbatching_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+libbatching_la_CFLAGS = $(AM_CFLAGS)
+libbatching_la_LDFLAGS = -Wl,-z,defs -lpthread $(requiredlibs) -shared -version-info 1:0:0
+libbatching_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+library_include_HEADERS = $(h_sources)
+
+library_includedir = $(pkgincludedir)
+
+#Create and Install libraries
+lib_LTLIBRARIES = libbatching.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = location-batching.pc
+sysconf_DATA = $(WORKSPACE)/hardware/qcom/gps/etc/flp.conf
+EXTRA_DIST = $(pkgconfig_DATA)
+
diff --git a/gps/batching/configure.ac b/gps/batching/configure.ac
new file mode 100644
index 0000000..4ca4998
--- /dev/null
+++ b/gps/batching/configure.ac
@@ -0,0 +1,74 @@
+# configure.ac -- Autoconf script for gps location-batching
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps location-batching package version 1.0.0
+AC_INIT([location-batching],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([Makefile.am])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+PKG_CHECK_MODULES([LOCCORE], [loc-core])
+AC_SUBST([LOCCORE_CFLAGS])
+AC_SUBST([LOCCORE_LIBS])
+
+AC_ARG_WITH([locpla_includes],
+      AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+         [specify the path to locpla-includes in loc-pla_git.bb]),
+      [locpla_incdir=$withval],
+      with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+   AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_ARG_WITH([glib],
+      AC_HELP_STRING([--with-glib],
+         [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+        AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+        PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GThread >= 2.16 is required))
+        PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GLib >= 2.16 is required))
+        GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+        GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+        AC_SUBST(GLIB_CFLAGS)
+        AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_CONFIG_FILES([ \
+        Makefile \
+        location-batching.pc
+        ])
+
+AC_OUTPUT
diff --git a/gps/batching/location-batching.pc.in b/gps/batching/location-batching.pc.in
new file mode 100644
index 0000000..da1fbf4
--- /dev/null
+++ b/gps/batching/location-batching.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: location-batching
+Description: QTI GPS Batching
+Version: @VERSION
+Libs: -L${libdir} -lbatching
+Cflags: -I${includedir}/location-batching
diff --git a/gps/batching/location_batching.cpp b/gps/batching/location_batching.cpp
new file mode 100644
index 0000000..571da72
--- /dev/null
+++ b/gps/batching/location_batching.cpp
@@ -0,0 +1,134 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "BatchingAdapter.h"
+#include "location_interface.h"
+
+static BatchingAdapter* gBatchingAdapter = NULL;
+
+static void initialize();
+static void deinitialize();
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks);
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+static void requestCapabilities(LocationAPI* client);
+
+static uint32_t startBatching(LocationAPI* client, BatchingOptions&);
+static void stopBatching(LocationAPI* client, uint32_t id);
+static void updateBatchingOptions(LocationAPI* client, uint32_t id, BatchingOptions&);
+static void getBatchedLocations(LocationAPI* client, uint32_t id, size_t count);
+
+static const BatchingInterface gBatchingInterface = {
+    sizeof(BatchingInterface),
+    initialize,
+    deinitialize,
+    addClient,
+    removeClient,
+    requestCapabilities,
+    startBatching,
+    stopBatching,
+    updateBatchingOptions,
+    getBatchedLocations
+};
+
+#ifndef DEBUG_X86
+extern "C" const BatchingInterface* getBatchingInterface()
+#else
+const BatchingInterface* getBatchingInterface()
+#endif // DEBUG_X86
+{
+   return &gBatchingInterface;
+}
+
+static void initialize()
+{
+    if (NULL == gBatchingAdapter) {
+        gBatchingAdapter = new BatchingAdapter();
+    }
+}
+
+static void deinitialize()
+{
+    if (NULL != gBatchingAdapter) {
+        delete gBatchingAdapter;
+        gBatchingAdapter = NULL;
+    }
+}
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+    if (NULL != gBatchingAdapter) {
+        gBatchingAdapter->addClientCommand(client, callbacks);
+    }
+}
+
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb)
+{
+    if (NULL != gBatchingAdapter) {
+        gBatchingAdapter->removeClientCommand(client, rmClientCb);
+    }
+}
+
+static void requestCapabilities(LocationAPI* client)
+{
+    if (NULL != gBatchingAdapter) {
+        gBatchingAdapter->requestCapabilitiesCommand(client);
+    }
+}
+
+static uint32_t startBatching(LocationAPI* client, BatchingOptions &batchOptions)
+{
+    if (NULL != gBatchingAdapter) {
+        return gBatchingAdapter->startBatchingCommand(client, batchOptions);
+    } else {
+        return 0;
+    }
+}
+
+static void stopBatching(LocationAPI* client, uint32_t id)
+{
+    if (NULL != gBatchingAdapter) {
+        gBatchingAdapter->stopBatchingCommand(client, id);
+    }
+}
+
+static void updateBatchingOptions(
+        LocationAPI* client, uint32_t id, BatchingOptions& batchOptions)
+{
+    if (NULL != gBatchingAdapter) {
+        gBatchingAdapter->updateBatchingOptionsCommand(client, id, batchOptions);
+    }
+}
+
+static void getBatchedLocations(LocationAPI* client, uint32_t id, size_t count)
+{
+    if (NULL != gBatchingAdapter) {
+        gBatchingAdapter->getBatchedLocationsCommand(client, id, count);
+    }
+}
+
diff --git a/gps/configure.ac b/gps/configure.ac
new file mode 100644
index 0000000..2a44051
--- /dev/null
+++ b/gps/configure.ac
@@ -0,0 +1,87 @@
+# configure.ac -- Autoconf script for gps loc_hal
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps loc-hal package version 1.0.0
+AC_INIT([loc-hal],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([Makefile.am])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+PKG_CHECK_MODULES([LOCCORE], [loc-core])
+AC_SUBST([LOCCORE_CFLAGS])
+AC_SUBST([LOCCORE_LIBS])
+
+AC_ARG_WITH([core_includes],
+      AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
+         [Specify the location of the core headers]),
+      [core_incdir=$withval],
+      with_core_includes=no)
+
+if test "x$with_core_includes" != "xno"; then
+   CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
+fi
+
+AC_ARG_WITH([locpla_includes],
+      AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+         [specify the path to locpla-includes in loc-pla_git.bb]),
+      [locpla_incdir=$withval],
+      with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+   AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_SUBST([CPPFLAGS])
+
+AC_ARG_WITH([glib],
+      AC_HELP_STRING([--with-glib],
+         [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+        AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+        PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GThread >= 2.16 is required))
+        PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GLib >= 2.16 is required))
+        GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+        GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+        AC_SUBST(GLIB_CFLAGS)
+        AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_CONFIG_FILES([ \
+        Makefile \
+        gnss/Makefile \
+        loc-hal.pc \
+        ])
+
+AC_OUTPUT
diff --git a/gps/core/Android.bp b/gps/core/Android.bp
new file mode 100644
index 0000000..fe9f067
--- /dev/null
+++ b/gps/core/Android.bp
@@ -0,0 +1,56 @@
+
+cc_library_shared {
+
+    name: "libloc_core",
+    vendor: true,
+
+
+
+    shared_libs: [
+        "liblog",
+        "libutils",
+        "libcutils",
+        "libgps.utils",
+        "libdl",
+        "liblog",
+    ],
+
+    srcs: [
+        "LocApiBase.cpp",
+        "LocAdapterBase.cpp",
+        "ContextBase.cpp",
+        "LocContext.cpp",
+        "loc_core_log.cpp",
+        "data-items/DataItemsFactoryProxy.cpp",
+        "SystemStatusOsObserver.cpp",
+        "SystemStatus.cpp",
+    ],
+
+    cflags: [
+        "-fno-short-enums",
+        "-D_ANDROID_",
+    ] + GNSS_CFLAGS,
+
+    local_include_dirs: [
+        "data-items",
+        "observer",
+    ],
+
+    header_libs: [
+        "libutils_headers",
+        "libgps.utils_headers",
+        "libloc_pla_headers",
+        "liblocation_api_headers",
+    ],
+
+}
+
+cc_library_headers {
+
+    name: "libloc_core_headers",
+    vendor: true,
+    export_include_dirs: ["."] + [
+        "data-items",
+        "observer",
+    ],
+}
diff --git a/gps/core/ContextBase.cpp b/gps/core/ContextBase.cpp
new file mode 100644
index 0000000..87e98dc
--- /dev/null
+++ b/gps/core/ContextBase.cpp
@@ -0,0 +1,384 @@
+/* Copyright (c) 2011-2014,2016-2017,2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_CtxBase"
+
+#include <dlfcn.h>
+#include <unistd.h>
+#include <ContextBase.h>
+#include <msg_q.h>
+#include <loc_target.h>
+#include <loc_pla.h>
+#include <loc_log.h>
+
+namespace loc_core {
+
+#define SLL_LOC_API_LIB_NAME "libsynergy_loc_api.so"
+#define LOC_APIV2_0_LIB_NAME "libloc_api_v02.so"
+#define IS_SS5_HW_ENABLED  1
+
+loc_gps_cfg_s_type ContextBase::mGps_conf {};
+loc_sap_cfg_s_type ContextBase::mSap_conf {};
+bool ContextBase::sIsEngineCapabilitiesKnown = false;
+uint64_t ContextBase::sSupportedMsgMask = 0;
+bool ContextBase::sGnssMeasurementSupported = false;
+uint8_t ContextBase::sFeaturesSupported[MAX_FEATURE_LENGTH];
+GnssNMEARptRate ContextBase::sNmeaReportRate = GNSS_NMEA_REPORT_RATE_NHZ;
+LocationCapabilitiesMask ContextBase::sQwesFeatureMask = 0;
+
+const loc_param_s_type ContextBase::mGps_conf_table[] =
+{
+  {"GPS_LOCK",                       &mGps_conf.GPS_LOCK,                       NULL, 'n'},
+  {"SUPL_VER",                       &mGps_conf.SUPL_VER,                       NULL, 'n'},
+  {"LPP_PROFILE",                    &mGps_conf.LPP_PROFILE,                    NULL, 'n'},
+  {"A_GLONASS_POS_PROTOCOL_SELECT",  &mGps_conf.A_GLONASS_POS_PROTOCOL_SELECT,  NULL, 'n'},
+  {"LPPE_CP_TECHNOLOGY",             &mGps_conf.LPPE_CP_TECHNOLOGY,             NULL, 'n'},
+  {"LPPE_UP_TECHNOLOGY",             &mGps_conf.LPPE_UP_TECHNOLOGY,             NULL, 'n'},
+  {"AGPS_CERT_WRITABLE_MASK",        &mGps_conf.AGPS_CERT_WRITABLE_MASK,        NULL, 'n'},
+  {"SUPL_MODE",                      &mGps_conf.SUPL_MODE,                      NULL, 'n'},
+  {"SUPL_ES",                        &mGps_conf.SUPL_ES,                        NULL, 'n'},
+  {"INTERMEDIATE_POS",               &mGps_conf.INTERMEDIATE_POS,               NULL, 'n'},
+  {"ACCURACY_THRES",                 &mGps_conf.ACCURACY_THRES,                 NULL, 'n'},
+  {"NMEA_PROVIDER",                  &mGps_conf.NMEA_PROVIDER,                  NULL, 'n'},
+  {"NMEA_REPORT_RATE",               &mGps_conf.NMEA_REPORT_RATE,               NULL, 's'},
+  {"CAPABILITIES",                   &mGps_conf.CAPABILITIES,                   NULL, 'n'},
+  {"XTRA_SERVER_1",                  &mGps_conf.XTRA_SERVER_1,                  NULL, 's'},
+  {"XTRA_SERVER_2",                  &mGps_conf.XTRA_SERVER_2,                  NULL, 's'},
+  {"XTRA_SERVER_3",                  &mGps_conf.XTRA_SERVER_3,                  NULL, 's'},
+  {"USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL",
+           &mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL,          NULL, 'n'},
+  {"AGPS_CONFIG_INJECT",             &mGps_conf.AGPS_CONFIG_INJECT,             NULL, 'n'},
+  {"EXTERNAL_DR_ENABLED",            &mGps_conf.EXTERNAL_DR_ENABLED,                  NULL, 'n'},
+  {"SUPL_HOST",                      &mGps_conf.SUPL_HOST,                      NULL, 's'},
+  {"SUPL_PORT",                      &mGps_conf.SUPL_PORT,                      NULL, 'n'},
+  {"MODEM_TYPE",                     &mGps_conf.MODEM_TYPE,                     NULL, 'n' },
+  {"MO_SUPL_HOST",                   &mGps_conf.MO_SUPL_HOST,                   NULL, 's' },
+  {"MO_SUPL_PORT",                   &mGps_conf.MO_SUPL_PORT,                   NULL, 'n' },
+  {"CONSTRAINED_TIME_UNCERTAINTY_ENABLED",
+           &mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_ENABLED,      NULL, 'n'},
+  {"CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD",
+           &mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD,    NULL, 'f'},
+  {"CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET",
+           &mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET, NULL, 'n'},
+  {"POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED",
+           &mGps_conf.POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED, NULL, 'n'},
+  {"PROXY_APP_PACKAGE_NAME",         &mGps_conf.PROXY_APP_PACKAGE_NAME,         NULL, 's' },
+  {"CP_MTLR_ES",                     &mGps_conf.CP_MTLR_ES,                     NULL, 'n' },
+  {"GNSS_DEPLOYMENT",  &mGps_conf.GNSS_DEPLOYMENT, NULL, 'n'},
+  {"CUSTOM_NMEA_GGA_FIX_QUALITY_ENABLED",
+           &mGps_conf.CUSTOM_NMEA_GGA_FIX_QUALITY_ENABLED, NULL, 'n'},
+  {"NMEA_TAG_BLOCK_GROUPING_ENABLED", &mGps_conf.NMEA_TAG_BLOCK_GROUPING_ENABLED, NULL, 'n'},
+  {"NI_SUPL_DENY_ON_NFW_LOCKED",  &mGps_conf.NI_SUPL_DENY_ON_NFW_LOCKED, NULL, 'n'},
+  {"ENABLE_NMEA_PRINT",  &mGps_conf.ENABLE_NMEA_PRINT, NULL, 'n'}
+};
+
+const loc_param_s_type ContextBase::mSap_conf_table[] =
+{
+  {"GYRO_BIAS_RANDOM_WALK",          &mSap_conf.GYRO_BIAS_RANDOM_WALK,          &mSap_conf.GYRO_BIAS_RANDOM_WALK_VALID, 'f'},
+  {"ACCEL_RANDOM_WALK_SPECTRAL_DENSITY",     &mSap_conf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY,    &mSap_conf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID, 'f'},
+  {"ANGLE_RANDOM_WALK_SPECTRAL_DENSITY",     &mSap_conf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY,    &mSap_conf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID, 'f'},
+  {"RATE_RANDOM_WALK_SPECTRAL_DENSITY",      &mSap_conf.RATE_RANDOM_WALK_SPECTRAL_DENSITY,     &mSap_conf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID, 'f'},
+  {"VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY",  &mSap_conf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY, &mSap_conf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID, 'f'},
+  {"SENSOR_ACCEL_BATCHES_PER_SEC",   &mSap_conf.SENSOR_ACCEL_BATCHES_PER_SEC,   NULL, 'n'},
+  {"SENSOR_ACCEL_SAMPLES_PER_BATCH", &mSap_conf.SENSOR_ACCEL_SAMPLES_PER_BATCH, NULL, 'n'},
+  {"SENSOR_GYRO_BATCHES_PER_SEC",    &mSap_conf.SENSOR_GYRO_BATCHES_PER_SEC,    NULL, 'n'},
+  {"SENSOR_GYRO_SAMPLES_PER_BATCH",  &mSap_conf.SENSOR_GYRO_SAMPLES_PER_BATCH,  NULL, 'n'},
+  {"SENSOR_ACCEL_BATCHES_PER_SEC_HIGH",   &mSap_conf.SENSOR_ACCEL_BATCHES_PER_SEC_HIGH,   NULL, 'n'},
+  {"SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH", &mSap_conf.SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH, NULL, 'n'},
+  {"SENSOR_GYRO_BATCHES_PER_SEC_HIGH",    &mSap_conf.SENSOR_GYRO_BATCHES_PER_SEC_HIGH,    NULL, 'n'},
+  {"SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH",  &mSap_conf.SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH,  NULL, 'n'},
+  {"SENSOR_CONTROL_MODE",            &mSap_conf.SENSOR_CONTROL_MODE,            NULL, 'n'},
+  {"SENSOR_ALGORITHM_CONFIG_MASK",   &mSap_conf.SENSOR_ALGORITHM_CONFIG_MASK,   NULL, 'n'}
+};
+
+void ContextBase::readConfig()
+{
+    static bool confReadDone = false;
+    if (!confReadDone) {
+        confReadDone = true;
+        /*Defaults for gps.conf*/
+        mGps_conf.INTERMEDIATE_POS = 0;
+        mGps_conf.ACCURACY_THRES = 0;
+        mGps_conf.NMEA_PROVIDER = 0;
+        mGps_conf.GPS_LOCK = GNSS_CONFIG_GPS_LOCK_MO_AND_NI;
+        mGps_conf.SUPL_VER = 0x10000;
+        mGps_conf.SUPL_MODE = 0x1;
+        mGps_conf.SUPL_ES = 0;
+        mGps_conf.CP_MTLR_ES = 0;
+        mGps_conf.SUPL_HOST[0] = 0;
+        mGps_conf.SUPL_PORT = 0;
+        mGps_conf.CAPABILITIES = 0x7;
+        /* LTE Positioning Profile configuration is disable by default*/
+        mGps_conf.LPP_PROFILE = 0;
+        /*By default no positioning protocol is selected on A-GLONASS system*/
+        mGps_conf.A_GLONASS_POS_PROTOCOL_SELECT = 0;
+        /*Use emergency PDN by default*/
+        mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL = 1;
+        /* By default no LPPe CP technology is enabled*/
+        mGps_conf.LPPE_CP_TECHNOLOGY = 0;
+        /* By default no LPPe UP technology is enabled*/
+        mGps_conf.LPPE_UP_TECHNOLOGY = 0;
+        /* By default we use unknown modem type*/
+        mGps_conf.MODEM_TYPE = 2;
+
+        /*Defaults for sap.conf*/
+        mSap_conf.GYRO_BIAS_RANDOM_WALK = 0;
+        mSap_conf.SENSOR_ACCEL_BATCHES_PER_SEC = 2;
+        mSap_conf.SENSOR_ACCEL_SAMPLES_PER_BATCH = 5;
+        mSap_conf.SENSOR_GYRO_BATCHES_PER_SEC = 2;
+        mSap_conf.SENSOR_GYRO_SAMPLES_PER_BATCH = 5;
+        mSap_conf.SENSOR_ACCEL_BATCHES_PER_SEC_HIGH = 4;
+        mSap_conf.SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH = 25;
+        mSap_conf.SENSOR_GYRO_BATCHES_PER_SEC_HIGH = 4;
+        mSap_conf.SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH = 25;
+        mSap_conf.SENSOR_CONTROL_MODE = 0; /* AUTO */
+        mSap_conf.SENSOR_ALGORITHM_CONFIG_MASK = 0; /* INS Disabled = FALSE*/
+        /* Values MUST be set by OEMs in configuration for sensor-assisted
+          navigation to work. There are NO default values */
+        mSap_conf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY = 0;
+        mSap_conf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY = 0;
+        mSap_conf.RATE_RANDOM_WALK_SPECTRAL_DENSITY = 0;
+        mSap_conf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY = 0;
+        mSap_conf.GYRO_BIAS_RANDOM_WALK_VALID = 0;
+        mSap_conf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID = 0;
+        mSap_conf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID = 0;
+        mSap_conf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID = 0;
+        mSap_conf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID = 0;
+
+        /* None of the 10 slots for agps certificates are writable by default */
+        mGps_conf.AGPS_CERT_WRITABLE_MASK = 0;
+
+        /* inject supl config to modem with config values from config.xml or gps.conf, default 1 */
+        mGps_conf.AGPS_CONFIG_INJECT = 1;
+
+        /* default configuration value of constrained time uncertainty mode:
+           feature disabled, time uncertainty threshold defined by modem,
+           and unlimited power budget */
+#ifdef FEATURE_AUTOMOTIVE
+        mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_ENABLED = 1;
+#else
+        mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_ENABLED = 0;
+#endif
+        mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD = 0.0;
+        mGps_conf.CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET = 0;
+
+        /* default configuration value of position assisted clock estimator mode */
+        mGps_conf.POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED = 0;
+        /* default configuration QTI GNSS H/W */
+        mGps_conf.GNSS_DEPLOYMENT = 0;
+        mGps_conf.CUSTOM_NMEA_GGA_FIX_QUALITY_ENABLED = 0;
+        /* default NMEA Tag Block Grouping is disabled */
+        mGps_conf.NMEA_TAG_BLOCK_GROUPING_ENABLED = 0;
+        /* default configuration for NI_SUPL_DENY_ON_NFW_LOCKED */
+        mGps_conf.NI_SUPL_DENY_ON_NFW_LOCKED = 1;
+        /* By default NMEA Printing is disabled */
+        mGps_conf.ENABLE_NMEA_PRINT = 0;
+
+        UTIL_READ_CONF(LOC_PATH_GPS_CONF, mGps_conf_table);
+        UTIL_READ_CONF(LOC_PATH_SAP_CONF, mSap_conf_table);
+
+        if (strncmp(mGps_conf.NMEA_REPORT_RATE, "1HZ", sizeof(mGps_conf.NMEA_REPORT_RATE)) == 0) {
+            /* NMEA reporting is configured at 1Hz*/
+            sNmeaReportRate = GNSS_NMEA_REPORT_RATE_1HZ;
+        } else {
+            sNmeaReportRate = GNSS_NMEA_REPORT_RATE_NHZ;
+        }
+        LOC_LOGI("%s] GNSS Deployment: %s", __FUNCTION__,
+                ((mGps_conf.GNSS_DEPLOYMENT == 1) ? "SS5" :
+                ((mGps_conf.GNSS_DEPLOYMENT == 2) ? "QFUSION" : "QGNSS")));
+
+        switch (getTargetGnssType(loc_get_target())) {
+          case GNSS_GSS:
+          case GNSS_AUTO:
+             // For APQ targets, MSA/MSB capabilities should be reset
+             mGps_conf.CAPABILITIES &= ~(LOC_GPS_CAPABILITY_MSA | LOC_GPS_CAPABILITY_MSB);
+             break;
+          default:
+             break;
+        }
+    }
+}
+
+uint32_t ContextBase::getCarrierCapabilities() {
+    #define carrierMSA (uint32_t)0x2
+    #define carrierMSB (uint32_t)0x1
+    #define gpsConfMSA (uint32_t)0x4
+    #define gpsConfMSB (uint32_t)0x2
+    uint32_t capabilities = mGps_conf.CAPABILITIES;
+    if ((mGps_conf.SUPL_MODE & carrierMSA) != carrierMSA) {
+        capabilities &= ~gpsConfMSA;
+    }
+    if ((mGps_conf.SUPL_MODE & carrierMSB) != carrierMSB) {
+        capabilities &= ~gpsConfMSB;
+    }
+
+    LOC_LOGV("getCarrierCapabilities: CAPABILITIES %x, SUPL_MODE %x, carrier capabilities %x",
+             mGps_conf.CAPABILITIES, mGps_conf.SUPL_MODE, capabilities);
+    return capabilities;
+}
+
+LBSProxyBase* ContextBase::getLBSProxy(const char* libName)
+{
+    LBSProxyBase* proxy = NULL;
+    LOC_LOGD("%s:%d]: getLBSProxy libname: %s\n", __func__, __LINE__, libName);
+    void* lib = dlopen(libName, RTLD_NOW);
+
+    if ((void*)NULL != lib) {
+        getLBSProxy_t* getter = (getLBSProxy_t*)dlsym(lib, "getLBSProxy");
+        if (NULL != getter) {
+            proxy = (*getter)();
+        }
+    }
+    else
+    {
+        LOC_LOGW("%s:%d]: FAILED TO LOAD libname: %s\n", __func__, __LINE__, libName);
+    }
+    if (NULL == proxy) {
+        proxy = new LBSProxyBase();
+    }
+    LOC_LOGD("%s:%d]: Exiting\n", __func__, __LINE__);
+    return proxy;
+}
+
+LocApiBase* ContextBase::createLocApi(LOC_API_ADAPTER_EVENT_MASK_T exMask)
+{
+    LocApiBase* locApi = NULL;
+    const char* libname = LOC_APIV2_0_LIB_NAME;
+
+    // Check the target
+    if (TARGET_NO_GNSS != loc_get_target()){
+
+        if (NULL == (locApi = mLBSProxy->getLocApi(exMask, this))) {
+            void *handle = NULL;
+
+            if (IS_SS5_HW_ENABLED == mGps_conf.GNSS_DEPLOYMENT) {
+                libname = SLL_LOC_API_LIB_NAME;
+            }
+
+            if ((handle = dlopen(libname, RTLD_NOW)) != NULL) {
+                LOC_LOGD("%s:%d]: %s is present", __func__, __LINE__, libname);
+                getLocApi_t* getter = (getLocApi_t*) dlsym(handle, "getLocApi");
+                if (getter != NULL) {
+                    LOC_LOGD("%s:%d]: getter is not NULL of %s", __func__,
+                            __LINE__, libname);
+                    locApi = (*getter)(exMask, this);
+                }
+            }
+            // only RPC is the option now
+            else {
+                LOC_LOGD("%s:%d]: libloc_api_v02.so is NOT present. Trying RPC",
+                        __func__, __LINE__);
+                handle = dlopen("libloc_api-rpc-qc.so", RTLD_NOW);
+                if (NULL != handle) {
+                    getLocApi_t* getter = (getLocApi_t*) dlsym(handle, "getLocApi");
+                    if (NULL != getter) {
+                        LOC_LOGD("%s:%d]: getter is not NULL in RPC", __func__,
+                                __LINE__);
+                        locApi = (*getter)(exMask, this);
+                    }
+                }
+            }
+        }
+    }
+
+    // locApi could still be NULL at this time
+    // we would then create a dummy one
+    if (NULL == locApi) {
+        locApi = new LocApiBase(exMask, this);
+    }
+
+    return locApi;
+}
+
+ContextBase::ContextBase(const MsgTask* msgTask,
+                         LOC_API_ADAPTER_EVENT_MASK_T exMask,
+                         const char* libName) :
+    mLBSProxy(getLBSProxy(libName)),
+    mMsgTask(msgTask),
+    mLocApi(createLocApi(exMask)),
+    mLocApiProxy(mLocApi->getLocApiProxy())
+{
+}
+
+void ContextBase::setEngineCapabilities(uint64_t supportedMsgMask,
+       uint8_t *featureList, bool gnssMeasurementSupported) {
+
+    if (ContextBase::sIsEngineCapabilitiesKnown == false) {
+        ContextBase::sSupportedMsgMask = supportedMsgMask;
+        ContextBase::sGnssMeasurementSupported = gnssMeasurementSupported;
+        if (featureList != NULL) {
+            memcpy((void *)ContextBase::sFeaturesSupported,
+                    (void *)featureList, sizeof(ContextBase::sFeaturesSupported));
+        }
+
+        /* */
+        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_MEASUREMENTS_CORRECTION)) {
+            static uint8_t isSapModeKnown = 0;
+
+            if (!isSapModeKnown) {
+                /* Check if SAP is PREMIUM_ENV_AIDING in izat.conf */
+                char conf_feature_sap[LOC_MAX_PARAM_STRING];
+                loc_param_s_type izat_conf_feature_table[] =
+                {
+                    { "SAP",           &conf_feature_sap,           &isSapModeKnown, 's' }
+                };
+                UTIL_READ_CONF(LOC_PATH_IZAT_CONF, izat_conf_feature_table);
+
+                /* Disable this feature if SAP is not PREMIUM_ENV_AIDING in izat.conf */
+                if (strcmp(conf_feature_sap, "PREMIUM_ENV_AIDING") != 0) {
+                    uint8_t arrayIndex = LOC_SUPPORTED_FEATURE_MEASUREMENTS_CORRECTION >> 3;
+                    uint8_t bitPos = LOC_SUPPORTED_FEATURE_MEASUREMENTS_CORRECTION & 7;
+
+                    if (arrayIndex < MAX_FEATURE_LENGTH) {
+                        /* To disable the feature we need to reset the bit on the "bitPos"
+                           position, so shift a "1" to the left by "bitPos" */
+                        ContextBase::sFeaturesSupported[arrayIndex] &= ~(1 << bitPos);
+                    }
+                }
+            }
+        }
+        ContextBase::sIsEngineCapabilitiesKnown = true;
+    }
+}
+
+
+bool ContextBase::isFeatureSupported(uint8_t featureVal)
+{
+    uint8_t arrayIndex = featureVal >> 3;
+    uint8_t bitPos = featureVal & 7;
+
+    if (arrayIndex >= MAX_FEATURE_LENGTH) return false;
+    return ((ContextBase::sFeaturesSupported[arrayIndex] >> bitPos ) & 0x1);
+}
+
+bool ContextBase::gnssConstellationConfig() {
+    return sGnssMeasurementSupported;
+}
+
+}
diff --git a/gps/core/ContextBase.h b/gps/core/ContextBase.h
new file mode 100644
index 0000000..34cad60
--- /dev/null
+++ b/gps/core/ContextBase.h
@@ -0,0 +1,385 @@
+/* Copyright (c) 2011-2017, 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __LOC_CONTEXT_BASE__
+#define __LOC_CONTEXT_BASE__
+
+#include <stdbool.h>
+#include <ctype.h>
+#include <MsgTask.h>
+#include <LocApiBase.h>
+#include <LBSProxyBase.h>
+#include <loc_cfg.h>
+#ifdef NO_UNORDERED_SET_OR_MAP
+    #include <map>
+#else
+    #include <unordered_map>
+#endif
+
+/* GPS.conf support */
+/* NOTE: the implementaiton of the parser casts number
+   fields to 32 bit. To ensure all 'n' fields working,
+   they must all be 32 bit fields. */
+typedef struct loc_gps_cfg_s
+{
+    uint32_t       INTERMEDIATE_POS;
+    uint32_t       ACCURACY_THRES;
+    uint32_t       SUPL_VER;
+    uint32_t       SUPL_MODE;
+    uint32_t       SUPL_ES;
+    uint32_t       CAPABILITIES;
+    uint32_t       LPP_PROFILE;
+    char           XTRA_SERVER_1[LOC_MAX_PARAM_STRING];
+    char           XTRA_SERVER_2[LOC_MAX_PARAM_STRING];
+    char           XTRA_SERVER_3[LOC_MAX_PARAM_STRING];
+    uint32_t       USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL;
+    uint32_t       NMEA_PROVIDER;
+    char           NMEA_REPORT_RATE[LOC_MAX_PARAM_NAME];
+    GnssConfigGpsLock   GPS_LOCK;
+    uint32_t       A_GLONASS_POS_PROTOCOL_SELECT;
+    uint32_t       AGPS_CERT_WRITABLE_MASK;
+    uint32_t       AGPS_CONFIG_INJECT;
+    uint32_t       LPPE_CP_TECHNOLOGY;
+    uint32_t       LPPE_UP_TECHNOLOGY;
+    uint32_t       EXTERNAL_DR_ENABLED;
+    char           SUPL_HOST[LOC_MAX_PARAM_STRING];
+    uint32_t       SUPL_PORT;
+    uint32_t       MODEM_TYPE;
+    char           MO_SUPL_HOST[LOC_MAX_PARAM_STRING];
+    uint32_t       MO_SUPL_PORT;
+    uint32_t       CONSTRAINED_TIME_UNCERTAINTY_ENABLED;
+    double         CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD;
+    uint32_t       CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET;
+    uint32_t       POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED;
+    char           PROXY_APP_PACKAGE_NAME[LOC_MAX_PARAM_STRING];
+    uint32_t       CP_MTLR_ES;
+    uint32_t       GNSS_DEPLOYMENT;
+    uint32_t       CUSTOM_NMEA_GGA_FIX_QUALITY_ENABLED;
+    uint32_t       NI_SUPL_DENY_ON_NFW_LOCKED;
+    uint32_t       ENABLE_NMEA_PRINT;
+    uint32_t       NMEA_TAG_BLOCK_GROUPING_ENABLED;
+} loc_gps_cfg_s_type;
+
+/* NOTE: the implementation of the parser casts number
+   fields to 32 bit. To ensure all 'n' fields working,
+   they must all be 32 bit fields. */
+/* Meanwhile, *_valid fields are 8 bit fields, and 'f'
+   fields are double. Rigid as they are, it is the
+   the status quo, until the parsing mechanism is
+   changed, that is. */
+typedef struct
+{
+    uint8_t        GYRO_BIAS_RANDOM_WALK_VALID;
+    double         GYRO_BIAS_RANDOM_WALK;
+    uint32_t       SENSOR_ACCEL_BATCHES_PER_SEC;
+    uint32_t       SENSOR_ACCEL_SAMPLES_PER_BATCH;
+    uint32_t       SENSOR_GYRO_BATCHES_PER_SEC;
+    uint32_t       SENSOR_GYRO_SAMPLES_PER_BATCH;
+    uint32_t       SENSOR_ACCEL_BATCHES_PER_SEC_HIGH;
+    uint32_t       SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH;
+    uint32_t       SENSOR_GYRO_BATCHES_PER_SEC_HIGH;
+    uint32_t       SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH;
+    uint32_t       SENSOR_CONTROL_MODE;
+    uint32_t       SENSOR_ALGORITHM_CONFIG_MASK;
+    uint8_t        ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID;
+    double         ACCEL_RANDOM_WALK_SPECTRAL_DENSITY;
+    uint8_t        ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID;
+    double         ANGLE_RANDOM_WALK_SPECTRAL_DENSITY;
+    uint8_t        RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID;
+    double         RATE_RANDOM_WALK_SPECTRAL_DENSITY;
+    uint8_t        VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID;
+    double         VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY;
+} loc_sap_cfg_s_type;
+
+using namespace loc_util;
+
+namespace loc_core {
+
+class LocAdapterBase;
+
+class ContextBase {
+    static LBSProxyBase* getLBSProxy(const char* libName);
+    LocApiBase* createLocApi(LOC_API_ADAPTER_EVENT_MASK_T excludedMask);
+    static const loc_param_s_type mGps_conf_table[];
+    static const loc_param_s_type mSap_conf_table[];
+protected:
+    const LBSProxyBase* mLBSProxy;
+    const MsgTask* mMsgTask;
+    LocApiBase* mLocApi;
+    LocApiProxyBase *mLocApiProxy;
+
+public:
+    ContextBase(const MsgTask* msgTask,
+                LOC_API_ADAPTER_EVENT_MASK_T exMask,
+                const char* libName);
+    inline virtual ~ContextBase() {
+        if (nullptr != mLocApi) {
+            mLocApi->destroy();
+            mLocApi = nullptr;
+        }
+        if (nullptr != mLBSProxy) {
+            delete mLBSProxy;
+            mLBSProxy = nullptr;
+        }
+    }
+
+    inline const MsgTask* getMsgTask() { return mMsgTask; }
+    inline LocApiBase* getLocApi() { return mLocApi; }
+    inline LocApiProxyBase* getLocApiProxy() { return mLocApiProxy; }
+    inline bool hasAgpsExtendedCapabilities() { return mLBSProxy->hasAgpsExtendedCapabilities(); }
+    inline bool hasNativeXtraClient() { return mLBSProxy->hasNativeXtraClient(); }
+    inline void modemPowerVote(bool power) const { return mLBSProxy->modemPowerVote(power); }
+    inline IzatDevId_t getIzatDevId() const {
+        return mLBSProxy->getIzatDevId();
+    }
+    inline void sendMsg(const LocMsg *msg) { getMsgTask()->sendMsg(msg); }
+
+    static loc_gps_cfg_s_type mGps_conf;
+    static loc_sap_cfg_s_type mSap_conf;
+    static bool sIsEngineCapabilitiesKnown;
+    static uint64_t sSupportedMsgMask;
+    static uint8_t sFeaturesSupported[MAX_FEATURE_LENGTH];
+    static bool sGnssMeasurementSupported;
+    static GnssNMEARptRate sNmeaReportRate;
+    static LocationCapabilitiesMask sQwesFeatureMask;
+
+    void readConfig();
+    static uint32_t getCarrierCapabilities();
+    void setEngineCapabilities(uint64_t supportedMsgMask,
+            uint8_t *featureList, bool gnssMeasurementSupported);
+
+    static inline bool isEngineCapabilitiesKnown() {
+        return sIsEngineCapabilitiesKnown;
+    }
+
+    static inline bool isMessageSupported(LocCheckingMessagesID msgID) {
+
+        // confirm if msgID is not larger than the number of bits in
+        // mSupportedMsg
+        if ((uint64_t)msgID > (sizeof(sSupportedMsgMask) << 3)) {
+            return false;
+        } else {
+            uint32_t messageChecker = 1 << msgID;
+            return (messageChecker & sSupportedMsgMask) == messageChecker;
+        }
+    }
+
+    /*
+        Check if a feature is supported
+    */
+    static bool isFeatureSupported(uint8_t featureVal);
+
+    /*
+        Check if gnss measurement is supported
+    */
+    static bool gnssConstellationConfig();
+
+    /*
+        set QWES feature status info
+    */
+    static inline void setQwesFeatureStatus(
+            const std::unordered_map<LocationQwesFeatureType, bool> &featureMap) {
+       std::unordered_map<LocationQwesFeatureType, bool>::const_iterator itr;
+       static LocationQwesFeatureType locQwesFeatType[LOCATION_QWES_FEATURE_TYPE_MAX];
+       for (itr = featureMap.begin(); itr != featureMap.end(); ++itr) {
+           LOC_LOGi("Feature : %d isValid: %d", itr->first, itr->second);
+           locQwesFeatType[itr->first] = itr->second;
+           switch (itr->first) {
+               case LOCATION_QWES_FEATURE_TYPE_CARRIER_PHASE:
+                   if (itr->second) {
+                       sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_CARRIER_PHASE_BIT;
+                   } else {
+                       sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_CARRIER_PHASE_BIT;
+                   }
+               break;
+               case LOCATION_QWES_FEATURE_TYPE_SV_POLYNOMIAL:
+                   if (itr->second) {
+                       sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_SV_POLYNOMIAL_BIT;
+                   } else {
+                       sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_SV_POLYNOMIAL_BIT;
+                   }
+               break;
+               case LOCATION_QWES_FEATURE_TYPE_GNSS_SINGLE_FREQUENCY:
+                   if (itr->second) {
+                       sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_GNSS_SINGLE_FREQUENCY;
+                   } else {
+                       sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_GNSS_SINGLE_FREQUENCY;
+                   }
+               break;
+               case LOCATION_QWES_FEATURE_TYPE_SV_EPH:
+                   if (itr->second) {
+                       sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_SV_EPHEMERIS_BIT;
+                   } else {
+                       sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_SV_EPHEMERIS_BIT;
+                   }
+               break;
+               case LOCATION_QWES_FEATURE_TYPE_GNSS_MULTI_FREQUENCY:
+                   if (itr->second) {
+                       sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_GNSS_MULTI_FREQUENCY;
+                   } else {
+                       sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_GNSS_MULTI_FREQUENCY;
+                   }
+               break;
+               case LOCATION_QWES_FEATURE_TYPE_PPE:
+                   if (itr->second) {
+                       sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_PPE;
+                   } else {
+                       sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_PPE;
+                   }
+               break;
+               case LOCATION_QWES_FEATURE_TYPE_QDR2:
+                   if (itr->second) {
+                       sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_QDR2;
+                   } else {
+                       sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_QDR2;
+                   }
+               break;
+               case LOCATION_QWES_FEATURE_TYPE_QDR3:
+                   if (itr->second) {
+                       sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_QDR3;
+                   } else {
+                       sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_QDR3;
+                   }
+               break;
+               case LOCATION_QWES_FEATURE_TYPE_VPE:
+                   if (itr->second) {
+                       sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_VPE;
+                   } else {
+                       sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_VPE;
+                   }
+               break;
+           }
+       }
+
+       // Set CV2X basic when time freq and tunc is set
+       // CV2X_BASIC  = LOCATION_QWES_FEATURE_TYPE_TIME_FREQUENCY &
+       //       LOCATION_QWES_FEATURE_TYPE_TIME_UNCERTAINTY
+
+       // Set CV2X premium when time freq and tunc is set
+       // CV2X_PREMIUM = CV2X_BASIC & LOCATION_QWES_FEATURE_TYPE_QDR3 &
+       //       LOCATION_QWES_FEATURE_TYPE_CLOCK_ESTIMATE
+
+       bool cv2xBasicEnabled = (1 == locQwesFeatType[LOCATION_QWES_FEATURE_TYPE_TIME_FREQUENCY]) &&
+            (1 == locQwesFeatType[LOCATION_QWES_FEATURE_TYPE_TIME_UNCERTAINTY]);
+       bool cv2xPremiumEnabled = cv2xBasicEnabled &&
+            (1 == locQwesFeatType[LOCATION_QWES_FEATURE_TYPE_QDR3]) &&
+            (1 == locQwesFeatType[LOCATION_QWES_FEATURE_TYPE_CLOCK_ESTIMATE]);
+
+       LOC_LOGd("CV2X_BASIC:%d, CV2X_PREMIUM:%d", cv2xBasicEnabled, cv2xPremiumEnabled);
+       if (cv2xBasicEnabled) {
+            sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_CV2X_LOCATION_BASIC;
+       } else {
+            sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_CV2X_LOCATION_BASIC;
+       }
+       if (cv2xPremiumEnabled) {
+            sQwesFeatureMask |= LOCATION_CAPABILITIES_QWES_CV2X_LOCATION_PREMIUM;
+       } else {
+            sQwesFeatureMask &= ~LOCATION_CAPABILITIES_QWES_CV2X_LOCATION_PREMIUM;
+       }
+    }
+
+    /*
+        get QWES feature status info
+    */
+    static inline LocationCapabilitiesMask getQwesFeatureStatus() {
+        return (ContextBase::sQwesFeatureMask);
+    }
+
+
+};
+
+struct LocApiResponse: LocMsg {
+    private:
+        ContextBase& mContext;
+        std::function<void (LocationError err)> mProcImpl;
+        inline virtual void proc() const {
+            mProcImpl(mLocationError);
+        }
+    protected:
+        LocationError mLocationError;
+    public:
+        inline LocApiResponse(ContextBase& context,
+                              std::function<void (LocationError err)> procImpl ) :
+                              mContext(context), mProcImpl(procImpl) {}
+
+        void returnToSender(const LocationError err) {
+            mLocationError = err;
+            mContext.sendMsg(this);
+        }
+};
+
+struct LocApiCollectiveResponse: LocMsg {
+    private:
+        ContextBase& mContext;
+        std::function<void (std::vector<LocationError> errs)> mProcImpl;
+        inline virtual void proc() const {
+            mProcImpl(mLocationErrors);
+        }
+    protected:
+        std::vector<LocationError> mLocationErrors;
+    public:
+        inline LocApiCollectiveResponse(ContextBase& context,
+                              std::function<void (std::vector<LocationError> errs)> procImpl ) :
+                              mContext(context), mProcImpl(procImpl) {}
+        inline virtual ~LocApiCollectiveResponse() {
+        }
+
+        void returnToSender(std::vector<LocationError>& errs) {
+            mLocationErrors = errs;
+            mContext.sendMsg(this);
+        }
+};
+
+
+template <typename DATA>
+struct LocApiResponseData: LocMsg {
+    private:
+        ContextBase& mContext;
+        std::function<void (LocationError err, DATA data)> mProcImpl;
+        inline virtual void proc() const {
+            mProcImpl(mLocationError, mData);
+        }
+    protected:
+        LocationError mLocationError;
+        DATA mData;
+    public:
+        inline LocApiResponseData(ContextBase& context,
+                              std::function<void (LocationError err, DATA data)> procImpl ) :
+                              mContext(context), mProcImpl(procImpl) {}
+
+        void returnToSender(const LocationError err, const DATA data) {
+            mLocationError = err;
+            mData = data;
+            mContext.sendMsg(this);
+        }
+};
+
+
+} // namespace loc_core
+
+#endif //__LOC_CONTEXT_BASE__
diff --git a/gps/core/EngineHubProxyBase.h b/gps/core/EngineHubProxyBase.h
new file mode 100644
index 0000000..468a8f0
--- /dev/null
+++ b/gps/core/EngineHubProxyBase.h
@@ -0,0 +1,160 @@
+/* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef ENGINE_HUB_PROXY_BASE_H
+#define ENGINE_HUB_PROXY_BASE_H
+#ifdef NO_UNORDERED_SET_OR_MAP
+    #include <map>
+#else
+    #include <unordered_map>
+#endif
+
+namespace loc_core {
+
+using namespace loc_util;
+
+class EngineHubProxyBase {
+public:
+    inline EngineHubProxyBase() {
+    }
+    inline virtual ~EngineHubProxyBase() {}
+
+    // gnss session related functions
+    inline virtual bool gnssStartFix() {
+        return false;
+    }
+
+    inline virtual bool gnssStopFix() {
+        return false;
+    }
+
+    inline virtual bool gnssSetFixMode(const LocPosMode &params) {
+        (void) params;
+        return false;
+    }
+
+    inline virtual bool gnssDeleteAidingData(const GnssAidingData &aidingData) {
+        (void) aidingData;
+        return false;
+    }
+
+    // GNSS reports
+    inline virtual bool gnssReportPosition(const UlpLocation &location,
+                                           const GpsLocationExtended &locationExtended,
+                                           enum loc_sess_status status) {
+        (void) location;
+        (void) locationExtended;
+        (void) status;
+        return false;
+    }
+
+    inline virtual bool gnssReportSv(const GnssSvNotification& svNotify) {
+        (void) svNotify;
+        return false;
+    }
+
+    inline virtual bool gnssReportSvMeasurement(const GnssSvMeasurementSet& svMeasurementSet) {
+        (void) svMeasurementSet;
+        return false;
+    }
+
+    inline virtual bool gnssReportSvPolynomial(const GnssSvPolynomial& svPolynomial) {
+        (void) svPolynomial;
+        return false;
+    }
+
+    inline virtual bool gnssReportSvEphemeris(const GnssSvEphemerisReport& svEphemeris) {
+        (void) svEphemeris;
+        return false;
+    }
+
+    inline virtual bool gnssReportSystemInfo(const LocationSystemInfo& systemInfo) {
+        (void) systemInfo;
+        return false;
+    }
+
+    inline virtual bool gnssReportKlobucharIonoModel(const GnssKlobucharIonoModel& ionoModel) {
+        (void) ionoModel;
+        return false;
+    }
+
+    inline virtual bool gnssReportAdditionalSystemInfo(
+            const GnssAdditionalSystemInfo& additionalSystemInfo) {
+        (void) additionalSystemInfo;
+        return false;
+    }
+
+    inline virtual bool configLeverArm(const LeverArmConfigInfo& configInfo) {
+        (void) configInfo;
+        return false;
+    }
+
+    inline virtual bool configDeadReckoningEngineParams(
+            const DeadReckoningEngineConfig& dreConfig) {
+        (void) dreConfig;
+        return false;
+    }
+
+    inline virtual bool configEngineRunState(
+            PositioningEngineMask engType, LocEngineRunState engState) {
+        (void) engType;
+        (void) engState;
+        return false;
+    }
+};
+
+typedef std::function<void(int count, EngineLocationInfo* locationArr)>
+        GnssAdapterReportEnginePositionsEventCb;
+
+typedef std::function<void(const GnssSvNotification& svNotify,
+                           bool fromEngineHub)>
+        GnssAdapterReportSvEventCb;
+
+typedef std::function<void(const GnssAidingDataSvMask& svDataMask)>
+        GnssAdapterReqAidingDataCb;
+
+typedef std::function<void(bool nHzNeeded, bool nHzMeasNeeded)>
+        GnssAdapterUpdateNHzRequirementCb;
+
+typedef std::function<void(const std::unordered_map<LocationQwesFeatureType, bool> &featureMap)>
+        GnssAdapterUpdateQwesFeatureStatusCb;
+
+// potential parameters: message queue: MsgTask * msgTask;
+// callback function to report back dr and ppe position and sv report
+typedef EngineHubProxyBase* (getEngHubProxyFn)(
+        const MsgTask * msgTask,
+        IOsObserver* osObserver,
+        GnssAdapterReportEnginePositionsEventCb positionEventCb,
+        GnssAdapterReportSvEventCb svEventCb,
+        GnssAdapterReqAidingDataCb reqAidingDataCb,
+        GnssAdapterUpdateNHzRequirementCb updateNHzRequirementCb,
+        GnssAdapterUpdateQwesFeatureStatusCb updateQwesFeatureStatusCb);
+
+} // namespace loc_core
+
+#endif // ENGINE_HUB_PROXY_BASE_H
diff --git a/gps/core/LBSProxyBase.h b/gps/core/LBSProxyBase.h
new file mode 100644
index 0000000..564c60b
--- /dev/null
+++ b/gps/core/LBSProxyBase.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef IZAT_PROXY_BASE_H
+#define IZAT_PROXY_BASE_H
+#include <gps_extended.h>
+
+namespace loc_core {
+
+class LocApiBase;
+class LocAdapterBase;
+class ContextBase;
+
+class LBSProxyBase {
+    friend class ContextBase;
+    inline virtual LocApiBase*
+        getLocApi(LOC_API_ADAPTER_EVENT_MASK_T exMask,
+                  ContextBase* context) const {
+
+        (void)exMask;
+        (void)context;
+        return NULL;
+    }
+protected:
+    inline LBSProxyBase() {}
+public:
+    inline virtual ~LBSProxyBase() {}
+    inline virtual bool hasAgpsExtendedCapabilities() const { return false; }
+    inline virtual void modemPowerVote(bool power) const {
+
+        (void)power;
+    }
+    virtual void injectFeatureConfig(ContextBase* context) const {
+
+        (void)context;
+    }
+    inline virtual bool hasNativeXtraClient() const { return false; }
+    inline virtual IzatDevId_t getIzatDevId() const { return 0; }
+};
+
+typedef LBSProxyBase* (getLBSProxy_t)();
+
+} // namespace loc_core
+
+#endif // IZAT_PROXY_BASE_H
diff --git a/gps/core/LocAdapterBase.cpp b/gps/core/LocAdapterBase.cpp
new file mode 100644
index 0000000..95f2728
--- /dev/null
+++ b/gps/core/LocAdapterBase.cpp
@@ -0,0 +1,439 @@
+/* Copyright (c) 2011-2014, 2016-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_LocAdapterBase"
+
+#include <dlfcn.h>
+#include <LocAdapterBase.h>
+#include <loc_target.h>
+#include <log_util.h>
+#include <LocAdapterProxyBase.h>
+
+namespace loc_core {
+
+// This is the top level class, so the constructor will
+// always gets called. Here we prepare for the default.
+// But if getLocApi(targetEnumType target) is overriden,
+// the right locApi should get created.
+LocAdapterBase::LocAdapterBase(const LOC_API_ADAPTER_EVENT_MASK_T mask,
+                               ContextBase* context, bool isMaster,
+                               LocAdapterProxyBase *adapterProxyBase,
+                               bool waitForDoneInit) :
+    mIsMaster(isMaster), mEvtMask(mask), mContext(context),
+    mLocApi(context->getLocApi()), mLocAdapterProxyBase(adapterProxyBase),
+    mMsgTask(context->getMsgTask()),
+    mIsEngineCapabilitiesKnown(ContextBase::sIsEngineCapabilitiesKnown)
+{
+    LOC_LOGd("waitForDoneInit: %d", waitForDoneInit);
+    if (!waitForDoneInit) {
+        mLocApi->addAdapter(this);
+        mAdapterAdded = true;
+    } else {
+        mAdapterAdded = false;
+    }
+}
+
+uint32_t LocAdapterBase::mSessionIdCounter(1);
+
+uint32_t LocAdapterBase::generateSessionId()
+{
+    if (++mSessionIdCounter == 0xFFFFFFFF)
+        mSessionIdCounter = 1;
+
+     return mSessionIdCounter;
+}
+
+void LocAdapterBase::handleEngineUpEvent()
+{
+    if (mLocAdapterProxyBase) {
+        mLocAdapterProxyBase->handleEngineUpEvent();
+    }
+}
+
+void LocAdapterBase::handleEngineDownEvent()
+{
+    if (mLocAdapterProxyBase) {
+        mLocAdapterProxyBase->handleEngineDownEvent();
+    }
+}
+
+void LocAdapterBase::
+    reportPositionEvent(const UlpLocation& location,
+                        const GpsLocationExtended& locationExtended,
+                        enum loc_sess_status status,
+                        LocPosTechMask loc_technology_mask,
+                        GnssDataNotification* pDataNotify,
+                        int msInWeek)
+{
+    if (mLocAdapterProxyBase != NULL) {
+        mLocAdapterProxyBase->reportPositionEvent((UlpLocation&)location,
+                                                   (GpsLocationExtended&)locationExtended,
+                                                   status,
+                                                   loc_technology_mask);
+    } else {
+        DEFAULT_IMPL()
+    }
+}
+
+void LocAdapterBase::
+    reportSvEvent(const GnssSvNotification& /*svNotify*/,
+                  bool /*fromEngineHub*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::
+    reportSvPolynomialEvent(GnssSvPolynomial &/*svPolynomial*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::
+    reportSvEphemerisEvent(GnssSvEphemerisReport &/*svEphemeris*/)
+DEFAULT_IMPL()
+
+
+void LocAdapterBase::
+    reportStatus(LocGpsStatusValue /*status*/)
+DEFAULT_IMPL()
+
+
+void LocAdapterBase::
+    reportNmeaEvent(const char* /*nmea*/, size_t /*length*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::
+    reportDataEvent(const GnssDataNotification& /*dataNotify*/,
+                    int /*msInWeek*/)
+DEFAULT_IMPL()
+
+bool LocAdapterBase::
+    reportXtraServer(const char* /*url1*/, const char* /*url2*/,
+                     const char* /*url3*/, const int /*maxlength*/)
+DEFAULT_IMPL(false)
+
+void LocAdapterBase::
+    reportLocationSystemInfoEvent(const LocationSystemInfo& /*locationSystemInfo*/)
+DEFAULT_IMPL()
+
+bool LocAdapterBase::
+    requestXtraData()
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    requestTime()
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    requestLocation()
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    requestATL(int /*connHandle*/, LocAGpsType /*agps_type*/,
+               LocApnTypeMask /*apn_type_mask*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    releaseATL(int /*connHandle*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    requestNiNotifyEvent(const GnssNiNotification &/*notify*/,
+                         const void* /*data*/,
+                         const LocInEmergency emergencyState)
+DEFAULT_IMPL(false)
+
+void LocAdapterBase::
+reportGnssMeasurementsEvent(const GnssMeasurements& /*gnssMeasurements*/,
+                                   int /*msInWeek*/)
+DEFAULT_IMPL()
+
+bool LocAdapterBase::
+    reportWwanZppFix(LocGpsLocation &/*zppLoc*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    reportZppBestAvailableFix(LocGpsLocation& /*zppLoc*/,
+            GpsLocationExtended& /*location_extended*/, LocPosTechMask /*tech_mask*/)
+DEFAULT_IMPL(false)
+
+void LocAdapterBase::reportGnssSvIdConfigEvent(const GnssSvIdConfig& /*config*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& /*config*/)
+DEFAULT_IMPL()
+
+void LocAdapterBase::reportGnssConfigEvent(uint32_t,  /* session id*/
+            const GnssConfig& /*gnssConfig*/)
+DEFAULT_IMPL()
+
+bool LocAdapterBase::
+    requestOdcpiEvent(OdcpiRequestInfo& /*request*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    reportGnssEngEnergyConsumedEvent(uint64_t /*energyConsumedSinceFirstBoot*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    reportDeleteAidingDataEvent(GnssAidingData & /*aidingData*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    reportKlobucharIonoModelEvent(GnssKlobucharIonoModel& /*ionoModel*/)
+DEFAULT_IMPL(false)
+
+bool LocAdapterBase::
+    reportGnssAdditionalSystemInfoEvent(GnssAdditionalSystemInfo& /*additionalSystemInfo*/)
+DEFAULT_IMPL(false)
+
+void LocAdapterBase::
+    reportNfwNotificationEvent(GnssNfwNotification& /*notification*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::geofenceBreachEvent(size_t /*count*/, uint32_t* /*hwIds*/, Location& /*location*/,
+                                    GeofenceBreachType /*breachType*/, uint64_t /*timestamp*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::geofenceStatusEvent(GeofenceStatusAvailable /*available*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::reportLocationsEvent(const Location* /*locations*/, size_t /*count*/,
+                                     BatchingMode /*batchingMode*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::reportCompletedTripsEvent(uint32_t /*accumulated_distance*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::reportBatchStatusChangeEvent(BatchingStatus /*batchStatus*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::reportPositionEvent(UlpLocation& /*location*/,
+                                    GpsLocationExtended& /*locationExtended*/,
+                                    enum loc_sess_status /*status*/,
+                                    LocPosTechMask /*loc_technology_mask*/)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::saveClient(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+    mClientData[client] = callbacks;
+    updateClientsEventMask();
+}
+
+void
+LocAdapterBase::eraseClient(LocationAPI* client)
+{
+    auto it = mClientData.find(client);
+    if (it != mClientData.end()) {
+        mClientData.erase(it);
+    }
+    updateClientsEventMask();
+}
+
+LocationCallbacks
+LocAdapterBase::getClientCallbacks(LocationAPI* client)
+{
+    LocationCallbacks callbacks = {};
+    auto it = mClientData.find(client);
+    if (it != mClientData.end()) {
+        callbacks = it->second;
+    }
+    return callbacks;
+}
+
+LocationCapabilitiesMask
+LocAdapterBase::getCapabilities()
+{
+    LocationCapabilitiesMask mask = 0;
+
+    if (isEngineCapabilitiesKnown()) {
+        // time based tracking always supported
+        mask |= LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT;
+        if (ContextBase::isMessageSupported(
+                LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING)){
+            mask |= LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT |
+                    LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT;
+        }
+        if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) {
+            mask |= LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT;
+        }
+        if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_OUTDOOR_TRIP_BATCHING)) {
+            mask |= LOCATION_CAPABILITIES_OUTDOOR_TRIP_BATCHING_BIT;
+        }
+        // geofence always supported
+        mask |= LOCATION_CAPABILITIES_GEOFENCE_BIT;
+        if (ContextBase::gnssConstellationConfig()) {
+            mask |= LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT;
+        }
+        uint32_t carrierCapabilities = ContextBase::getCarrierCapabilities();
+        if (carrierCapabilities & LOC_GPS_CAPABILITY_MSB) {
+            mask |= LOCATION_CAPABILITIES_GNSS_MSB_BIT;
+        }
+        if (LOC_GPS_CAPABILITY_MSA & carrierCapabilities) {
+            mask |= LOCATION_CAPABILITIES_GNSS_MSA_BIT;
+        }
+        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) {
+            mask |= LOCATION_CAPABILITIES_DEBUG_NMEA_BIT;
+        }
+        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+            mask |= LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT;
+        }
+        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_AGPM_V02)) {
+            mask |= LOCATION_CAPABILITIES_AGPM_BIT;
+        }
+        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_LOCATION_PRIVACY)) {
+            mask |= LOCATION_CAPABILITIES_PRIVACY_BIT;
+        }
+        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_MEASUREMENTS_CORRECTION)) {
+            mask |= LOCATION_CAPABILITIES_MEASUREMENTS_CORRECTION_BIT;
+        }
+        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_ROBUST_LOCATION)) {
+            mask |= LOCATION_CAPABILITIES_CONFORMITY_INDEX_BIT;
+        }
+        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_EDGNSS)) {
+            mask |= LOCATION_CAPABILITIES_EDGNSS_BIT;
+        }
+    } else {
+        LOC_LOGE("%s]: attempt to get capabilities before they are known.", __func__);
+    }
+
+    return mask;
+}
+
+void
+LocAdapterBase::broadcastCapabilities(LocationCapabilitiesMask mask)
+{
+    for (auto clientData : mClientData) {
+        if (nullptr != clientData.second.capabilitiesCb) {
+            clientData.second.capabilitiesCb(mask);
+        }
+    }
+}
+
+void
+LocAdapterBase::updateClientsEventMask()
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::stopClientSessions(LocationAPI* client)
+DEFAULT_IMPL()
+
+void
+LocAdapterBase::addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+    LOC_LOGD("%s]: client %p", __func__, client);
+
+    struct MsgAddClient : public LocMsg {
+        LocAdapterBase& mAdapter;
+        LocationAPI* mClient;
+        const LocationCallbacks mCallbacks;
+        inline MsgAddClient(LocAdapterBase& adapter,
+                            LocationAPI* client,
+                            const LocationCallbacks& callbacks) :
+            LocMsg(),
+            mAdapter(adapter),
+            mClient(client),
+            mCallbacks(callbacks) {}
+        inline virtual void proc() const {
+            mAdapter.saveClient(mClient, mCallbacks);
+        }
+    };
+
+    sendMsg(new MsgAddClient(*this, client, callbacks));
+}
+
+void
+LocAdapterBase::removeClientCommand(LocationAPI* client,
+                                removeClientCompleteCallback rmClientCb)
+{
+    LOC_LOGD("%s]: client %p", __func__, client);
+
+    struct MsgRemoveClient : public LocMsg {
+        LocAdapterBase& mAdapter;
+        LocationAPI* mClient;
+        removeClientCompleteCallback mRmClientCb;
+        inline MsgRemoveClient(LocAdapterBase& adapter,
+                               LocationAPI* client,
+                               removeClientCompleteCallback rmCb) :
+            LocMsg(),
+            mAdapter(adapter),
+            mClient(client),
+            mRmClientCb(rmCb){}
+        inline virtual void proc() const {
+            mAdapter.stopClientSessions(mClient);
+            mAdapter.eraseClient(mClient);
+            if (nullptr != mRmClientCb) {
+                (mRmClientCb)(mClient);
+            }
+        }
+    };
+
+    sendMsg(new MsgRemoveClient(*this, client, rmClientCb));
+}
+
+void
+LocAdapterBase::requestCapabilitiesCommand(LocationAPI* client)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    struct MsgRequestCapabilities : public LocMsg {
+        LocAdapterBase& mAdapter;
+        LocationAPI* mClient;
+        inline MsgRequestCapabilities(LocAdapterBase& adapter,
+                                      LocationAPI* client) :
+            LocMsg(),
+            mAdapter(adapter),
+            mClient(client) {}
+        inline virtual void proc() const {
+            if (!mAdapter.isEngineCapabilitiesKnown()) {
+                mAdapter.mPendingMsgs.push_back(new MsgRequestCapabilities(*this));
+                return;
+            }
+            LocationCallbacks callbacks = mAdapter.getClientCallbacks(mClient);
+            if (callbacks.capabilitiesCb != nullptr) {
+                callbacks.capabilitiesCb(mAdapter.getCapabilities());
+            }
+        }
+    };
+
+    sendMsg(new MsgRequestCapabilities(*this, client));
+}
+
+void
+LocAdapterBase::reportLatencyInfoEvent(const GnssLatencyInfo& /*gnssLatencyInfo*/)
+DEFAULT_IMPL()
+
+bool LocAdapterBase::
+    reportQwesCapabilities(const std::unordered_map<LocationQwesFeatureType, bool> &featureMap)
+DEFAULT_IMPL(false)
+
+} // namespace loc_core
diff --git a/gps/core/LocAdapterBase.h b/gps/core/LocAdapterBase.h
new file mode 100644
index 0000000..51b2306
--- /dev/null
+++ b/gps/core/LocAdapterBase.h
@@ -0,0 +1,246 @@
+/* Copyright (c) 2011-2014, 2016-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef LOC_API_ADAPTER_BASE_H
+#define LOC_API_ADAPTER_BASE_H
+
+#include <gps_extended.h>
+#include <ContextBase.h>
+#include <LocationAPI.h>
+#include <map>
+
+#define MIN_TRACKING_INTERVAL (100) // 100 msec
+
+typedef struct LocationSessionKey {
+    LocationAPI* client;
+    uint32_t id;
+    inline LocationSessionKey(LocationAPI* _client, uint32_t _id) :
+        client(_client), id(_id) {}
+} LocationSessionKey;
+inline bool operator <(LocationSessionKey const& left, LocationSessionKey const& right) {
+    return left.id < right.id || (left.id == right.id && left.client < right.client);
+}
+inline bool operator ==(LocationSessionKey const& left, LocationSessionKey const& right) {
+    return left.id == right.id && left.client == right.client;
+}
+inline bool operator !=(LocationSessionKey const& left, LocationSessionKey const& right) {
+    return left.id != right.id || left.client != right.client;
+}
+
+typedef void (*removeClientCompleteCallback)(LocationAPI* client);
+
+namespace loc_core {
+
+class LocAdapterProxyBase;
+
+class LocAdapterBase {
+private:
+    static uint32_t mSessionIdCounter;
+    const bool mIsMaster;
+    bool mIsEngineCapabilitiesKnown = false;
+
+protected:
+    LOC_API_ADAPTER_EVENT_MASK_T mEvtMask;
+    ContextBase* mContext;
+    LocApiBase* mLocApi;
+    LocAdapterProxyBase* mLocAdapterProxyBase;
+    const MsgTask* mMsgTask;
+    bool mAdapterAdded;
+
+    inline LocAdapterBase(const MsgTask* msgTask) :
+        mIsMaster(false), mEvtMask(0), mContext(NULL), mLocApi(NULL),
+        mLocAdapterProxyBase(NULL), mMsgTask(msgTask), mAdapterAdded(false) {}
+
+    /* ==== CLIENT ========================================================================= */
+    typedef std::map<LocationAPI*, LocationCallbacks> ClientDataMap;
+    ClientDataMap mClientData;
+    std::vector<LocMsg*> mPendingMsgs; // For temporal storage of msgs before Open is completed
+    /* ======== UTILITIES ================================================================== */
+    void saveClient(LocationAPI* client, const LocationCallbacks& callbacks);
+    void eraseClient(LocationAPI* client);
+    LocationCallbacks getClientCallbacks(LocationAPI* client);
+    LocationCapabilitiesMask getCapabilities();
+    void broadcastCapabilities(LocationCapabilitiesMask mask);
+    virtual void updateClientsEventMask();
+    virtual void stopClientSessions(LocationAPI* client);
+
+public:
+    inline virtual ~LocAdapterBase() { mLocApi->removeAdapter(this); }
+    // When waitForDoneInit is not specified or specified as false,
+    // handleEngineUpEvent may be called on the child adapter object from
+    // a different thread before the constructor of the child
+    // object finishes.
+    //
+    // If the handleEngineUpEvent relies on member variables of the constructor
+    // of the child adapter to be initialized first, we need to specify the
+    // waitForDoneInit to *TRUE* to delay handleEngineUpEvent to get called
+    // until when the child adapter finishes its initialization and notify
+    // LocAdapterBase via doneInit method.
+    LocAdapterBase(const LOC_API_ADAPTER_EVENT_MASK_T mask,
+                   ContextBase* context, bool isMaster = false,
+                   LocAdapterProxyBase *adapterProxyBase = NULL,
+                   bool waitForDoneInit = false);
+
+    inline void doneInit() {
+        if (!mAdapterAdded) {
+            mLocApi->addAdapter(this);
+            mAdapterAdded = true;
+        }
+    }
+
+    inline LOC_API_ADAPTER_EVENT_MASK_T
+        checkMask(LOC_API_ADAPTER_EVENT_MASK_T mask) const {
+        return mEvtMask & mask;
+    }
+
+    inline LOC_API_ADAPTER_EVENT_MASK_T getEvtMask() const {
+        return mEvtMask;
+    }
+
+    inline void sendMsg(const LocMsg* msg) const {
+        mMsgTask->sendMsg(msg);
+    }
+
+    inline void sendMsg(const LocMsg* msg) {
+        mMsgTask->sendMsg(msg);
+    }
+
+    inline void updateEvtMask(LOC_API_ADAPTER_EVENT_MASK_T event,
+                              loc_registration_mask_status status)
+    {
+        switch(status) {
+            case (LOC_REGISTRATION_MASK_ENABLED):
+                mEvtMask = mEvtMask | event;
+                break;
+            case (LOC_REGISTRATION_MASK_DISABLED):
+                mEvtMask = mEvtMask &~ event;
+                break;
+            case (LOC_REGISTRATION_MASK_SET):
+                mEvtMask = event;
+                break;
+        }
+        mLocApi->updateEvtMask();
+    }
+
+    inline void updateNmeaMask(uint32_t mask)
+    {
+        mLocApi->updateNmeaMask(mask);
+    }
+
+    inline bool isFeatureSupported(uint8_t featureVal) {
+        return ContextBase::isFeatureSupported(featureVal);
+    }
+
+    static uint32_t generateSessionId();
+
+    inline bool isAdapterMaster() {
+        return mIsMaster;
+    }
+
+    inline bool isEngineCapabilitiesKnown() { return mIsEngineCapabilitiesKnown;}
+    inline void setEngineCapabilitiesKnown(bool value) { mIsEngineCapabilitiesKnown = value;}
+
+    virtual void handleEngineUpEvent();
+    virtual void handleEngineDownEvent();
+    virtual void reportPositionEvent(const UlpLocation& location,
+                                     const GpsLocationExtended& locationExtended,
+                                     enum loc_sess_status status,
+                                     LocPosTechMask loc_technology_mask,
+                                     GnssDataNotification* pDataNotify = nullptr,
+                                     int msInWeek = -1);
+    virtual void reportEnginePositionsEvent(unsigned int count,
+                                            EngineLocationInfo* locationArr) {
+        (void)count;
+        (void)locationArr;
+    }
+    virtual void reportSvEvent(const GnssSvNotification& svNotify,
+                               bool fromEngineHub=false);
+    virtual void reportDataEvent(const GnssDataNotification& dataNotify, int msInWeek);
+    virtual void reportNmeaEvent(const char* nmea, size_t length);
+    virtual void reportSvPolynomialEvent(GnssSvPolynomial &svPolynomial);
+    virtual void reportSvEphemerisEvent(GnssSvEphemerisReport &svEphemeris);
+    virtual void reportStatus(LocGpsStatusValue status);
+    virtual bool reportXtraServer(const char* url1, const char* url2,
+                                  const char* url3, const int maxlength);
+    virtual void reportLocationSystemInfoEvent(const LocationSystemInfo& locationSystemInfo);
+
+    virtual bool requestXtraData();
+    virtual bool requestTime();
+    virtual bool requestLocation();
+    virtual bool requestATL(int connHandle, LocAGpsType agps_type,
+                            LocApnTypeMask apn_type_mask);
+    virtual bool releaseATL(int connHandle);
+    virtual bool requestNiNotifyEvent(const GnssNiNotification &notify, const void* data,
+                                      const LocInEmergency emergencyState);
+    inline virtual bool isInSession() { return false; }
+    ContextBase* getContext() const { return mContext; }
+    virtual void reportGnssMeasurementsEvent(const GnssMeasurements& gnssMeasurements,
+                                                int msInWeek);
+    virtual bool reportWwanZppFix(LocGpsLocation &zppLoc);
+    virtual bool reportZppBestAvailableFix(LocGpsLocation &zppLoc,
+            GpsLocationExtended &location_extended, LocPosTechMask tech_mask);
+    virtual void reportGnssSvIdConfigEvent(const GnssSvIdConfig& config);
+    virtual void reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config);
+    virtual void reportGnssConfigEvent(uint32_t sessionId, const GnssConfig& gnssConfig);
+    virtual bool requestOdcpiEvent(OdcpiRequestInfo& request);
+    virtual bool reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot);
+    virtual bool reportDeleteAidingDataEvent(GnssAidingData &aidingData);
+    virtual bool reportKlobucharIonoModelEvent(GnssKlobucharIonoModel& ionoModel);
+    virtual bool reportGnssAdditionalSystemInfoEvent(
+            GnssAdditionalSystemInfo& additionalSystemInfo);
+    virtual void reportNfwNotificationEvent(GnssNfwNotification& notification);
+
+    virtual void geofenceBreachEvent(size_t count, uint32_t* hwIds, Location& location,
+                                     GeofenceBreachType breachType, uint64_t timestamp);
+    virtual void geofenceStatusEvent(GeofenceStatusAvailable available);
+
+    virtual void reportPositionEvent(UlpLocation &location,
+                                     GpsLocationExtended &locationExtended,
+                                     enum loc_sess_status status,
+                                     LocPosTechMask loc_technology_mask);
+
+    virtual void reportLocationsEvent(const Location* locations, size_t count,
+            BatchingMode batchingMode);
+    virtual void reportCompletedTripsEvent(uint32_t accumulated_distance);
+    virtual void reportBatchStatusChangeEvent(BatchingStatus batchStatus);
+
+    /* ==== CLIENT ========================================================================= */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    void addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks);
+    void removeClientCommand(LocationAPI* client,
+                             removeClientCompleteCallback rmClientCb);
+    void requestCapabilitiesCommand(LocationAPI* client);
+
+    virtual void reportLatencyInfoEvent(const GnssLatencyInfo& gnssLatencyInfo);
+    virtual bool reportQwesCapabilities(
+            const std::unordered_map<LocationQwesFeatureType, bool> &featureMap);
+};
+
+} // namespace loc_core
+
+#endif //LOC_API_ADAPTER_BASE_H
diff --git a/gps/core/LocAdapterProxyBase.h b/gps/core/LocAdapterProxyBase.h
new file mode 100644
index 0000000..727d424
--- /dev/null
+++ b/gps/core/LocAdapterProxyBase.h
@@ -0,0 +1,77 @@
+/* Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOC_ADAPTER_PROXY_BASE_H
+#define LOC_ADAPTER_PROXY_BASE_H
+
+#include <ContextBase.h>
+#include <gps_extended.h>
+
+namespace loc_core {
+
+class LocAdapterProxyBase {
+private:
+    LocAdapterBase *mLocAdapterBase;
+protected:
+    inline LocAdapterProxyBase(const LOC_API_ADAPTER_EVENT_MASK_T mask,
+                               ContextBase* context, bool isMaster = false):
+            mLocAdapterBase(new LocAdapterBase(mask, context, isMaster, this)) {
+    }
+    inline virtual ~LocAdapterProxyBase() {
+        delete mLocAdapterBase;
+    }
+    inline void updateEvtMask(LOC_API_ADAPTER_EVENT_MASK_T event,
+                              loc_registration_mask_status isEnabled) {
+        mLocAdapterBase->updateEvtMask(event,isEnabled);
+    }
+
+    inline uint32_t generateSessionId() {
+        return mLocAdapterBase->generateSessionId();
+    }
+public:
+    inline ContextBase* getContext() const {
+        return mLocAdapterBase->getContext();
+    }
+
+    inline virtual void handleEngineUpEvent() {};
+    inline virtual void handleEngineDownEvent() {};
+    inline virtual void reportPositionEvent(UlpLocation &location,
+                                            GpsLocationExtended &locationExtended,
+                                            enum loc_sess_status status,
+                                            LocPosTechMask loc_technology_mask) {
+        (void)location;
+        (void)locationExtended;
+        (void)status;
+        (void)loc_technology_mask;
+    }
+};
+
+} // namespace loc_core
+
+#endif //LOC_ADAPTER_PROXY_BASE_H
diff --git a/gps/core/LocApiBase.cpp b/gps/core/LocApiBase.cpp
new file mode 100644
index 0000000..860da2e
--- /dev/null
+++ b/gps/core/LocApiBase.cpp
@@ -0,0 +1,1069 @@
+/* Copyright (c) 2011-2014, 2016-2021 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_NDEBUG 0 //Define to enable LOGV
+#define LOG_TAG "LocSvc_LocApiBase"
+
+#include <dlfcn.h>
+#include <inttypes.h>
+#include <gps_extended_c.h>
+#include <LocApiBase.h>
+#include <LocAdapterBase.h>
+#include <log_util.h>
+#include <LocContext.h>
+#include <loc_misc_utils.h>
+
+namespace loc_core {
+
+#define TO_ALL_LOCADAPTERS(call) TO_ALL_ADAPTERS(mLocAdapters, (call))
+#define TO_1ST_HANDLING_LOCADAPTERS(call) TO_1ST_HANDLING_ADAPTER(mLocAdapters, (call))
+
+int hexcode(char *hexstring, int string_size,
+            const char *data, int data_size)
+{
+   int i;
+   for (i = 0; i < data_size; i++)
+   {
+      char ch = data[i];
+      if (i*2 + 3 <= string_size)
+      {
+         snprintf(&hexstring[i*2], 3, "%02X", ch);
+      }
+      else {
+         break;
+      }
+   }
+   return i;
+}
+
+int decodeAddress(char *addr_string, int string_size,
+                   const char *data, int data_size)
+{
+    const char addr_prefix = 0x91;
+    int i, idxOutput = 0;
+
+    if (!data || !addr_string) { return 0; }
+
+    if (data[0] != addr_prefix)
+    {
+        LOC_LOGW("decodeAddress: address prefix is not 0x%x but 0x%x", addr_prefix, data[0]);
+        addr_string[0] = '\0';
+        return 0; // prefix not correct
+    }
+
+    for (i = 1; i < data_size; i++)
+    {
+        unsigned char ch = data[i], low = ch & 0x0F, hi = ch >> 4;
+        if (low <= 9 && idxOutput < string_size - 1) { addr_string[idxOutput++] = low + '0'; }
+        if (hi <= 9 && idxOutput < string_size - 1) { addr_string[idxOutput++] = hi + '0'; }
+    }
+
+    addr_string[idxOutput] = '\0'; // Terminates the string
+
+    return idxOutput;
+}
+
+struct LocSsrMsg : public LocMsg {
+    LocApiBase* mLocApi;
+    inline LocSsrMsg(LocApiBase* locApi) :
+        LocMsg(), mLocApi(locApi)
+    {
+        locallog();
+    }
+    inline virtual void proc() const {
+        mLocApi->close();
+        if (LOC_API_ADAPTER_ERR_SUCCESS == mLocApi->open(mLocApi->getEvtMask())) {
+            // Notify adapters that engine up after SSR
+            mLocApi->handleEngineUpEvent();
+        }
+    }
+    inline void locallog() const {
+        LOC_LOGV("LocSsrMsg");
+    }
+    inline virtual void log() const {
+        locallog();
+    }
+};
+
+struct LocOpenMsg : public LocMsg {
+    LocApiBase* mLocApi;
+    LocAdapterBase* mAdapter;
+    inline LocOpenMsg(LocApiBase* locApi, LocAdapterBase* adapter = nullptr) :
+            LocMsg(), mLocApi(locApi), mAdapter(adapter)
+    {
+        locallog();
+    }
+    inline virtual void proc() const {
+        if (LOC_API_ADAPTER_ERR_SUCCESS == mLocApi->open(mLocApi->getEvtMask()) &&
+            nullptr != mAdapter) {
+            mAdapter->handleEngineUpEvent();
+        }
+    }
+    inline void locallog() const {
+        LOC_LOGv("LocOpen Mask: %" PRIx64 "\n", mLocApi->getEvtMask());
+    }
+    inline virtual void log() const {
+        locallog();
+    }
+};
+
+struct LocCloseMsg : public LocMsg {
+    LocApiBase* mLocApi;
+    inline LocCloseMsg(LocApiBase* locApi) :
+        LocMsg(), mLocApi(locApi)
+    {
+        locallog();
+    }
+    inline virtual void proc() const {
+        mLocApi->close();
+    }
+    inline void locallog() const {
+    }
+    inline virtual void log() const {
+        locallog();
+    }
+};
+
+MsgTask* LocApiBase::mMsgTask = nullptr;
+volatile int32_t LocApiBase::mMsgTaskRefCount = 0;
+
+LocApiBase::LocApiBase(LOC_API_ADAPTER_EVENT_MASK_T excludedMask,
+                       ContextBase* context) :
+    mContext(context),
+    mMask(0), mExcludedMask(excludedMask)
+{
+    memset(mLocAdapters, 0, sizeof(mLocAdapters));
+
+    android_atomic_inc(&mMsgTaskRefCount);
+    if (nullptr == mMsgTask) {
+        mMsgTask = new MsgTask("LocApiMsgTask");
+    }
+}
+
+LOC_API_ADAPTER_EVENT_MASK_T LocApiBase::getEvtMask()
+{
+    LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
+
+    TO_ALL_LOCADAPTERS(mask |= mLocAdapters[i]->getEvtMask());
+
+    return mask & ~mExcludedMask;
+}
+
+bool LocApiBase::isMaster()
+{
+    bool isMaster = false;
+
+    for (int i = 0;
+            !isMaster && i < MAX_ADAPTERS && NULL != mLocAdapters[i];
+            i++) {
+        isMaster |= mLocAdapters[i]->isAdapterMaster();
+    }
+    return isMaster;
+}
+
+bool LocApiBase::isInSession()
+{
+    bool inSession = false;
+
+    for (int i = 0;
+         !inSession && i < MAX_ADAPTERS && NULL != mLocAdapters[i];
+         i++) {
+        inSession = mLocAdapters[i]->isInSession();
+    }
+
+    return inSession;
+}
+
+bool LocApiBase::needReport(const UlpLocation& ulpLocation,
+                            enum loc_sess_status status,
+                            LocPosTechMask techMask)
+{
+    bool reported = false;
+
+    if (LOC_SESS_SUCCESS == status) {
+        // this is a final fix
+        LocPosTechMask mask =
+            LOC_POS_TECH_MASK_SATELLITE | LOC_POS_TECH_MASK_SENSORS | LOC_POS_TECH_MASK_HYBRID;
+        // it is a Satellite fix or a sensor fix
+        reported = (mask & techMask);
+    }
+    else if (LOC_SESS_INTERMEDIATE == status &&
+        LOC_SESS_INTERMEDIATE == ContextBase::mGps_conf.INTERMEDIATE_POS) {
+        // this is a intermediate fix and we accept intermediate
+
+        // it is NOT the case that
+        // there is inaccuracy; and
+        // we care about inaccuracy; and
+        // the inaccuracy exceeds our tolerance
+        reported = !((ulpLocation.gpsLocation.flags & LOC_GPS_LOCATION_HAS_ACCURACY) &&
+            (ContextBase::mGps_conf.ACCURACY_THRES != 0) &&
+            (ulpLocation.gpsLocation.accuracy > ContextBase::mGps_conf.ACCURACY_THRES));
+    }
+
+    return reported;
+}
+
+void LocApiBase::addAdapter(LocAdapterBase* adapter)
+{
+    for (int i = 0; i < MAX_ADAPTERS && mLocAdapters[i] != adapter; i++) {
+        if (mLocAdapters[i] == NULL) {
+            mLocAdapters[i] = adapter;
+            sendMsg(new LocOpenMsg(this,  adapter));
+            break;
+        }
+    }
+}
+
+void LocApiBase::removeAdapter(LocAdapterBase* adapter)
+{
+    for (int i = 0;
+         i < MAX_ADAPTERS && NULL != mLocAdapters[i];
+         i++) {
+        if (mLocAdapters[i] == adapter) {
+            mLocAdapters[i] = NULL;
+
+            // shift the rest of the adapters up so that the pointers
+            // in the array do not have holes.  This should be more
+            // performant, because the array maintenance is much much
+            // less frequent than event handlings, which need to linear
+            // search all the adapters
+            int j = i;
+            while (++i < MAX_ADAPTERS && mLocAdapters[i] != NULL);
+
+            // i would be MAX_ADAPTERS or point to a NULL
+            i--;
+            // i now should point to a none NULL adapter within valid
+            // range although i could be equal to j, but it won't hurt.
+            // No need to check it, as it gains nothing.
+            mLocAdapters[j] = mLocAdapters[i];
+            // this makes sure that we exit the for loop
+            mLocAdapters[i] = NULL;
+
+            // if we have an empty list of adapters
+            if (0 == i) {
+                sendMsg(new LocCloseMsg(this));
+            } else {
+                // else we need to remove the bit
+                sendMsg(new LocOpenMsg(this));
+            }
+        }
+    }
+}
+
+void LocApiBase::updateEvtMask()
+{
+    sendMsg(new LocOpenMsg(this));
+}
+
+void LocApiBase::updateNmeaMask(uint32_t mask)
+{
+    struct LocSetNmeaMsg : public LocMsg {
+        LocApiBase* mLocApi;
+        uint32_t mMask;
+        inline LocSetNmeaMsg(LocApiBase* locApi, uint32_t mask) :
+            LocMsg(), mLocApi(locApi), mMask(mask)
+        {
+            locallog();
+        }
+        inline virtual void proc() const {
+            mLocApi->setNMEATypesSync(mMask);
+        }
+        inline void locallog() const {
+            LOC_LOGv("LocSyncNmea NmeaMask: %" PRIx32 "\n", mMask);
+        }
+        inline virtual void log() const {
+            locallog();
+        }
+    };
+
+    sendMsg(new LocSetNmeaMsg(this, mask));
+}
+
+void LocApiBase::handleEngineUpEvent()
+{
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->handleEngineUpEvent());
+}
+
+void LocApiBase::handleEngineDownEvent()
+{    // This will take care of renegotiating the loc handle
+    sendMsg(new LocSsrMsg(this));
+
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->handleEngineDownEvent());
+}
+
+void LocApiBase::reportPosition(UlpLocation& location,
+                                GpsLocationExtended& locationExtended,
+                                enum loc_sess_status status,
+                                LocPosTechMask loc_technology_mask,
+                                GnssDataNotification* pDataNotify,
+                                int msInWeek)
+{
+    // print the location info before delivering
+    LOC_LOGD("flags: %d\n  source: %d\n  latitude: %f\n  longitude: %f\n  "
+             "altitude: %f\n  speed: %f\n  bearing: %f\n  accuracy: %f\n  "
+             "timestamp: %" PRId64 "\n"
+             "Session status: %d\n Technology mask: %u\n "
+             "SV used in fix (gps/glo/bds/gal/qzss) : \
+             (0x%" PRIx64 "/0x%" PRIx64 "/0x%" PRIx64 "/0x%" PRIx64 "/0x%" PRIx64 "/0x%" PRIx64 ")",
+             location.gpsLocation.flags, location.position_source,
+             location.gpsLocation.latitude, location.gpsLocation.longitude,
+             location.gpsLocation.altitude, location.gpsLocation.speed,
+             location.gpsLocation.bearing, location.gpsLocation.accuracy,
+             location.gpsLocation.timestamp, status, loc_technology_mask,
+             locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask,
+             locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask,
+             locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask,
+             locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask,
+             locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask,
+             locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask);
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(
+        mLocAdapters[i]->reportPositionEvent(location, locationExtended,
+                                             status, loc_technology_mask,
+                                             pDataNotify, msInWeek)
+    );
+}
+
+void LocApiBase::reportWwanZppFix(LocGpsLocation &zppLoc)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportWwanZppFix(zppLoc));
+}
+
+void LocApiBase::reportZppBestAvailableFix(LocGpsLocation &zppLoc,
+        GpsLocationExtended &location_extended, LocPosTechMask tech_mask)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportZppBestAvailableFix(zppLoc,
+            location_extended, tech_mask));
+}
+
+void LocApiBase::requestOdcpi(OdcpiRequestInfo& request)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestOdcpiEvent(request));
+}
+
+void LocApiBase::reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssEngEnergyConsumedEvent(
+            energyConsumedSinceFirstBoot));
+}
+
+void LocApiBase::reportDeleteAidingDataEvent(GnssAidingData& aidingData) {
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportDeleteAidingDataEvent(aidingData));
+}
+
+void LocApiBase::reportKlobucharIonoModel(GnssKlobucharIonoModel & ionoModel) {
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportKlobucharIonoModelEvent(ionoModel));
+}
+
+void LocApiBase::reportGnssAdditionalSystemInfo(GnssAdditionalSystemInfo& additionalSystemInfo) {
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportGnssAdditionalSystemInfoEvent(
+            additionalSystemInfo));
+}
+
+void LocApiBase::sendNfwNotification(GnssNfwNotification& notification)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportNfwNotificationEvent(notification));
+
+}
+
+void LocApiBase::reportSv(GnssSvNotification& svNotify)
+{
+    const char* constellationString[] = { "Unknown", "GPS", "SBAS", "GLONASS",
+        "QZSS", "BEIDOU", "GALILEO", "NAVIC" };
+
+    // print the SV info before delivering
+    LOC_LOGV("num sv: %u\n"
+        "      sv: constellation svid         cN0  basebandCN0"
+        "    elevation    azimuth    flags",
+        svNotify.count);
+    for (size_t i = 0; i < svNotify.count && i < GNSS_SV_MAX; i++) {
+        if (svNotify.gnssSvs[i].type >
+            sizeof(constellationString) / sizeof(constellationString[0]) - 1) {
+            svNotify.gnssSvs[i].type = GNSS_SV_TYPE_UNKNOWN;
+        }
+        // Display what we report to clients
+        LOC_LOGV("   %03zu: %*s  %02d    %f    %f    %f    %f    %f    0x%02X 0x%2X",
+            i,
+            13,
+            constellationString[svNotify.gnssSvs[i].type],
+            svNotify.gnssSvs[i].svId,
+            svNotify.gnssSvs[i].cN0Dbhz,
+            svNotify.gnssSvs[i].basebandCarrierToNoiseDbHz,
+            svNotify.gnssSvs[i].elevation,
+            svNotify.gnssSvs[i].azimuth,
+            svNotify.gnssSvs[i].carrierFrequencyHz,
+            svNotify.gnssSvs[i].gnssSvOptionsMask,
+            svNotify.gnssSvs[i].gnssSignalTypeMask);
+    }
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(
+        mLocAdapters[i]->reportSvEvent(svNotify)
+        );
+}
+
+void LocApiBase::reportSvPolynomial(GnssSvPolynomial &svPolynomial)
+{
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(
+        mLocAdapters[i]->reportSvPolynomialEvent(svPolynomial)
+    );
+}
+
+void LocApiBase::reportSvEphemeris(GnssSvEphemerisReport & svEphemeris)
+{
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(
+        mLocAdapters[i]->reportSvEphemerisEvent(svEphemeris)
+    );
+}
+
+void LocApiBase::reportStatus(LocGpsStatusValue status)
+{
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportStatus(status));
+}
+
+void LocApiBase::reportData(GnssDataNotification& dataNotify, int msInWeek)
+{
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportDataEvent(dataNotify, msInWeek));
+}
+
+void LocApiBase::reportNmea(const char* nmea, int length)
+{
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportNmeaEvent(nmea, length));
+}
+
+void LocApiBase::reportXtraServer(const char* url1, const char* url2,
+                                  const char* url3, const int maxlength)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportXtraServer(url1, url2, url3, maxlength));
+
+}
+
+void LocApiBase::reportLocationSystemInfo(const LocationSystemInfo& locationSystemInfo)
+{
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportLocationSystemInfoEvent(locationSystemInfo));
+}
+
+void LocApiBase::reportQwesCapabilities
+(
+    const std::unordered_map<LocationQwesFeatureType, bool> &featureMap
+)
+{
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportQwesCapabilities(featureMap));
+}
+void LocApiBase::requestXtraData()
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestXtraData());
+}
+
+void LocApiBase::requestTime()
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestTime());
+}
+
+void LocApiBase::requestLocation()
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestLocation());
+}
+
+void LocApiBase::requestATL(int connHandle, LocAGpsType agps_type,
+                            LocApnTypeMask apn_type_mask)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(
+            mLocAdapters[i]->requestATL(connHandle, agps_type, apn_type_mask));
+}
+
+void LocApiBase::releaseATL(int connHandle)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->releaseATL(connHandle));
+}
+
+void LocApiBase::requestNiNotify(GnssNiNotification &notify, const void* data,
+                                 const LocInEmergency emergencyState)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_1ST_HANDLING_LOCADAPTERS(
+            mLocAdapters[i]->requestNiNotifyEvent(notify,
+                                                  data,
+                                                  emergencyState));
+}
+
+void* LocApiBase :: getSibling()
+    DEFAULT_IMPL(NULL)
+
+LocApiProxyBase* LocApiBase :: getLocApiProxy()
+    DEFAULT_IMPL(NULL)
+
+void LocApiBase::reportGnssMeasurements(GnssMeasurements& gnssMeasurements, int msInWeek)
+{
+    // loop through adapters, and deliver to all adapters.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssMeasurementsEvent(gnssMeasurements, msInWeek));
+}
+
+void LocApiBase::reportGnssSvIdConfig(const GnssSvIdConfig& config)
+{
+    // Print the config
+    LOC_LOGv("gloBlacklistSvMask: %" PRIu64 ", bdsBlacklistSvMask: %" PRIu64 ",\n"
+             "qzssBlacklistSvMask: %" PRIu64 ", galBlacklistSvMask: %" PRIu64 ",\n"
+              "navicBlacklistSvMask: %" PRIu64,
+             config.gloBlacklistSvMask, config.bdsBlacklistSvMask,
+             config.qzssBlacklistSvMask, config.galBlacklistSvMask, config.navicBlacklistSvMask);
+
+    // 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));
+}
+
+void LocApiBase::geofenceBreach(size_t count, uint32_t* hwIds, Location& location,
+                                GeofenceBreachType breachType, uint64_t timestamp)
+{
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->geofenceBreachEvent(count, hwIds, location, breachType,
+                                                            timestamp));
+}
+
+void LocApiBase::geofenceStatus(GeofenceStatusAvailable available)
+{
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->geofenceStatusEvent(available));
+}
+
+void LocApiBase::reportDBTPosition(UlpLocation &location, GpsLocationExtended &locationExtended,
+                                   enum loc_sess_status status, LocPosTechMask loc_technology_mask)
+{
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportPositionEvent(location, locationExtended, status,
+                                                            loc_technology_mask));
+}
+
+void LocApiBase::reportLocations(Location* locations, size_t count, BatchingMode batchingMode)
+{
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportLocationsEvent(locations, count, batchingMode));
+}
+
+void LocApiBase::reportCompletedTrips(uint32_t accumulated_distance)
+{
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportCompletedTripsEvent(accumulated_distance));
+}
+
+void LocApiBase::handleBatchStatusEvent(BatchingStatus batchStatus)
+{
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportBatchStatusChangeEvent(batchStatus));
+}
+
+void LocApiBase::reportGnssConfig(uint32_t sessionId, const GnssConfig& gnssConfig)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssConfigEvent(sessionId, gnssConfig));
+}
+
+void LocApiBase::reportLatencyInfo(GnssLatencyInfo& gnssLatencyInfo)
+{
+    // loop through adapters, and deliver to the first handling adapter.
+    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportLatencyInfoEvent(gnssLatencyInfo));
+}
+
+enum loc_api_adapter_err LocApiBase::
+   open(LOC_API_ADAPTER_EVENT_MASK_T /*mask*/)
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+enum loc_api_adapter_err LocApiBase::
+    close()
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+void LocApiBase::startFix(const LocPosMode& /*posMode*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::stopFix(LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    deleteAidingData(const GnssAidingData& /*data*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    injectPosition(double /*latitude*/, double /*longitude*/, float /*accuracy*/,
+                   bool /*onDemandCpi*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    injectPosition(const Location& /*location*/, bool /*onDemandCpi*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    injectPosition(const GnssLocationInfoNotification & /*locationInfo*/, bool /*onDemandCpi*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    setTime(LocGpsUtcTime /*time*/, int64_t /*timeReference*/, int /*uncertainty*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+   atlOpenStatus(int /*handle*/, int /*is_succ*/, char* /*apn*/, uint32_t /*apnLen*/,
+                 AGpsBearerType /*bear*/, LocAGpsType /*agpsType*/,
+                 LocApnTypeMask /*mask*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    atlCloseStatus(int /*handle*/, int /*is_succ*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+    setServerSync(const char* /*url*/, int /*len*/, LocServerType /*type*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+    setServerSync(unsigned int /*ip*/, int /*port*/, LocServerType /*type*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::
+    informNiResponse(GnssNiResponse /*userResponse*/, const void* /*passThroughData*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+    setSUPLVersionSync(GnssConfigSuplVersion /*version*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+enum loc_api_adapter_err LocApiBase::
+    setNMEATypesSync (uint32_t /*typesMask*/)
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+LocationError LocApiBase::
+    setLPPConfigSync(GnssConfigLppProfileMask /*profileMask*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+
+enum loc_api_adapter_err LocApiBase::
+    setSensorPropertiesSync(bool /*gyroBiasVarianceRandomWalk_valid*/,
+                        float /*gyroBiasVarianceRandomWalk*/,
+                        bool /*accelBiasVarianceRandomWalk_valid*/,
+                        float /*accelBiasVarianceRandomWalk*/,
+                        bool /*angleBiasVarianceRandomWalk_valid*/,
+                        float /*angleBiasVarianceRandomWalk*/,
+                        bool /*rateBiasVarianceRandomWalk_valid*/,
+                        float /*rateBiasVarianceRandomWalk*/,
+                        bool /*velocityBiasVarianceRandomWalk_valid*/,
+                        float /*velocityBiasVarianceRandomWalk*/)
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+enum loc_api_adapter_err LocApiBase::
+    setSensorPerfControlConfigSync(int /*controlMode*/,
+                               int /*accelSamplesPerBatch*/,
+                               int /*accelBatchesPerSec*/,
+                               int /*gyroSamplesPerBatch*/,
+                               int /*gyroBatchesPerSec*/,
+                               int /*accelSamplesPerBatchHigh*/,
+                               int /*accelBatchesPerSecHigh*/,
+                               int /*gyroSamplesPerBatchHigh*/,
+                               int /*gyroBatchesPerSecHigh*/,
+                               int /*algorithmConfig*/)
+DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
+
+LocationError LocApiBase::
+    setAGLONASSProtocolSync(GnssConfigAGlonassPositionProtocolMask /*aGlonassProtocol*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+    setLPPeProtocolCpSync(GnssConfigLppeControlPlaneMask /*lppeCP*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::
+    setLPPeProtocolUpSync(GnssConfigLppeUserPlaneMask /*lppeUP*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+GnssConfigSuplVersion LocApiBase::convertSuplVersion(const uint32_t /*suplVersion*/)
+DEFAULT_IMPL(GNSS_CONFIG_SUPL_VERSION_1_0_0)
+
+GnssConfigLppeControlPlaneMask LocApiBase::convertLppeCp(const uint32_t /*lppeControlPlaneMask*/)
+DEFAULT_IMPL(0)
+
+GnssConfigLppeUserPlaneMask LocApiBase::convertLppeUp(const uint32_t /*lppeUserPlaneMask*/)
+DEFAULT_IMPL(0)
+
+LocationError LocApiBase::setEmergencyExtensionWindowSync(
+        const uint32_t /*emergencyExtensionSeconds*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::setMeasurementCorrections(
+        const GnssMeasurementCorrections& /*gnssMeasurementCorrections*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+   getWwanZppFix()
+DEFAULT_IMPL()
+
+void LocApiBase::
+   getBestAvailableZppFix()
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+    setGpsLockSync(GnssConfigGpsLock /*lock*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::
+    requestForAidingData(GnssAidingDataSvMask /*svDataMask*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+    setXtraVersionCheckSync(uint32_t /*check*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+LocationError LocApiBase::setBlacklistSvSync(const GnssSvIdConfig& /*config*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::setBlacklistSv(const GnssSvIdConfig& /*config*/,
+                                LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::getBlacklistSv()
+DEFAULT_IMPL()
+
+void LocApiBase::setConstellationControl(const GnssSvTypeConfig& /*config*/,
+                                         LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::getConstellationControl()
+DEFAULT_IMPL()
+
+void LocApiBase::resetConstellationControl(LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    setConstrainedTuncMode(bool /*enabled*/,
+                           float /*tuncConstraint*/,
+                           uint32_t /*energyBudget*/,
+                           LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    setPositionAssistedClockEstimatorMode(bool /*enabled*/,
+                                          LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::getGnssEnergyConsumed()
+DEFAULT_IMPL()
+
+
+void LocApiBase::addGeofence(uint32_t /*clientId*/, const GeofenceOption& /*options*/,
+        const GeofenceInfo& /*info*/,
+        LocApiResponseData<LocApiGeofenceData>* /*adapterResponseData*/)
+DEFAULT_IMPL()
+
+void LocApiBase::removeGeofence(uint32_t /*hwId*/, uint32_t /*clientId*/,
+        LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::pauseGeofence(uint32_t /*hwId*/, uint32_t /*clientId*/,
+        LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::resumeGeofence(uint32_t /*hwId*/, uint32_t /*clientId*/,
+        LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::modifyGeofence(uint32_t /*hwId*/, uint32_t /*clientId*/,
+         const GeofenceOption& /*options*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::startTimeBasedTracking(const TrackingOptions& /*options*/,
+        LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::stopTimeBasedTracking(LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::startDistanceBasedTracking(uint32_t /*sessionId*/,
+        const LocationOptions& /*options*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::stopDistanceBasedTracking(uint32_t /*sessionId*/,
+        LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::startBatching(uint32_t /*sessionId*/, const LocationOptions& /*options*/,
+        uint32_t /*accuracy*/, uint32_t /*timeout*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::stopBatching(uint32_t /*sessionId*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::startOutdoorTripBatchingSync(uint32_t /*tripDistance*/,
+        uint32_t /*tripTbf*/, uint32_t /*timeout*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::startOutdoorTripBatching(uint32_t /*tripDistance*/, uint32_t /*tripTbf*/,
+        uint32_t /*timeout*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::reStartOutdoorTripBatching(uint32_t /*ongoingTripDistance*/,
+        uint32_t /*ongoingTripInterval*/, uint32_t /*batchingTimeout,*/,
+        LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::stopOutdoorTripBatchingSync(bool /*deallocBatchBuffer*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::stopOutdoorTripBatching(bool /*deallocBatchBuffer*/,
+        LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::getBatchedLocationsSync(size_t /*count*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::getBatchedLocations(size_t /*count*/, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::getBatchedTripLocationsSync(size_t /*count*/,
+        uint32_t /*accumulatedDistance*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::getBatchedTripLocations(size_t /*count*/, uint32_t /*accumulatedDistance*/,
+        LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::queryAccumulatedTripDistanceSync(uint32_t& /*accumulated_trip_distance*/,
+        uint32_t& /*numOfBatchedPositions*/)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::queryAccumulatedTripDistance(
+        LocApiResponseData<LocApiBatchData>* /*adapterResponseData*/)
+DEFAULT_IMPL()
+
+void LocApiBase::setBatchSize(size_t /*size*/)
+DEFAULT_IMPL()
+
+void LocApiBase::setTripBatchSize(size_t /*size*/)
+DEFAULT_IMPL()
+
+void LocApiBase::addToCallQueue(LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::updateSystemPowerState(PowerStateType /*powerState*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    configRobustLocation(bool /*enabled*/,
+                         bool /*enableForE911*/,
+                         LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    getRobustLocationConfig(uint32_t sessionId, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    configMinGpsWeek(uint16_t minGpsWeek,
+                     LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    getMinGpsWeek(uint32_t sessionId, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+LocationError LocApiBase::
+    setParameterSync(const GnssConfig& gnssConfig)
+DEFAULT_IMPL(LOCATION_ERROR_SUCCESS)
+
+void LocApiBase::
+    getParameter(uint32_t sessionId, GnssConfigFlagsMask flags, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    configConstellationMultiBand(const GnssSvTypeConfig& secondaryBandConfig,
+                                 LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+void LocApiBase::
+    getConstellationMultiBandConfig(uint32_t sessionId, LocApiResponse* /*adapterResponse*/)
+DEFAULT_IMPL()
+
+int64_t ElapsedRealtimeEstimator::getElapsedRealtimeEstimateNanos(int64_t curDataTimeNanos,
+            bool isCurDataTimeTrustable, int64_t tbf) {
+    //The algorithm works follow below steps:
+    //When isCurDataTimeTrustable is meet (means Modem timestamp is already stable),
+    //1, Wait for mFixTimeStablizationThreshold fixes; While waiting for modem time
+    //   stable, we set the traveltime to a default value;
+    //2, When the mFixTimeStablizationThreshold fix comes, we think now the mode time
+    //   is already stable, calculate the initial AP-Modem clock diff(mCurrentClockDiff)
+    //   using formula:
+    //   mCurrentClockDiff = currentTimeNanos - locationTimeNanos - currentTravelTimeNanos
+    //3, since then, when the nth fix comes,
+    //   3.1 First update mCurrentClockDiff using below formula:
+    //        mCurrentClockDiff = mCurrentClockDiff + (currentTimeNanos - sinceBootTimeNanos)
+    //                - (mPrevUtcTimeNanos - mPrevBootTimeNanos)
+    //   3.2 Calculate currentTravelTimeNanos:
+    //        currentTravelTimeNanos = currentTimeNanos - locationTimeNanos - mCurrentClockDiff
+    //4, It is possible that locationTimeNanos will jump,
+    //   reset mFixTimeStablizationThreshold to default value, jump to step 2 to continue.
+
+    int64_t currentTravelTimeNanos = mInitialTravelTime;
+    struct timespec currentTime;
+    int64_t sinceBootTimeNanos;
+    if (getCurrentTime(currentTime, sinceBootTimeNanos)) {
+        if (isCurDataTimeTrustable) {
+            if (tbf > 0 && tbf != curDataTimeNanos - mPrevDataTimeNanos) {
+                mFixTimeStablizationThreshold = 5;
+            }
+            int64_t currentTimeNanos = (int64_t)currentTime.tv_sec*1000000000 + currentTime.tv_nsec;
+            LOC_LOGd("sinceBootTimeNanos:%" PRIi64 " currentTimeNanos:%" PRIi64 ""
+                     " locationTimeNanos:%" PRIi64 "",
+                     sinceBootTimeNanos, currentTimeNanos, curDataTimeNanos);
+            if (mFixTimeStablizationThreshold == 0) {
+                currentTravelTimeNanos = mInitialTravelTime;
+                mCurrentClockDiff = currentTimeNanos - curDataTimeNanos - currentTravelTimeNanos;
+            } else if (mFixTimeStablizationThreshold < 0) {
+                mCurrentClockDiff = mCurrentClockDiff + (currentTimeNanos - sinceBootTimeNanos)
+                        - (mPrevUtcTimeNanos - mPrevBootTimeNanos);
+                currentTravelTimeNanos = currentTimeNanos - curDataTimeNanos - mCurrentClockDiff;
+            }
+
+            mPrevUtcTimeNanos = currentTimeNanos;
+            mPrevBootTimeNanos = sinceBootTimeNanos;
+            mPrevDataTimeNanos = curDataTimeNanos;
+            mFixTimeStablizationThreshold--;
+        }
+    } else {
+        return -1;
+    }
+    LOC_LOGd("Estimated travel time: %" PRIi64 "", currentTravelTimeNanos);
+    return (sinceBootTimeNanos - currentTravelTimeNanos);
+}
+
+void ElapsedRealtimeEstimator::reset() {
+    mCurrentClockDiff = 0;
+    mPrevDataTimeNanos = 0;
+    mPrevUtcTimeNanos = 0;
+    mPrevBootTimeNanos = 0;
+    mFixTimeStablizationThreshold = 5;
+}
+
+int64_t ElapsedRealtimeEstimator::getElapsedRealtimeQtimer(int64_t qtimerTicksAtOrigin) {
+    struct timespec currentTime;
+    int64_t sinceBootTimeNanos;
+    int64_t elapsedRealTimeNanos;
+
+    if (getCurrentTime(currentTime, sinceBootTimeNanos)) {
+       uint64_t qtimerDiff = 0;
+       uint64_t qTimerTickCount = getQTimerTickCount();
+       if (qTimerTickCount >= qtimerTicksAtOrigin) {
+           qtimerDiff = qTimerTickCount - qtimerTicksAtOrigin;
+       }
+       LOC_LOGd("sinceBootTimeNanos:%" PRIi64 " qtimerTicksAtOrigin=%" PRIi64 ""
+                " qTimerTickCount=%" PRIi64 " qtimerDiff=%" PRIi64 "",
+                sinceBootTimeNanos, qtimerTicksAtOrigin, qTimerTickCount, qtimerDiff);
+       uint64_t qTimerDiffNanos = qTimerTicksToNanos(double(qtimerDiff));
+
+       /* If the time difference between Qtimer on modem side and Qtimer on AP side
+          is greater than one second we assume this is a dual-SoC device such as
+          Kona and will try to get Qtimer on modem side and on AP side and
+          will adjust our difference accordingly */
+       if (qTimerDiffNanos > 1000000000) {
+           uint64_t qtimerDelta = getQTimerDeltaNanos();
+           if (qTimerDiffNanos >= qtimerDelta) {
+               qTimerDiffNanos -= qtimerDelta;
+           }
+       }
+
+       LOC_LOGd("Qtimer travel time: %" PRIi64 "", qTimerDiffNanos);
+       if (sinceBootTimeNanos >= qTimerDiffNanos) {
+           elapsedRealTimeNanos = sinceBootTimeNanos - qTimerDiffNanos;
+       } else {
+           elapsedRealTimeNanos = -1;
+       }
+    } else {
+        elapsedRealTimeNanos = -1;
+    }
+    return elapsedRealTimeNanos;
+}
+
+bool ElapsedRealtimeEstimator::getCurrentTime(
+        struct timespec& currentTime, int64_t& sinceBootTimeNanos)
+{
+    struct timespec sinceBootTime;
+    struct timespec sinceBootTimeTest;
+    bool clockGetTimeSuccess = false;
+    const uint32_t MAX_TIME_DELTA_VALUE_NANOS = 15000;
+    const uint32_t MAX_GET_TIME_COUNT = 20;
+    /* Attempt to get CLOCK_REALTIME and CLOCK_BOOTIME in succession without an interruption
+    or context switch (for up to MAX_GET_TIME_COUNT times) to avoid errors in the calculation */
+    for (uint32_t i = 0; i < MAX_GET_TIME_COUNT; i++) {
+        if (clock_gettime(CLOCK_BOOTTIME, &sinceBootTime) != 0) {
+            break;
+        };
+        if (clock_gettime(CLOCK_REALTIME, &currentTime) != 0) {
+            break;
+        }
+        if (clock_gettime(CLOCK_BOOTTIME, &sinceBootTimeTest) != 0) {
+            break;
+        };
+        sinceBootTimeNanos = (int64_t)sinceBootTime.tv_sec * 1000000000 + sinceBootTime.tv_nsec;
+        int64_t sinceBootTimeTestNanos =
+            (int64_t)sinceBootTimeTest.tv_sec * 1000000000 + sinceBootTimeTest.tv_nsec;
+        int64_t sinceBootTimeDeltaNanos = sinceBootTimeTestNanos - sinceBootTimeNanos;
+
+        /* sinceBootTime and sinceBootTimeTest should have a close value if there was no
+        interruption or context switch between clock_gettime for CLOCK_BOOTIME and
+        clock_gettime for CLOCK_REALTIME */
+        if (sinceBootTimeDeltaNanos < MAX_TIME_DELTA_VALUE_NANOS) {
+            clockGetTimeSuccess = true;
+            break;
+        } else {
+            LOC_LOGd("Delta:%" PRIi64 "ns time too large, retry number #%u...",
+                     sinceBootTimeDeltaNanos, i + 1);
+        }
+    }
+    return clockGetTimeSuccess;
+}
+} // namespace loc_core
diff --git a/gps/core/LocApiBase.h b/gps/core/LocApiBase.h
new file mode 100644
index 0000000..121f795
--- /dev/null
+++ b/gps/core/LocApiBase.h
@@ -0,0 +1,375 @@
+/* Copyright (c) 2011-2014, 2016-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef LOC_API_BASE_H
+#define LOC_API_BASE_H
+
+#include <stddef.h>
+#include <ctype.h>
+#include <gps_extended.h>
+#include <LocationAPI.h>
+#include <MsgTask.h>
+#include <LocSharedLock.h>
+#include <log_util.h>
+#ifdef NO_UNORDERED_SET_OR_MAP
+    #include <map>
+#else
+    #include <unordered_map>
+#endif
+#include <inttypes.h>
+#include <functional>
+
+using namespace loc_util;
+
+namespace loc_core {
+
+class ContextBase;
+struct LocApiResponse;
+template <typename> struct LocApiResponseData;
+
+int hexcode(char *hexstring, int string_size,
+            const char *data, int data_size);
+int decodeAddress(char *addr_string, int string_size,
+                  const char *data, int data_size);
+
+#define MAX_ADAPTERS          10
+#define MAX_FEATURE_LENGTH    100
+
+#define TO_ALL_ADAPTERS(adapters, call)                                \
+    for (int i = 0; i < MAX_ADAPTERS && NULL != (adapters)[i]; i++) {  \
+        call;                                                          \
+    }
+
+#define TO_1ST_HANDLING_ADAPTER(adapters, call)                              \
+    for (int i = 0; i <MAX_ADAPTERS && NULL != (adapters)[i] && !(call); i++);
+
+class LocAdapterBase;
+struct LocSsrMsg;
+struct LocOpenMsg;
+
+typedef struct
+{
+    uint32_t accumulatedDistance;
+    uint32_t numOfBatchedPositions;
+} LocApiBatchData;
+
+typedef struct
+{
+    uint32_t hwId;
+} LocApiGeofenceData;
+
+struct LocApiMsg: LocMsg {
+    private:
+        std::function<void ()> mProcImpl;
+        inline virtual void proc() const {
+            mProcImpl();
+        }
+    public:
+        inline LocApiMsg(std::function<void ()> procImpl ) :
+                         mProcImpl(procImpl) {}
+};
+
+class LocApiProxyBase {
+public:
+    inline LocApiProxyBase() {}
+    inline virtual ~LocApiProxyBase() {}
+    inline virtual void* getSibling2() { return NULL; }
+    inline virtual double getGloRfLoss(uint32_t left,
+            uint32_t center, uint32_t right, uint8_t gloFrequency) { return 0.0; }
+};
+
+class LocApiBase {
+    friend struct LocSsrMsg;
+    //LocOpenMsg calls open() which makes it necessary to declare
+    //it as a friend
+    friend struct LocOpenMsg;
+    friend struct LocCloseMsg;
+    friend struct LocKillMsg;
+    friend class ContextBase;
+    static MsgTask* mMsgTask;
+    static volatile int32_t mMsgTaskRefCount;
+    LocAdapterBase* mLocAdapters[MAX_ADAPTERS];
+
+protected:
+    ContextBase *mContext;
+    virtual enum loc_api_adapter_err
+        open(LOC_API_ADAPTER_EVENT_MASK_T mask);
+    virtual enum loc_api_adapter_err
+        close();
+    LOC_API_ADAPTER_EVENT_MASK_T getEvtMask();
+    LOC_API_ADAPTER_EVENT_MASK_T mMask;
+    uint32_t mNmeaMask;
+    LocApiBase(LOC_API_ADAPTER_EVENT_MASK_T excludedMask,
+               ContextBase* context = NULL);
+    inline virtual ~LocApiBase() {
+        android_atomic_dec(&mMsgTaskRefCount);
+        if (nullptr != mMsgTask && 0 == mMsgTaskRefCount) {
+            delete mMsgTask;
+            mMsgTask = nullptr;
+        }
+    }
+    bool isInSession();
+    const LOC_API_ADAPTER_EVENT_MASK_T mExcludedMask;
+    bool isMaster();
+
+public:
+    inline void sendMsg(const LocMsg* msg) const {
+        if (nullptr != mMsgTask) {
+            mMsgTask->sendMsg(msg);
+        }
+    }
+    inline void destroy() {
+        close();
+        struct LocKillMsg : public LocMsg {
+            LocApiBase* mLocApi;
+            inline LocKillMsg(LocApiBase* locApi) : LocMsg(), mLocApi(locApi) {}
+            inline virtual void proc() const {
+                delete mLocApi;
+            }
+        };
+        sendMsg(new LocKillMsg(this));
+    }
+
+    static bool needReport(const UlpLocation& ulpLocation,
+                           enum loc_sess_status status,
+                           LocPosTechMask techMask);
+
+    void addAdapter(LocAdapterBase* adapter);
+    void removeAdapter(LocAdapterBase* adapter);
+
+    // upward calls
+    void handleEngineUpEvent();
+    void handleEngineDownEvent();
+    void reportPosition(UlpLocation& location,
+                        GpsLocationExtended& locationExtended,
+                        enum loc_sess_status status,
+                        LocPosTechMask loc_technology_mask =
+                                  LOC_POS_TECH_MASK_DEFAULT,
+                        GnssDataNotification* pDataNotify = nullptr,
+                        int msInWeek = -1);
+    void reportSv(GnssSvNotification& svNotify);
+    void reportSvPolynomial(GnssSvPolynomial &svPolynomial);
+    void reportSvEphemeris(GnssSvEphemerisReport &svEphemeris);
+    void reportStatus(LocGpsStatusValue status);
+    void reportNmea(const char* nmea, int length);
+    void reportData(GnssDataNotification& dataNotify, int msInWeek);
+    void reportXtraServer(const char* url1, const char* url2,
+                          const char* url3, const int maxlength);
+    void reportLocationSystemInfo(const LocationSystemInfo& locationSystemInfo);
+    void requestXtraData();
+    void requestTime();
+    void requestLocation();
+    void requestATL(int connHandle, LocAGpsType agps_type, LocApnTypeMask apn_type_mask);
+    void releaseATL(int connHandle);
+    void requestNiNotify(GnssNiNotification &notify, const void* data,
+                         const LocInEmergency emergencyState);
+    void reportGnssMeasurements(GnssMeasurements& gnssMeasurements, int msInWeek);
+    void reportWwanZppFix(LocGpsLocation &zppLoc);
+    void reportZppBestAvailableFix(LocGpsLocation &zppLoc, GpsLocationExtended &location_extended,
+            LocPosTechMask tech_mask);
+    void reportGnssSvIdConfig(const GnssSvIdConfig& config);
+    void reportGnssSvTypeConfig(const GnssSvTypeConfig& config);
+    void requestOdcpi(OdcpiRequestInfo& request);
+    void reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot);
+    void reportDeleteAidingDataEvent(GnssAidingData& aidingData);
+    void reportKlobucharIonoModel(GnssKlobucharIonoModel& ionoModel);
+    void reportGnssAdditionalSystemInfo(GnssAdditionalSystemInfo& additionalSystemInfo);
+    void sendNfwNotification(GnssNfwNotification& notification);
+    void reportGnssConfig(uint32_t sessionId, const GnssConfig& gnssConfig);
+    void reportLatencyInfo(GnssLatencyInfo& gnssLatencyInfo);
+    void reportQwesCapabilities
+    (
+        const std::unordered_map<LocationQwesFeatureType, bool> &featureMap
+    );
+
+    void geofenceBreach(size_t count, uint32_t* hwIds, Location& location,
+            GeofenceBreachType breachType, uint64_t timestamp);
+    void geofenceStatus(GeofenceStatusAvailable available);
+    void reportDBTPosition(UlpLocation &location,
+                           GpsLocationExtended &locationExtended,
+                           enum loc_sess_status status,
+                           LocPosTechMask loc_technology_mask);
+    void reportLocations(Location* locations, size_t count, BatchingMode batchingMode);
+    void reportCompletedTrips(uint32_t accumulated_distance);
+    void handleBatchStatusEvent(BatchingStatus batchStatus);
+
+    // downward calls
+    virtual void* getSibling();
+    virtual LocApiProxyBase* getLocApiProxy();
+    virtual void startFix(const LocPosMode& fixCriteria, LocApiResponse* adapterResponse);
+    virtual void stopFix(LocApiResponse* adapterResponse);
+    virtual void deleteAidingData(const GnssAidingData& data, LocApiResponse* adapterResponse);
+    virtual void injectPosition(double latitude, double longitude, float accuracy,
+            bool onDemandCpi);
+    virtual void injectPosition(const GnssLocationInfoNotification &locationInfo,
+            bool onDemandCpi=false);
+    virtual void injectPosition(const Location& location, bool onDemandCpi);
+    virtual void setTime(LocGpsUtcTime time, int64_t timeReference, int uncertainty);
+    virtual void atlOpenStatus(int handle, int is_succ, char* apn, uint32_t apnLen,
+            AGpsBearerType bear, LocAGpsType agpsType, LocApnTypeMask mask);
+    virtual void atlCloseStatus(int handle, int is_succ);
+    virtual LocationError setServerSync(const char* url, int len, LocServerType type);
+    virtual LocationError setServerSync(unsigned int ip, int port, LocServerType type);
+    virtual void informNiResponse(GnssNiResponse userResponse, const void* passThroughData);
+    virtual LocationError setSUPLVersionSync(GnssConfigSuplVersion version);
+    virtual enum loc_api_adapter_err setNMEATypesSync(uint32_t typesMask);
+    virtual LocationError setLPPConfigSync(GnssConfigLppProfileMask profileMask);
+    virtual enum loc_api_adapter_err setSensorPropertiesSync(
+            bool gyroBiasVarianceRandomWalk_valid, float gyroBiasVarianceRandomWalk,
+            bool accelBiasVarianceRandomWalk_valid, float accelBiasVarianceRandomWalk,
+            bool angleBiasVarianceRandomWalk_valid, float angleBiasVarianceRandomWalk,
+            bool rateBiasVarianceRandomWalk_valid, float rateBiasVarianceRandomWalk,
+            bool velocityBiasVarianceRandomWalk_valid, float velocityBiasVarianceRandomWalk);
+    virtual enum loc_api_adapter_err setSensorPerfControlConfigSync(int controlMode,
+            int accelSamplesPerBatch, int accelBatchesPerSec, int gyroSamplesPerBatch,
+            int gyroBatchesPerSec, int accelSamplesPerBatchHigh, int accelBatchesPerSecHigh,
+            int gyroSamplesPerBatchHigh, int gyroBatchesPerSecHigh, int algorithmConfig);
+    virtual LocationError
+            setAGLONASSProtocolSync(GnssConfigAGlonassPositionProtocolMask aGlonassProtocol);
+    virtual LocationError setLPPeProtocolCpSync(GnssConfigLppeControlPlaneMask lppeCP);
+    virtual LocationError setLPPeProtocolUpSync(GnssConfigLppeUserPlaneMask lppeUP);
+    virtual GnssConfigSuplVersion convertSuplVersion(const uint32_t suplVersion);
+    virtual GnssConfigLppeControlPlaneMask convertLppeCp(const uint32_t lppeControlPlaneMask);
+    virtual GnssConfigLppeUserPlaneMask convertLppeUp(const uint32_t lppeUserPlaneMask);
+    virtual LocationError setEmergencyExtensionWindowSync(const uint32_t emergencyExtensionSeconds);
+    virtual void setMeasurementCorrections(
+            const GnssMeasurementCorrections& gnssMeasurementCorrections);
+
+    virtual void getWwanZppFix();
+    virtual void getBestAvailableZppFix();
+    virtual LocationError setGpsLockSync(GnssConfigGpsLock lock);
+    virtual void requestForAidingData(GnssAidingDataSvMask svDataMask);
+    virtual LocationError setXtraVersionCheckSync(uint32_t check);
+    /* Requests for SV/Constellation Control */
+    virtual LocationError setBlacklistSvSync(const GnssSvIdConfig& config);
+    virtual void setBlacklistSv(const GnssSvIdConfig& config,
+                                LocApiResponse *adapterResponse=nullptr);
+    virtual void getBlacklistSv();
+    virtual void setConstellationControl(const GnssSvTypeConfig& config,
+                                         LocApiResponse *adapterResponse=nullptr);
+    virtual void getConstellationControl();
+    virtual void resetConstellationControl(LocApiResponse *adapterResponse=nullptr);
+
+    virtual void setConstrainedTuncMode(bool enabled,
+                                        float tuncConstraint,
+                                        uint32_t energyBudget,
+                                        LocApiResponse* adapterResponse=nullptr);
+    virtual void setPositionAssistedClockEstimatorMode(bool enabled,
+                                                       LocApiResponse* adapterResponse=nullptr);
+    virtual void getGnssEnergyConsumed();
+
+    virtual void addGeofence(uint32_t clientId, const GeofenceOption& options,
+            const GeofenceInfo& info, LocApiResponseData<LocApiGeofenceData>* adapterResponseData);
+    virtual void removeGeofence(uint32_t hwId, uint32_t clientId, LocApiResponse* adapterResponse);
+    virtual void pauseGeofence(uint32_t hwId, uint32_t clientId, LocApiResponse* adapterResponse);
+    virtual void resumeGeofence(uint32_t hwId, uint32_t clientId, LocApiResponse* adapterResponse);
+    virtual void modifyGeofence(uint32_t hwId, uint32_t clientId, const GeofenceOption& options,
+             LocApiResponse* adapterResponse);
+
+    virtual void startTimeBasedTracking(const TrackingOptions& options,
+             LocApiResponse* adapterResponse);
+    virtual void stopTimeBasedTracking(LocApiResponse* adapterResponse);
+    virtual void startDistanceBasedTracking(uint32_t sessionId, const LocationOptions& options,
+             LocApiResponse* adapterResponse);
+    virtual void stopDistanceBasedTracking(uint32_t sessionId,
+             LocApiResponse* adapterResponse = nullptr);
+    virtual void startBatching(uint32_t sessionId, const LocationOptions& options,
+            uint32_t accuracy, uint32_t timeout, LocApiResponse* adapterResponse);
+    virtual void stopBatching(uint32_t sessionId, LocApiResponse* adapterResponse);
+    virtual LocationError startOutdoorTripBatchingSync(uint32_t tripDistance,
+            uint32_t tripTbf, uint32_t timeout);
+    virtual void startOutdoorTripBatching(uint32_t tripDistance,
+            uint32_t tripTbf, uint32_t timeout, LocApiResponse* adapterResponse);
+    virtual void reStartOutdoorTripBatching(uint32_t ongoingTripDistance,
+            uint32_t ongoingTripInterval, uint32_t batchingTimeout,
+            LocApiResponse* adapterResponse);
+    virtual LocationError stopOutdoorTripBatchingSync(bool deallocBatchBuffer = true);
+    virtual void stopOutdoorTripBatching(bool deallocBatchBuffer = true,
+            LocApiResponse* adapterResponse = nullptr);
+    virtual LocationError getBatchedLocationsSync(size_t count);
+    virtual void getBatchedLocations(size_t count, LocApiResponse* adapterResponse);
+    virtual LocationError getBatchedTripLocationsSync(size_t count, uint32_t accumulatedDistance);
+    virtual void getBatchedTripLocations(size_t count, uint32_t accumulatedDistance,
+            LocApiResponse* adapterResponse);
+    virtual LocationError queryAccumulatedTripDistanceSync(uint32_t &accumulated_trip_distance,
+            uint32_t &numOfBatchedPositions);
+    virtual void queryAccumulatedTripDistance(
+            LocApiResponseData<LocApiBatchData>* adapterResponseData);
+    virtual void setBatchSize(size_t size);
+    virtual void setTripBatchSize(size_t size);
+    virtual void addToCallQueue(LocApiResponse* adapterResponse);
+
+    void updateEvtMask();
+    void updateNmeaMask(uint32_t mask);
+
+    virtual void updateSystemPowerState(PowerStateType systemPowerState);
+
+    virtual void configRobustLocation(bool enable, bool enableForE911,
+                                      LocApiResponse* adapterResponse=nullptr);
+    virtual void getRobustLocationConfig(uint32_t sessionId, LocApiResponse* adapterResponse);
+    virtual void configMinGpsWeek(uint16_t minGpsWeek,
+                                  LocApiResponse* adapterResponse=nullptr);
+    virtual void getMinGpsWeek(uint32_t sessionId, LocApiResponse* adapterResponse);
+
+    virtual LocationError setParameterSync(const GnssConfig & gnssConfig);
+    virtual void getParameter(uint32_t sessionId, GnssConfigFlagsMask flags,
+                              LocApiResponse* adapterResponse=nullptr);
+
+    virtual void configConstellationMultiBand(const GnssSvTypeConfig& secondaryBandConfig,
+                                              LocApiResponse* adapterResponse=nullptr);
+    virtual void getConstellationMultiBandConfig(uint32_t sessionId,
+                                        LocApiResponse* adapterResponse=nullptr);
+};
+
+class ElapsedRealtimeEstimator {
+private:
+    int64_t mCurrentClockDiff;
+    int64_t mPrevUtcTimeNanos;
+    int64_t mPrevBootTimeNanos;
+    int64_t mFixTimeStablizationThreshold;
+    int64_t mInitialTravelTime;
+    int64_t mPrevDataTimeNanos;
+public:
+
+    ElapsedRealtimeEstimator(int64_t travelTimeNanosEstimate):
+            mInitialTravelTime(travelTimeNanosEstimate) {reset();}
+    int64_t getElapsedRealtimeEstimateNanos(int64_t curDataTimeNanos,
+            bool isCurDataTimeTrustable, int64_t tbf);
+    inline int64_t getElapsedRealtimeUncNanos() { return 5000000;}
+    void reset();
+
+    static int64_t getElapsedRealtimeQtimer(int64_t qtimerTicksAtOrigin);
+    static bool getCurrentTime(struct timespec& currentTime, int64_t& sinceBootTimeNanos);
+};
+
+typedef LocApiBase* (getLocApi_t)(LOC_API_ADAPTER_EVENT_MASK_T exMask,
+                                  ContextBase *context);
+
+} // namespace loc_core
+
+#endif //LOC_API_BASE_H
diff --git a/gps/core/LocContext.cpp b/gps/core/LocContext.cpp
new file mode 100644
index 0000000..272c08c
--- /dev/null
+++ b/gps/core/LocContext.cpp
@@ -0,0 +1,87 @@
+/* Copyright (c) 2011-2014, 2016-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_Ctx"
+
+#include <cutils/sched_policy.h>
+#include <unistd.h>
+#include <LocContext.h>
+#include <msg_q.h>
+#include <log_util.h>
+#include <loc_log.h>
+
+namespace loc_core {
+
+const MsgTask* LocContext::mMsgTask = NULL;
+ContextBase* LocContext::mContext = NULL;
+// the name must be shorter than 15 chars
+const char* LocContext::mLocationHalName = "Loc_hal_worker";
+#ifndef USE_GLIB
+const char* LocContext::mLBSLibName = "liblbs_core.so";
+#else
+const char* LocContext::mLBSLibName = "liblbs_core.so.1";
+#endif
+
+pthread_mutex_t LocContext::mGetLocContextMutex = PTHREAD_MUTEX_INITIALIZER;
+
+const MsgTask* LocContext::getMsgTask(const char* name)
+{
+    if (NULL == mMsgTask) {
+        mMsgTask = new MsgTask(name);
+    }
+    return mMsgTask;
+}
+
+ContextBase* LocContext::getLocContext(const char* name)
+{
+    pthread_mutex_lock(&LocContext::mGetLocContextMutex);
+    LOC_LOGD("%s:%d]: querying ContextBase with tCreator", __func__, __LINE__);
+    if (NULL == mContext) {
+        LOC_LOGD("%s:%d]: creating msgTask with tCreator", __func__, __LINE__);
+        const MsgTask* msgTask = getMsgTask(name);
+        mContext = new LocContext(msgTask);
+    }
+    pthread_mutex_unlock(&LocContext::mGetLocContextMutex);
+
+    return mContext;
+}
+
+void LocContext :: injectFeatureConfig(ContextBase *curContext)
+{
+    LOC_LOGD("%s:%d]: Calling LBSProxy (%p) to inject feature config",
+             __func__, __LINE__, ((LocContext *)curContext)->mLBSProxy);
+    ((LocContext *)curContext)->mLBSProxy->injectFeatureConfig(curContext);
+}
+
+LocContext::LocContext(const MsgTask* msgTask) :
+    ContextBase(msgTask, 0, mLBSLibName)
+{
+}
+
+}
diff --git a/gps/core/LocContext.h b/gps/core/LocContext.h
new file mode 100644
index 0000000..628ed93
--- /dev/null
+++ b/gps/core/LocContext.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2011-2014, 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __LOC_CONTEXT__
+#define __LOC_CONTEXT__
+
+#include <stdbool.h>
+#include <ctype.h>
+#include <dlfcn.h>
+#include <ContextBase.h>
+
+namespace loc_core {
+
+class LocContext : public ContextBase {
+    static const MsgTask* mMsgTask;
+    static ContextBase* mContext;
+    static const MsgTask* getMsgTask(const char* name);
+    static pthread_mutex_t mGetLocContextMutex;
+
+protected:
+    LocContext(const MsgTask* msgTask);
+    inline virtual ~LocContext() {}
+
+public:
+    static const char* mLBSLibName;
+    static const char* mLocationHalName;
+
+    static ContextBase* getLocContext(const char* name);
+
+    static void injectFeatureConfig(ContextBase *context);
+};
+
+}
+
+#endif //__LOC_CONTEXT__
diff --git a/gps/core/Makefile.am b/gps/core/Makefile.am
new file mode 100644
index 0000000..291dbb5
--- /dev/null
+++ b/gps/core/Makefile.am
@@ -0,0 +1,74 @@
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CFLAGS = -I./ \
+            $(LOCPLA_CFLAGS) \
+            $(GPSUTILS_CFLAGS) \
+            -I./data-items/ \
+            -I./data-items/common \
+            -I./observer \
+            -I$(WORKSPACE)/gps-noship/flp \
+            -D__func__=__PRETTY_FUNCTION__ \
+            -fno-short-enums \
+            -std=c++11
+
+libloc_core_la_h_sources = \
+           LocApiBase.h \
+           LocAdapterBase.h \
+           ContextBase.h \
+           LocContext.h \
+           LBSProxyBase.h \
+           loc_core_log.h \
+           LocAdapterProxyBase.h \
+           EngineHubProxyBase.h \
+           data-items/DataItemId.h \
+           data-items/IDataItemCore.h \
+           data-items/DataItemConcreteTypesBase.h \
+           observer/IDataItemObserver.h \
+           observer/IDataItemSubscription.h \
+           observer/IFrameworkActionReq.h \
+           observer/IOsObserver.h \
+           SystemStatusOsObserver.h \
+           SystemStatus.h
+
+libloc_core_la_c_sources = \
+           LocApiBase.cpp \
+           LocAdapterBase.cpp \
+           ContextBase.cpp \
+           LocContext.cpp \
+           loc_core_log.cpp \
+           data-items/DataItemsFactoryProxy.cpp \
+           SystemStatusOsObserver.cpp \
+           SystemStatus.cpp
+
+if USE_EXTERNAL_AP
+AM_CFLAGS += -DFEATURE_EXTERNAL_AP
+endif
+
+library_includedir = $(pkgincludedir)
+
+library_include_HEADERS = $(libloc_core_la_h_sources)
+
+libloc_core_la_SOURCES = $(libloc_core_la_c_sources)
+
+if USE_GLIB
+libloc_core_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+libloc_core_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
+libloc_core_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+libloc_core_la_CFLAGS = $(AM_CFLAGS)
+libloc_core_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0
+libloc_core_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+if USE_FEATURE_AUTOMOTIVE
+AM_CFLAGS += -DFEATURE_AUTOMOTIVE
+endif
+
+libloc_core_la_LIBADD = -ldl $(GPSUTILS_LIBS)
+
+#Create and Install libraries
+lib_LTLIBRARIES = libloc_core.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = loc-core.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/gps/core/SystemStatus.cpp b/gps/core/SystemStatus.cpp
new file mode 100644
index 0000000..fe11de0
--- /dev/null
+++ b/gps/core/SystemStatus.cpp
@@ -0,0 +1,1761 @@
+/* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_TAG "LocSvc_SystemStatus"
+
+#include <inttypes.h>
+#include <string>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <loc_pla.h>
+#include <log_util.h>
+#include <loc_nmea.h>
+#include <DataItemsFactoryProxy.h>
+#include <SystemStatus.h>
+#include <SystemStatusOsObserver.h>
+#include <DataItemConcreteTypesBase.h>
+
+namespace loc_core
+{
+
+/******************************************************************************
+ SystemStatusNmeaBase - base class for all NMEA parsers
+******************************************************************************/
+class SystemStatusNmeaBase
+{
+protected:
+    std::vector<std::string> mField;
+
+    SystemStatusNmeaBase(const char *str_in, uint32_t len_in)
+    {
+        // check size and talker
+        if (!loc_nmea_is_debug(str_in, len_in)) {
+            return;
+        }
+
+        std::string parser(str_in);
+        std::string::size_type index = 0;
+
+        // verify checksum field
+        index = parser.find("*");
+        if (index == std::string::npos) {
+            return;
+        }
+        parser[index] = ',';
+
+        // tokenize parser
+        while (1) {
+            std::string str;
+            index = parser.find(",");
+            if (index == std::string::npos) {
+                break;
+            }
+            str = parser.substr(0, index);
+            parser = parser.substr(index + 1);
+            mField.push_back(str);
+        }
+    }
+
+    virtual ~SystemStatusNmeaBase() { }
+
+public:
+    static const uint32_t NMEA_MINSIZE = DEBUG_NMEA_MINSIZE;
+    static const uint32_t NMEA_MAXSIZE = DEBUG_NMEA_MAXSIZE;
+};
+
+/******************************************************************************
+ SystemStatusPQWM1
+******************************************************************************/
+class SystemStatusPQWM1
+{
+public:
+    uint16_t mGpsWeek;    // x1
+    uint32_t mGpsTowMs;   // x2
+    uint8_t  mTimeValid;  // x3
+    uint8_t  mTimeSource; // x4
+    int32_t  mTimeUnc;    // x5
+    int32_t  mClockFreqBias; // x6
+    int32_t  mClockFreqBiasUnc; // x7
+    uint8_t  mXoState;    // x8
+    int32_t  mPgaGain;    // x9
+    uint32_t mGpsBpAmpI;  // xA
+    uint32_t mGpsBpAmpQ;  // xB
+    uint32_t mAdcI;       // xC
+    uint32_t mAdcQ;       // xD
+    uint32_t mJammerGps;  // xE
+    uint32_t mJammerGlo;  // xF
+    uint32_t mJammerBds;  // x10
+    uint32_t mJammerGal;  // x11
+    uint32_t mRecErrorRecovery; // x12
+    double   mAgcGps;     // x13
+    double   mAgcGlo;     // x14
+    double   mAgcBds;     // x15
+    double   mAgcGal;     // x16
+    int32_t  mLeapSeconds;// x17
+    int32_t  mLeapSecUnc; // x18
+    uint32_t mGloBpAmpI;  // x19
+    uint32_t mGloBpAmpQ;  // x1A
+    uint32_t mBdsBpAmpI;  // x1B
+    uint32_t mBdsBpAmpQ;  // x1C
+    uint32_t mGalBpAmpI;  // x1D
+    uint32_t mGalBpAmpQ;  // x1E
+    uint64_t mTimeUncNs;  // x1F
+};
+
+// parser
+class SystemStatusPQWM1parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eGpsWeek = 1,
+        eGpsTowMs = 2,
+        eTimeValid = 3,
+        eTimeSource = 4,
+        eTimeUnc = 5,
+        eClockFreqBias = 6,
+        eClockFreqBiasUnc = 7,
+        eXoState = 8,
+        ePgaGain = 9,
+        eGpsBpAmpI = 10,
+        eGpsBpAmpQ = 11,
+        eAdcI = 12,
+        eAdcQ = 13,
+        eJammerGps = 14,
+        eJammerGlo = 15,
+        eJammerBds = 16,
+        eJammerGal = 17,
+        eRecErrorRecovery = 18,
+        eAgcGps = 19,
+        eAgcGlo = 20,
+        eAgcBds = 21,
+        eAgcGal = 22,
+        eMax0 = eAgcGal,
+        eLeapSeconds = 23,
+        eLeapSecUnc = 24,
+        eGloBpAmpI = 25,
+        eGloBpAmpQ = 26,
+        eBdsBpAmpI = 27,
+        eBdsBpAmpQ = 28,
+        eGalBpAmpI = 29,
+        eGalBpAmpQ = 30,
+        eTimeUncNs = 31,
+        eMax
+    };
+    SystemStatusPQWM1 mM1;
+
+public:
+    inline uint16_t   getGpsWeek()    { return mM1.mGpsWeek; }
+    inline uint32_t   getGpsTowMs()   { return mM1.mGpsTowMs; }
+    inline uint8_t    getTimeValid()  { return mM1.mTimeValid; }
+    inline uint8_t    getTimeSource() { return mM1.mTimeSource; }
+    inline int32_t    getTimeUnc()    { return mM1.mTimeUnc; }
+    inline int32_t    getClockFreqBias() { return mM1.mClockFreqBias; }
+    inline int32_t    getClockFreqBiasUnc() { return mM1.mClockFreqBiasUnc; }
+    inline uint8_t    getXoState()    { return mM1.mXoState;}
+    inline int32_t    getPgaGain()    { return mM1.mPgaGain;          }
+    inline uint32_t   getGpsBpAmpI()  { return mM1.mGpsBpAmpI;        }
+    inline uint32_t   getGpsBpAmpQ()  { return mM1.mGpsBpAmpQ;        }
+    inline uint32_t   getAdcI()       { return mM1.mAdcI;             }
+    inline uint32_t   getAdcQ()       { return mM1.mAdcQ;             }
+    inline uint32_t   getJammerGps()  { return mM1.mJammerGps;        }
+    inline uint32_t   getJammerGlo()  { return mM1.mJammerGlo;        }
+    inline uint32_t   getJammerBds()  { return mM1.mJammerBds;        }
+    inline uint32_t   getJammerGal()  { return mM1.mJammerGal;        }
+    inline uint32_t   getAgcGps()     { return mM1.mAgcGps;           }
+    inline uint32_t   getAgcGlo()     { return mM1.mAgcGlo;           }
+    inline uint32_t   getAgcBds()     { return mM1.mAgcBds;           }
+    inline uint32_t   getAgcGal()     { return mM1.mAgcGal;           }
+    inline uint32_t   getRecErrorRecovery() { return mM1.mRecErrorRecovery; }
+    inline int32_t    getLeapSeconds(){ return mM1.mLeapSeconds; }
+    inline int32_t    getLeapSecUnc() { return mM1.mLeapSecUnc; }
+    inline uint32_t   getGloBpAmpI()  { return mM1.mGloBpAmpI; }
+    inline uint32_t   getGloBpAmpQ()  { return mM1.mGloBpAmpQ; }
+    inline uint32_t   getBdsBpAmpI()  { return mM1.mBdsBpAmpI; }
+    inline uint32_t   getBdsBpAmpQ()  { return mM1.mBdsBpAmpQ; }
+    inline uint32_t   getGalBpAmpI()  { return mM1.mGalBpAmpI; }
+    inline uint32_t   getGalBpAmpQ()  { return mM1.mGalBpAmpQ; }
+    inline uint64_t   getTimeUncNs()  { return mM1.mTimeUncNs; }
+
+    SystemStatusPQWM1parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        memset(&mM1, 0, sizeof(mM1));
+        if (mField.size() <= eMax0) {
+            LOC_LOGE("PQWM1parser - invalid size=%zu", mField.size());
+            mM1.mTimeValid = 0;
+            return;
+        }
+        mM1.mGpsWeek = atoi(mField[eGpsWeek].c_str());
+        mM1.mGpsTowMs = atoi(mField[eGpsTowMs].c_str());
+        mM1.mTimeValid = atoi(mField[eTimeValid].c_str());
+        mM1.mTimeSource = atoi(mField[eTimeSource].c_str());
+        mM1.mTimeUnc = atoi(mField[eTimeUnc].c_str());
+        mM1.mClockFreqBias = atoi(mField[eClockFreqBias].c_str());
+        mM1.mClockFreqBiasUnc = atoi(mField[eClockFreqBiasUnc].c_str());
+        mM1.mXoState = atoi(mField[eXoState].c_str());
+        mM1.mPgaGain = atoi(mField[ePgaGain].c_str());
+        mM1.mGpsBpAmpI = atoi(mField[eGpsBpAmpI].c_str());
+        mM1.mGpsBpAmpQ = atoi(mField[eGpsBpAmpQ].c_str());
+        mM1.mAdcI = atoi(mField[eAdcI].c_str());
+        mM1.mAdcQ = atoi(mField[eAdcQ].c_str());
+        mM1.mJammerGps = atoi(mField[eJammerGps].c_str());
+        mM1.mJammerGlo = atoi(mField[eJammerGlo].c_str());
+        mM1.mJammerBds = atoi(mField[eJammerBds].c_str());
+        mM1.mJammerGal = atoi(mField[eJammerGal].c_str());
+        mM1.mRecErrorRecovery = atoi(mField[eRecErrorRecovery].c_str());
+        mM1.mAgcGps = atof(mField[eAgcGps].c_str());
+        mM1.mAgcGlo = atof(mField[eAgcGlo].c_str());
+        mM1.mAgcBds = atof(mField[eAgcBds].c_str());
+        mM1.mAgcGal = atof(mField[eAgcGal].c_str());
+        if (mField.size() > eLeapSecUnc) {
+            mM1.mLeapSeconds = atoi(mField[eLeapSeconds].c_str());
+            mM1.mLeapSecUnc = atoi(mField[eLeapSecUnc].c_str());
+        }
+        if (mField.size() > eGalBpAmpQ) {
+            mM1.mGloBpAmpI = atoi(mField[eGloBpAmpI].c_str());
+            mM1.mGloBpAmpQ = atoi(mField[eGloBpAmpQ].c_str());
+            mM1.mBdsBpAmpI = atoi(mField[eBdsBpAmpI].c_str());
+            mM1.mBdsBpAmpQ = atoi(mField[eBdsBpAmpQ].c_str());
+            mM1.mGalBpAmpI = atoi(mField[eGalBpAmpI].c_str());
+            mM1.mGalBpAmpQ = atoi(mField[eGalBpAmpQ].c_str());
+        }
+        if (mField.size() > eTimeUncNs) {
+            mM1.mTimeUncNs = strtoull(mField[eTimeUncNs].c_str(), nullptr, 10);
+        }
+    }
+
+    inline SystemStatusPQWM1& get() { return mM1;} //getparser
+};
+
+/******************************************************************************
+ SystemStatusPQWP1
+******************************************************************************/
+class SystemStatusPQWP1
+{
+public:
+    uint8_t  mEpiValidity; // x4
+    float    mEpiLat;    // x5
+    float    mEpiLon;    // x6
+    float    mEpiAlt;    // x7
+    float    mEpiHepe;   // x8
+    float    mEpiAltUnc; // x9
+    uint8_t  mEpiSrc;    // x10
+};
+
+class SystemStatusPQWP1parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eEpiValidity = 2,
+        eEpiLat = 3,
+        eEpiLon = 4,
+        eEpiAlt = 5,
+        eEpiHepe = 6,
+        eEpiAltUnc = 7,
+        eEpiSrc = 8,
+        eMax
+    };
+    SystemStatusPQWP1 mP1;
+
+public:
+    inline uint8_t    getEpiValidity() { return mP1.mEpiValidity;      }
+    inline float      getEpiLat() { return mP1.mEpiLat;           }
+    inline float      getEpiLon() { return mP1.mEpiLon;           }
+    inline float      getEpiAlt() { return mP1.mEpiAlt;           }
+    inline float      getEpiHepe() { return mP1.mEpiHepe;          }
+    inline float      getEpiAltUnc() { return mP1.mEpiAltUnc;        }
+    inline uint8_t    getEpiSrc() { return mP1.mEpiSrc;           }
+
+    SystemStatusPQWP1parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP1, 0, sizeof(mP1));
+        mP1.mEpiValidity = strtol(mField[eEpiValidity].c_str(), NULL, 16);
+        mP1.mEpiLat = atof(mField[eEpiLat].c_str());
+        mP1.mEpiLon = atof(mField[eEpiLon].c_str());
+        mP1.mEpiAlt = atof(mField[eEpiAlt].c_str());
+        mP1.mEpiHepe = atoi(mField[eEpiHepe].c_str());
+        mP1.mEpiAltUnc = atof(mField[eEpiAltUnc].c_str());
+        mP1.mEpiSrc = atoi(mField[eEpiSrc].c_str());
+    }
+
+    inline SystemStatusPQWP1& get() { return mP1;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP2
+******************************************************************************/
+class SystemStatusPQWP2
+{
+public:
+    float    mBestLat;   // x4
+    float    mBestLon;   // x5
+    float    mBestAlt;   // x6
+    float    mBestHepe;  // x7
+    float    mBestAltUnc; // x8
+};
+
+class SystemStatusPQWP2parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eBestLat = 2,
+        eBestLon = 3,
+        eBestAlt = 4,
+        eBestHepe = 5,
+        eBestAltUnc = 6,
+        eMax
+    };
+    SystemStatusPQWP2 mP2;
+
+public:
+    inline float      getBestLat() { return mP2.mBestLat;          }
+    inline float      getBestLon() { return mP2.mBestLon;          }
+    inline float      getBestAlt() { return mP2.mBestAlt;          }
+    inline float      getBestHepe() { return mP2.mBestHepe;         }
+    inline float      getBestAltUnc() { return mP2.mBestAltUnc;       }
+
+    SystemStatusPQWP2parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP2, 0, sizeof(mP2));
+        mP2.mBestLat = atof(mField[eBestLat].c_str());
+        mP2.mBestLon = atof(mField[eBestLon].c_str());
+        mP2.mBestAlt = atof(mField[eBestAlt].c_str());
+        mP2.mBestHepe = atof(mField[eBestHepe].c_str());
+        mP2.mBestAltUnc = atof(mField[eBestAltUnc].c_str());
+    }
+
+    inline SystemStatusPQWP2& get() { return mP2;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP3
+******************************************************************************/
+class SystemStatusPQWP3
+{
+public:
+    uint8_t   mXtraValidMask;
+    uint32_t  mGpsXtraAge;
+    uint32_t  mGloXtraAge;
+    uint32_t  mBdsXtraAge;
+    uint32_t  mGalXtraAge;
+    uint32_t  mQzssXtraAge;
+    uint32_t  mNavicXtraAge;
+    uint32_t  mGpsXtraValid;
+    uint32_t  mGloXtraValid;
+    uint64_t  mBdsXtraValid;
+    uint64_t  mGalXtraValid;
+    uint8_t   mQzssXtraValid;
+    uint32_t  mNavicXtraValid;
+};
+
+class SystemStatusPQWP3parser : public SystemStatusNmeaBase
+{
+private:
+    // todo: update for navic once available
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eXtraValidMask = 2,
+        eGpsXtraAge = 3,
+        eGloXtraAge = 4,
+        eBdsXtraAge = 5,
+        eGalXtraAge = 6,
+        eQzssXtraAge = 7,
+        eGpsXtraValid = 8,
+        eGloXtraValid = 9,
+        eBdsXtraValid = 10,
+        eGalXtraValid = 11,
+        eQzssXtraValid = 12,
+        eMax
+    };
+    SystemStatusPQWP3 mP3;
+
+public:
+    inline uint8_t    getXtraValid() { return mP3.mXtraValidMask;   }
+    inline uint32_t   getGpsXtraAge() { return mP3.mGpsXtraAge;       }
+    inline uint32_t   getGloXtraAge() { return mP3.mGloXtraAge;       }
+    inline uint32_t   getBdsXtraAge() { return mP3.mBdsXtraAge;       }
+    inline uint32_t   getGalXtraAge() { return mP3.mGalXtraAge;       }
+    inline uint32_t   getQzssXtraAge() { return mP3.mQzssXtraAge;      }
+    inline uint32_t   getNavicXtraAge() { return mP3.mNavicXtraAge;     }
+    inline uint32_t   getGpsXtraValid() { return mP3.mGpsXtraValid;     }
+    inline uint32_t   getGloXtraValid() { return mP3.mGloXtraValid;     }
+    inline uint64_t   getBdsXtraValid() { return mP3.mBdsXtraValid;     }
+    inline uint64_t   getGalXtraValid() { return mP3.mGalXtraValid;     }
+    inline uint8_t    getQzssXtraValid() { return mP3.mQzssXtraValid;    }
+    inline uint32_t   getNavicXtraValid() { return mP3.mNavicXtraValid;     }
+
+    SystemStatusPQWP3parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP3, 0, sizeof(mP3));
+        // todo: update for navic once available
+        mP3.mXtraValidMask = strtol(mField[eXtraValidMask].c_str(), NULL, 16);
+        mP3.mGpsXtraAge = atoi(mField[eGpsXtraAge].c_str());
+        mP3.mGloXtraAge = atoi(mField[eGloXtraAge].c_str());
+        mP3.mBdsXtraAge = atoi(mField[eBdsXtraAge].c_str());
+        mP3.mGalXtraAge = atoi(mField[eGalXtraAge].c_str());
+        mP3.mQzssXtraAge = atoi(mField[eQzssXtraAge].c_str());
+        mP3.mGpsXtraValid = strtol(mField[eGpsXtraValid].c_str(), NULL, 16);
+        mP3.mGloXtraValid = strtol(mField[eGloXtraValid].c_str(), NULL, 16);
+        mP3.mBdsXtraValid = strtol(mField[eBdsXtraValid].c_str(), NULL, 16);
+        mP3.mGalXtraValid = strtol(mField[eGalXtraValid].c_str(), NULL, 16);
+        mP3.mQzssXtraValid = strtol(mField[eQzssXtraValid].c_str(), NULL, 16);
+    }
+
+    inline SystemStatusPQWP3& get() { return mP3;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP4
+******************************************************************************/
+class SystemStatusPQWP4
+{
+public:
+    uint32_t  mGpsEpheValid;
+    uint32_t  mGloEpheValid;
+    uint64_t  mBdsEpheValid;
+    uint64_t  mGalEpheValid;
+    uint8_t   mQzssEpheValid;
+};
+
+class SystemStatusPQWP4parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eGpsEpheValid = 2,
+        eGloEpheValid = 3,
+        eBdsEpheValid = 4,
+        eGalEpheValid = 5,
+        eQzssEpheValid = 6,
+        eMax
+    };
+    SystemStatusPQWP4 mP4;
+
+public:
+    inline uint32_t   getGpsEpheValid() { return mP4.mGpsEpheValid;     }
+    inline uint32_t   getGloEpheValid() { return mP4.mGloEpheValid;     }
+    inline uint64_t   getBdsEpheValid() { return mP4.mBdsEpheValid;     }
+    inline uint64_t   getGalEpheValid() { return mP4.mGalEpheValid;     }
+    inline uint8_t    getQzssEpheValid() { return mP4.mQzssEpheValid;    }
+
+    SystemStatusPQWP4parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP4, 0, sizeof(mP4));
+        mP4.mGpsEpheValid = strtol(mField[eGpsEpheValid].c_str(), NULL, 16);
+        mP4.mGloEpheValid = strtol(mField[eGloEpheValid].c_str(), NULL, 16);
+        mP4.mBdsEpheValid = strtol(mField[eBdsEpheValid].c_str(), NULL, 16);
+        mP4.mGalEpheValid = strtol(mField[eGalEpheValid].c_str(), NULL, 16);
+        mP4.mQzssEpheValid = strtol(mField[eQzssEpheValid].c_str(), NULL, 16);
+    }
+
+    inline SystemStatusPQWP4& get() { return mP4;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP5
+******************************************************************************/
+class SystemStatusPQWP5
+{
+public:
+    uint32_t  mGpsUnknownMask;
+    uint32_t  mGloUnknownMask;
+    uint64_t  mBdsUnknownMask;
+    uint64_t  mGalUnknownMask;
+    uint8_t   mQzssUnknownMask;
+    uint32_t  mNavicUnknownMask;
+    uint32_t  mGpsGoodMask;
+    uint32_t  mGloGoodMask;
+    uint64_t  mBdsGoodMask;
+    uint64_t  mGalGoodMask;
+    uint8_t   mQzssGoodMask;
+    uint32_t  mNavicGoodMask;
+    uint32_t  mGpsBadMask;
+    uint32_t  mGloBadMask;
+    uint64_t  mBdsBadMask;
+    uint64_t  mGalBadMask;
+    uint8_t   mQzssBadMask;
+    uint32_t  mNavicBadMask;
+};
+
+class SystemStatusPQWP5parser : public SystemStatusNmeaBase
+{
+private:
+    // todo: update for navic once available
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eGpsUnknownMask = 2,
+        eGloUnknownMask = 3,
+        eBdsUnknownMask = 4,
+        eGalUnknownMask = 5,
+        eQzssUnknownMask = 6,
+        eGpsGoodMask = 7,
+        eGloGoodMask = 8,
+        eBdsGoodMask = 9,
+        eGalGoodMask = 10,
+        eQzssGoodMask = 11,
+        eGpsBadMask = 12,
+        eGloBadMask = 13,
+        eBdsBadMask = 14,
+        eGalBadMask = 15,
+        eQzssBadMask = 16,
+        eMax
+    };
+    SystemStatusPQWP5 mP5;
+
+public:
+    inline uint32_t   getGpsUnknownMask() { return mP5.mGpsUnknownMask;   }
+    inline uint32_t   getGloUnknownMask() { return mP5.mGloUnknownMask;   }
+    inline uint64_t   getBdsUnknownMask() { return mP5.mBdsUnknownMask;   }
+    inline uint64_t   getGalUnknownMask() { return mP5.mGalUnknownMask;   }
+    inline uint8_t    getQzssUnknownMask() { return mP5.mQzssUnknownMask;  }
+    inline uint32_t   getNavicUnknownMask() { return mP5.mNavicUnknownMask;   }
+    inline uint32_t   getGpsGoodMask() { return mP5.mGpsGoodMask;      }
+    inline uint32_t   getGloGoodMask() { return mP5.mGloGoodMask;      }
+    inline uint64_t   getBdsGoodMask() { return mP5.mBdsGoodMask;      }
+    inline uint64_t   getGalGoodMask() { return mP5.mGalGoodMask;      }
+    inline uint8_t    getQzssGoodMask() { return mP5.mQzssGoodMask;     }
+    inline uint32_t   getNavicGoodMask() { return mP5.mNavicGoodMask;      }
+    inline uint32_t   getGpsBadMask() { return mP5.mGpsBadMask;       }
+    inline uint32_t   getGloBadMask() { return mP5.mGloBadMask;       }
+    inline uint64_t   getBdsBadMask() { return mP5.mBdsBadMask;       }
+    inline uint64_t   getGalBadMask() { return mP5.mGalBadMask;       }
+    inline uint8_t    getQzssBadMask() { return mP5.mQzssBadMask;      }
+    inline uint32_t   getNavicBadMask() { return mP5.mNavicBadMask;       }
+
+    SystemStatusPQWP5parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP5, 0, sizeof(mP5));
+        // todo: update for navic once available
+        mP5.mGpsUnknownMask = strtol(mField[eGpsUnknownMask].c_str(), NULL, 16);
+        mP5.mGloUnknownMask = strtol(mField[eGloUnknownMask].c_str(), NULL, 16);
+        mP5.mBdsUnknownMask = strtol(mField[eBdsUnknownMask].c_str(), NULL, 16);
+        mP5.mGalUnknownMask = strtol(mField[eGalUnknownMask].c_str(), NULL, 16);
+        mP5.mQzssUnknownMask = strtol(mField[eQzssUnknownMask].c_str(), NULL, 16);
+        mP5.mGpsGoodMask = strtol(mField[eGpsGoodMask].c_str(), NULL, 16);
+        mP5.mGloGoodMask = strtol(mField[eGloGoodMask].c_str(), NULL, 16);
+        mP5.mBdsGoodMask = strtol(mField[eBdsGoodMask].c_str(), NULL, 16);
+        mP5.mGalGoodMask = strtol(mField[eGalGoodMask].c_str(), NULL, 16);
+        mP5.mQzssGoodMask = strtol(mField[eQzssGoodMask].c_str(), NULL, 16);
+        mP5.mGpsBadMask = strtol(mField[eGpsBadMask].c_str(), NULL, 16);
+        mP5.mGloBadMask = strtol(mField[eGloBadMask].c_str(), NULL, 16);
+        mP5.mBdsBadMask = strtol(mField[eBdsBadMask].c_str(), NULL, 16);
+        mP5.mGalBadMask = strtol(mField[eGalBadMask].c_str(), NULL, 16);
+        mP5.mQzssBadMask = strtol(mField[eQzssBadMask].c_str(), NULL, 16);
+    }
+
+    inline SystemStatusPQWP5& get() { return mP5;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP6parser
+******************************************************************************/
+class SystemStatusPQWP6
+{
+public:
+    uint32_t  mFixInfoMask;
+};
+
+class SystemStatusPQWP6parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eFixInfoMask = 2,
+        eMax
+    };
+    SystemStatusPQWP6 mP6;
+
+public:
+    inline uint32_t   getFixInfoMask() { return mP6.mFixInfoMask;      }
+
+    SystemStatusPQWP6parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mP6, 0, sizeof(mP6));
+        mP6.mFixInfoMask = strtol(mField[eFixInfoMask].c_str(), NULL, 16);
+    }
+
+    inline SystemStatusPQWP6& get() { return mP6;}
+};
+
+/******************************************************************************
+ SystemStatusPQWP7parser
+******************************************************************************/
+class SystemStatusPQWP7
+{
+public:
+    SystemStatusNav mNav[SV_ALL_NUM];
+};
+
+class SystemStatusPQWP7parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eMin = 2 + SV_ALL_NUM_MIN*3,
+        eMax = 2 + SV_ALL_NUM*3
+    };
+    SystemStatusPQWP7 mP7;
+
+public:
+    SystemStatusPQWP7parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        uint32_t svLimit = SV_ALL_NUM;
+        if (mField.size() < eMin) {
+            LOC_LOGE("PQWP7parser - invalid size=%zu", mField.size());
+            return;
+        }
+        if (mField.size() < eMax) {
+            // Try reducing limit, accounting for possibly missing NAVIC support
+            svLimit = SV_ALL_NUM_MIN;
+        }
+
+        memset(mP7.mNav, 0, sizeof(mP7.mNav));
+        for (uint32_t i=0; i<svLimit; i++) {
+            mP7.mNav[i].mType   = GnssEphemerisType(atoi(mField[i*3+2].c_str()));
+            mP7.mNav[i].mSource = GnssEphemerisSource(atoi(mField[i*3+3].c_str()));
+            mP7.mNav[i].mAgeSec = atoi(mField[i*3+4].c_str());
+        }
+    }
+
+    inline SystemStatusPQWP7& get() { return mP7;}
+};
+
+/******************************************************************************
+ SystemStatusPQWS1parser
+******************************************************************************/
+class SystemStatusPQWS1
+{
+public:
+    uint32_t  mFixInfoMask;
+    uint32_t  mHepeLimit;
+};
+
+class SystemStatusPQWS1parser : public SystemStatusNmeaBase
+{
+private:
+    enum
+    {
+        eTalker = 0,
+        eUtcTime = 1,
+        eFixInfoMask = 2,
+        eHepeLimit = 3,
+        eMax
+    };
+    SystemStatusPQWS1 mS1;
+
+public:
+    inline uint16_t   getFixInfoMask() { return mS1.mFixInfoMask;      }
+    inline uint32_t   getHepeLimit()   { return mS1.mHepeLimit;      }
+
+    SystemStatusPQWS1parser(const char *str_in, uint32_t len_in)
+        : SystemStatusNmeaBase(str_in, len_in)
+    {
+        if (mField.size() < eMax) {
+            return;
+        }
+        memset(&mS1, 0, sizeof(mS1));
+        mS1.mFixInfoMask = atoi(mField[eFixInfoMask].c_str());
+        mS1.mHepeLimit = atoi(mField[eHepeLimit].c_str());
+    }
+
+    inline SystemStatusPQWS1& get() { return mS1;}
+};
+
+/******************************************************************************
+ SystemStatusTimeAndClock
+******************************************************************************/
+SystemStatusTimeAndClock::SystemStatusTimeAndClock(const SystemStatusPQWM1& nmea) :
+    mGpsWeek(nmea.mGpsWeek),
+    mGpsTowMs(nmea.mGpsTowMs),
+    mTimeValid(nmea.mTimeValid),
+    mTimeSource(nmea.mTimeSource),
+    mTimeUnc(nmea.mTimeUnc),
+    mClockFreqBias(nmea.mClockFreqBias),
+    mClockFreqBiasUnc(nmea.mClockFreqBiasUnc),
+    mLeapSeconds(nmea.mLeapSeconds),
+    mLeapSecUnc(nmea.mLeapSecUnc),
+    mTimeUncNs(nmea.mTimeUncNs)
+{
+}
+
+bool SystemStatusTimeAndClock::equals(const SystemStatusTimeAndClock& peer)
+{
+    if ((mGpsWeek != peer.mGpsWeek) ||
+        (mGpsTowMs != peer.mGpsTowMs) ||
+        (mTimeValid != peer.mTimeValid) ||
+        (mTimeSource != peer.mTimeSource) ||
+        (mTimeUnc != peer.mTimeUnc) ||
+        (mClockFreqBias != peer.mClockFreqBias) ||
+        (mClockFreqBiasUnc != peer.mClockFreqBiasUnc) ||
+        (mLeapSeconds != peer.mLeapSeconds) ||
+        (mLeapSecUnc != peer.mLeapSecUnc) ||
+        (mTimeUncNs != peer.mTimeUncNs)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusTimeAndClock::dump()
+{
+    LOC_LOGV("TimeAndClock: u=%ld:%ld g=%d:%d v=%d ts=%d tu=%d b=%d bu=%d ls=%d lu=%d un=%" PRIu64,
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mGpsWeek,
+             mGpsTowMs,
+             mTimeValid,
+             mTimeSource,
+             mTimeUnc,
+             mClockFreqBias,
+             mClockFreqBiasUnc,
+             mLeapSeconds,
+             mLeapSecUnc,
+             mTimeUncNs);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusXoState
+******************************************************************************/
+SystemStatusXoState::SystemStatusXoState(const SystemStatusPQWM1& nmea) :
+    mXoState(nmea.mXoState)
+{
+}
+
+bool SystemStatusXoState::equals(const SystemStatusXoState& peer)
+{
+    if (mXoState != peer.mXoState) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusXoState::dump()
+{
+    LOC_LOGV("XoState: u=%ld:%ld x=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mXoState);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusRfAndParams
+******************************************************************************/
+SystemStatusRfAndParams::SystemStatusRfAndParams(const SystemStatusPQWM1& nmea) :
+    mPgaGain(nmea.mPgaGain),
+    mGpsBpAmpI(nmea.mGpsBpAmpI),
+    mGpsBpAmpQ(nmea.mGpsBpAmpQ),
+    mAdcI(nmea.mAdcI),
+    mAdcQ(nmea.mAdcQ),
+    mJammerGps(nmea.mJammerGps),
+    mJammerGlo(nmea.mJammerGlo),
+    mJammerBds(nmea.mJammerBds),
+    mJammerGal(nmea.mJammerGal),
+    mAgcGps(nmea.mAgcGps),
+    mAgcGlo(nmea.mAgcGlo),
+    mAgcBds(nmea.mAgcBds),
+    mAgcGal(nmea.mAgcGal),
+    mGloBpAmpI(nmea.mGloBpAmpI),
+    mGloBpAmpQ(nmea.mGloBpAmpQ),
+    mBdsBpAmpI(nmea.mBdsBpAmpI),
+    mBdsBpAmpQ(nmea.mBdsBpAmpQ),
+    mGalBpAmpI(nmea.mGalBpAmpI),
+    mGalBpAmpQ(nmea.mGalBpAmpQ)
+{
+}
+
+bool SystemStatusRfAndParams::equals(const SystemStatusRfAndParams& peer)
+{
+    if ((mPgaGain != peer.mPgaGain) ||
+        (mGpsBpAmpI != peer.mGpsBpAmpI) ||
+        (mGpsBpAmpQ != peer.mGpsBpAmpQ) ||
+        (mAdcI != peer.mAdcI) ||
+        (mAdcQ != peer.mAdcQ) ||
+        (mJammerGps != peer.mJammerGps) ||
+        (mJammerGlo != peer.mJammerGlo) ||
+        (mJammerBds != peer.mJammerBds) ||
+        (mJammerGal != peer.mJammerGal) ||
+        (mAgcGps != peer.mAgcGps) ||
+        (mAgcGlo != peer.mAgcGlo) ||
+        (mAgcBds != peer.mAgcBds) ||
+        (mAgcGal != peer.mAgcGal) ||
+        (mGloBpAmpI != peer.mGloBpAmpI) ||
+        (mGloBpAmpQ != peer.mGloBpAmpQ) ||
+        (mBdsBpAmpI != peer.mBdsBpAmpI) ||
+        (mBdsBpAmpQ != peer.mBdsBpAmpQ) ||
+        (mGalBpAmpI != peer.mGalBpAmpI) ||
+        (mGalBpAmpQ != peer.mGalBpAmpQ)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusRfAndParams::dump()
+{
+    LOC_LOGV("RfAndParams: u=%ld:%ld p=%d bi=%d bq=%d ai=%d aq=%d "
+             "jgp=%d jgl=%d jbd=%d jga=%d "
+             "agp=%lf agl=%lf abd=%lf aga=%lf",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mPgaGain,
+             mGpsBpAmpI,
+             mGpsBpAmpQ,
+             mAdcI,
+             mAdcQ,
+             mJammerGps,
+             mJammerGlo,
+             mJammerBds,
+             mJammerGal,
+             mAgcGps,
+             mAgcGlo,
+             mAgcBds,
+             mAgcGal);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusErrRecovery
+******************************************************************************/
+SystemStatusErrRecovery::SystemStatusErrRecovery(const SystemStatusPQWM1& nmea) :
+    mRecErrorRecovery(nmea.mRecErrorRecovery)
+{
+}
+
+bool SystemStatusErrRecovery::equals(const SystemStatusErrRecovery& peer)
+{
+    if (mRecErrorRecovery != peer.mRecErrorRecovery) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusErrRecovery::dump()
+{
+    LOC_LOGV("ErrRecovery: u=%ld:%ld e=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mRecErrorRecovery);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusInjectedPosition
+******************************************************************************/
+SystemStatusInjectedPosition::SystemStatusInjectedPosition(const SystemStatusPQWP1& nmea) :
+    mEpiValidity(nmea.mEpiValidity),
+    mEpiLat(nmea.mEpiLat),
+    mEpiLon(nmea.mEpiLon),
+    mEpiAlt(nmea.mEpiAlt),
+    mEpiHepe(nmea.mEpiHepe),
+    mEpiAltUnc(nmea.mEpiAltUnc),
+    mEpiSrc(nmea.mEpiSrc)
+{
+}
+
+bool SystemStatusInjectedPosition::equals(const SystemStatusInjectedPosition& peer)
+{
+    if ((mEpiValidity != peer.mEpiValidity) ||
+        (mEpiLat != peer.mEpiLat) ||
+        (mEpiLon != peer.mEpiLon) ||
+        (mEpiAlt != peer.mEpiAlt) ||
+        (mEpiHepe != peer.mEpiHepe) ||
+        (mEpiAltUnc != peer.mEpiAltUnc) ||
+        (mEpiSrc != peer.mEpiSrc)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusInjectedPosition::dump()
+{
+    LOC_LOGV("InjectedPosition: u=%ld:%ld v=%x la=%f lo=%f al=%f he=%f au=%f es=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mEpiValidity,
+             mEpiLat,
+             mEpiLon,
+             mEpiAlt,
+             mEpiHepe,
+             mEpiAltUnc,
+             mEpiSrc);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusBestPosition
+******************************************************************************/
+SystemStatusBestPosition::SystemStatusBestPosition(const SystemStatusPQWP2& nmea) :
+    mValid(true),
+    mBestLat(nmea.mBestLat),
+    mBestLon(nmea.mBestLon),
+    mBestAlt(nmea.mBestAlt),
+    mBestHepe(nmea.mBestHepe),
+    mBestAltUnc(nmea.mBestAltUnc)
+{
+}
+
+bool SystemStatusBestPosition::equals(const SystemStatusBestPosition& peer)
+{
+    if ((mBestLat != peer.mBestLat) ||
+        (mBestLon != peer.mBestLon) ||
+        (mBestAlt != peer.mBestAlt) ||
+        (mBestHepe != peer.mBestHepe) ||
+        (mBestAltUnc != peer.mBestAltUnc)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusBestPosition::dump()
+{
+    LOC_LOGV("BestPosition: u=%ld:%ld la=%f lo=%f al=%f he=%f au=%f",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mBestLat,
+             mBestLon,
+             mBestAlt,
+             mBestHepe,
+             mBestAltUnc);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusXtra
+******************************************************************************/
+SystemStatusXtra::SystemStatusXtra(const SystemStatusPQWP3& nmea) :
+    mXtraValidMask(nmea.mXtraValidMask),
+    mGpsXtraAge(nmea.mGpsXtraAge),
+    mGloXtraAge(nmea.mGloXtraAge),
+    mBdsXtraAge(nmea.mBdsXtraAge),
+    mGalXtraAge(nmea.mGalXtraAge),
+    mQzssXtraAge(nmea.mQzssXtraAge),
+    mNavicXtraAge(nmea.mNavicXtraAge),
+    mGpsXtraValid(nmea.mGpsXtraValid),
+    mGloXtraValid(nmea.mGloXtraValid),
+    mBdsXtraValid(nmea.mBdsXtraValid),
+    mGalXtraValid(nmea.mGalXtraValid),
+    mQzssXtraValid(nmea.mQzssXtraValid),
+    mNavicXtraValid(nmea.mNavicXtraValid)
+{
+}
+
+bool SystemStatusXtra::equals(const SystemStatusXtra& peer)
+{
+    if ((mXtraValidMask != peer.mXtraValidMask) ||
+        (mGpsXtraAge != peer.mGpsXtraAge) ||
+        (mGloXtraAge != peer.mGloXtraAge) ||
+        (mBdsXtraAge != peer.mBdsXtraAge) ||
+        (mGalXtraAge != peer.mGalXtraAge) ||
+        (mQzssXtraAge != peer.mQzssXtraAge) ||
+        (mNavicXtraAge != peer.mNavicXtraAge) ||
+        (mGpsXtraValid != peer.mGpsXtraValid) ||
+        (mGloXtraValid != peer.mGloXtraValid) ||
+        (mBdsXtraValid != peer.mBdsXtraValid) ||
+        (mGalXtraValid != peer.mGalXtraValid) ||
+        (mQzssXtraValid != peer.mQzssXtraValid) ||
+        (mNavicXtraValid != peer.mNavicXtraValid)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusXtra::dump()
+{
+    LOC_LOGV("SystemStatusXtra: u=%ld:%ld m=%x a=%d:%d:%d:%d:%d v=%x:%x:%" PRIx64 ":%" PRIx64":%x",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mXtraValidMask,
+             mGpsXtraAge,
+             mGloXtraAge,
+             mBdsXtraAge,
+             mGalXtraAge,
+             mQzssXtraAge,
+             mGpsXtraValid,
+             mGloXtraValid,
+             mBdsXtraValid,
+             mGalXtraValid,
+             mQzssXtraValid);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusEphemeris
+******************************************************************************/
+SystemStatusEphemeris::SystemStatusEphemeris(const SystemStatusPQWP4& nmea) :
+    mGpsEpheValid(nmea.mGpsEpheValid),
+    mGloEpheValid(nmea.mGloEpheValid),
+    mBdsEpheValid(nmea.mBdsEpheValid),
+    mGalEpheValid(nmea.mGalEpheValid),
+    mQzssEpheValid(nmea.mQzssEpheValid)
+{
+}
+
+bool SystemStatusEphemeris::equals(const SystemStatusEphemeris& peer)
+{
+    if ((mGpsEpheValid != peer.mGpsEpheValid) ||
+        (mGloEpheValid != peer.mGloEpheValid) ||
+        (mBdsEpheValid != peer.mBdsEpheValid) ||
+        (mGalEpheValid != peer.mGalEpheValid) ||
+        (mQzssEpheValid != peer.mQzssEpheValid)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusEphemeris::dump()
+{
+    LOC_LOGV("Ephemeris: u=%ld:%ld ev=%x:%x:%" PRIx64 ":%" PRIx64 ":%x",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mGpsEpheValid,
+             mGloEpheValid,
+             mBdsEpheValid,
+             mGalEpheValid,
+             mQzssEpheValid);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusSvHealth
+******************************************************************************/
+SystemStatusSvHealth::SystemStatusSvHealth(const SystemStatusPQWP5& nmea) :
+    mGpsUnknownMask(nmea.mGpsUnknownMask),
+    mGloUnknownMask(nmea.mGloUnknownMask),
+    mBdsUnknownMask(nmea.mBdsUnknownMask),
+    mGalUnknownMask(nmea.mGalUnknownMask),
+    mQzssUnknownMask(nmea.mQzssUnknownMask),
+    mNavicUnknownMask(nmea.mNavicUnknownMask),
+    mGpsGoodMask(nmea.mGpsGoodMask),
+    mGloGoodMask(nmea.mGloGoodMask),
+    mBdsGoodMask(nmea.mBdsGoodMask),
+    mGalGoodMask(nmea.mGalGoodMask),
+    mQzssGoodMask(nmea.mQzssGoodMask),
+    mNavicGoodMask(nmea.mNavicGoodMask),
+    mGpsBadMask(nmea.mGpsBadMask),
+    mGloBadMask(nmea.mGloBadMask),
+    mBdsBadMask(nmea.mBdsBadMask),
+    mGalBadMask(nmea.mGalBadMask),
+    mQzssBadMask(nmea.mQzssBadMask),
+    mNavicBadMask(nmea.mNavicBadMask)
+{
+}
+
+bool SystemStatusSvHealth::equals(const SystemStatusSvHealth& peer)
+{
+    if ((mGpsUnknownMask != peer.mGpsUnknownMask) ||
+        (mGloUnknownMask != peer.mGloUnknownMask) ||
+        (mBdsUnknownMask != peer.mBdsUnknownMask) ||
+        (mGalUnknownMask != peer.mGalUnknownMask) ||
+        (mQzssUnknownMask != peer.mQzssUnknownMask) ||
+        (mGpsGoodMask != peer.mGpsGoodMask) ||
+        (mGloGoodMask != peer.mGloGoodMask) ||
+        (mBdsGoodMask != peer.mBdsGoodMask) ||
+        (mGalGoodMask != peer.mGalGoodMask) ||
+        (mQzssGoodMask != peer.mQzssGoodMask) ||
+        (mGpsBadMask != peer.mGpsBadMask) ||
+        (mGloBadMask != peer.mGloBadMask) ||
+        (mBdsBadMask != peer.mBdsBadMask) ||
+        (mGalBadMask != peer.mGalBadMask) ||
+        (mQzssBadMask != peer.mQzssBadMask)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusSvHealth::dump()
+{
+    LOC_LOGV("SvHealth: u=%ld:%ld \
+             u=%x:%x:%" PRIx64 ":%" PRIx64 ":%x \
+             g=%x:%x:%" PRIx64 ":%" PRIx64 ":%x \
+             b=%x:%x:%" PRIx64 ":%" PRIx64 ":%x",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mGpsUnknownMask,
+             mGloUnknownMask,
+             mBdsUnknownMask,
+             mGalUnknownMask,
+             mQzssUnknownMask,
+             mGpsGoodMask,
+             mGloGoodMask,
+             mBdsGoodMask,
+             mGalGoodMask,
+             mQzssGoodMask,
+             mGpsBadMask,
+             mGloBadMask,
+             mBdsBadMask,
+             mGalBadMask,
+             mQzssBadMask);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusPdr
+******************************************************************************/
+SystemStatusPdr::SystemStatusPdr(const SystemStatusPQWP6& nmea) :
+    mFixInfoMask(nmea.mFixInfoMask)
+{
+}
+
+bool SystemStatusPdr::equals(const SystemStatusPdr& peer)
+{
+    if (mFixInfoMask != peer.mFixInfoMask) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusPdr::dump()
+{
+    LOC_LOGV("Pdr: u=%ld:%ld m=%x",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mFixInfoMask);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusNavData
+******************************************************************************/
+SystemStatusNavData::SystemStatusNavData(const SystemStatusPQWP7& nmea)
+{
+    for (uint32_t i=0; i<SV_ALL_NUM; i++) {
+        mNav[i] = nmea.mNav[i];
+    }
+}
+
+bool SystemStatusNavData::equals(const SystemStatusNavData& peer)
+{
+    for (uint32_t i=0; i<SV_ALL_NUM; i++) {
+        if ((mNav[i].mType != peer.mNav[i].mType) ||
+            (mNav[i].mSource != peer.mNav[i].mSource) ||
+            (mNav[i].mAgeSec != peer.mNav[i].mAgeSec)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void SystemStatusNavData::dump()
+{
+    LOC_LOGV("NavData: u=%ld:%ld",
+            mUtcTime.tv_sec, mUtcTime.tv_nsec);
+    for (uint32_t i=0; i<SV_ALL_NUM; i++) {
+        LOC_LOGV("i=%d type=%d src=%d age=%d",
+            i, mNav[i].mType, mNav[i].mSource, mNav[i].mAgeSec);
+    }
+    return;
+}
+
+/******************************************************************************
+ SystemStatusPositionFailure
+******************************************************************************/
+SystemStatusPositionFailure::SystemStatusPositionFailure(const SystemStatusPQWS1& nmea) :
+    mFixInfoMask(nmea.mFixInfoMask),
+    mHepeLimit(nmea.mHepeLimit)
+{
+}
+
+bool SystemStatusPositionFailure::equals(const SystemStatusPositionFailure& peer)
+{
+    if ((mFixInfoMask != peer.mFixInfoMask) ||
+        (mHepeLimit != peer.mHepeLimit)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusPositionFailure::dump()
+{
+    LOC_LOGV("PositionFailure: u=%ld:%ld m=%d h=%d",
+             mUtcTime.tv_sec, mUtcTime.tv_nsec,
+             mFixInfoMask,
+             mHepeLimit);
+    return;
+}
+
+/******************************************************************************
+ SystemStatusLocation
+******************************************************************************/
+bool SystemStatusLocation::equals(const SystemStatusLocation& peer)
+{
+    if ((mLocation.gpsLocation.latitude != peer.mLocation.gpsLocation.latitude) ||
+        (mLocation.gpsLocation.longitude != peer.mLocation.gpsLocation.longitude) ||
+        (mLocation.gpsLocation.altitude != peer.mLocation.gpsLocation.altitude)) {
+        return false;
+    }
+    return true;
+}
+
+void SystemStatusLocation::dump()
+{
+    LOC_LOGV("Location: lat=%f lon=%f alt=%f spd=%f",
+             mLocation.gpsLocation.latitude,
+             mLocation.gpsLocation.longitude,
+             mLocation.gpsLocation.altitude,
+             mLocation.gpsLocation.speed);
+    return;
+}
+
+/******************************************************************************
+ SystemStatus
+******************************************************************************/
+pthread_mutex_t   SystemStatus::mMutexSystemStatus = PTHREAD_MUTEX_INITIALIZER;
+SystemStatus*     SystemStatus::mInstance = NULL;
+
+SystemStatus* SystemStatus::getInstance(const MsgTask* msgTask)
+{
+    pthread_mutex_lock(&mMutexSystemStatus);
+
+    if (!mInstance) {
+        // Instantiating for the first time. msgTask should not be NULL
+        if (msgTask == NULL) {
+            LOC_LOGE("SystemStatus: msgTask is NULL!!");
+            pthread_mutex_unlock(&mMutexSystemStatus);
+            return NULL;
+        }
+        mInstance = new (nothrow) SystemStatus(msgTask);
+        LOC_LOGD("SystemStatus::getInstance:%p. Msgtask:%p", mInstance, msgTask);
+    }
+
+    pthread_mutex_unlock(&mMutexSystemStatus);
+    return mInstance;
+}
+
+void SystemStatus::destroyInstance()
+{
+    delete mInstance;
+    mInstance = NULL;
+}
+
+void SystemStatus::resetNetworkInfo() {
+    for (int i=0; i<mCache.mNetworkInfo.size(); ++i) {
+        // Reset all the cached NetworkInfo Items as disconnected
+        eventConnectionStatus(false, mCache.mNetworkInfo[i].mType, mCache.mNetworkInfo[i].mRoaming,
+                mCache.mNetworkInfo[i].mNetworkHandle, mCache.mNetworkInfo[i].mApn);
+    }
+}
+
+IOsObserver* SystemStatus::getOsObserver()
+{
+    return &mSysStatusObsvr;
+}
+
+SystemStatus::SystemStatus(const MsgTask* msgTask) :
+    mSysStatusObsvr(this, msgTask)
+{
+    int result = 0;
+    ENTRY_LOG ();
+    mCache.mLocation.clear();
+
+    mCache.mTimeAndClock.clear();
+    mCache.mXoState.clear();
+    mCache.mRfAndParams.clear();
+    mCache.mErrRecovery.clear();
+
+    mCache.mInjectedPosition.clear();
+    mCache.mBestPosition.clear();
+    mCache.mXtra.clear();
+    mCache.mEphemeris.clear();
+    mCache.mSvHealth.clear();
+    mCache.mPdr.clear();
+    mCache.mNavData.clear();
+
+    mCache.mPositionFailure.clear();
+
+    mCache.mAirplaneMode.clear();
+    mCache.mENH.clear();
+    mCache.mGPSState.clear();
+    mCache.mNLPStatus.clear();
+    mCache.mWifiHardwareState.clear();
+    mCache.mNetworkInfo.clear();
+    mCache.mRilServiceInfo.clear();
+    mCache.mRilCellInfo.clear();
+    mCache.mServiceStatus.clear();
+    mCache.mModel.clear();
+    mCache.mManufacturer.clear();
+    mCache.mAssistedGps.clear();
+    mCache.mScreenState.clear();
+    mCache.mPowerConnectState.clear();
+    mCache.mTimeZoneChange.clear();
+    mCache.mTimeChange.clear();
+    mCache.mWifiSupplicantStatus.clear();
+    mCache.mShutdownState.clear();
+    mCache.mTac.clear();
+    mCache.mMccMnc.clear();
+    mCache.mBtDeviceScanDetail.clear();
+    mCache.mBtLeDeviceScanDetail.clear();
+
+    EXIT_LOG_WITH_ERROR ("%d",result);
+}
+
+/******************************************************************************
+ SystemStatus - storing dataitems
+******************************************************************************/
+template <typename TYPE_REPORT, typename TYPE_ITEM>
+bool SystemStatus::setIteminReport(TYPE_REPORT& report, TYPE_ITEM&& s)
+{
+    if (s.ignore()) {
+        return false;
+    }
+    if (!report.empty() && report.back().equals(static_cast<TYPE_ITEM&>(s.collate(report.back())))) {
+        // there is no change - just update reported timestamp
+        report.back().mUtcReported = s.mUtcReported;
+        return false;
+    }
+
+    // first event or updated
+    report.push_back(s);
+    if (report.size() > s.maxItem) {
+        report.erase(report.begin());
+    }
+    return true;
+}
+
+template <typename TYPE_REPORT, typename TYPE_ITEM>
+void SystemStatus::setDefaultIteminReport(TYPE_REPORT& report, const TYPE_ITEM& s)
+{
+    report.push_back(s);
+    if (report.size() > s.maxItem) {
+        report.erase(report.begin());
+    }
+}
+
+template <typename TYPE_REPORT, typename TYPE_ITEM>
+void SystemStatus::getIteminReport(TYPE_REPORT& reportout, const TYPE_ITEM& c) const
+{
+    reportout.clear();
+    if (c.size() >= 1) {
+        reportout.push_back(c.back());
+        reportout.back().dump();
+    }
+}
+
+/******************************************************************************
+@brief      API to set report data into internal buffer
+
+@param[In]  data pointer to the NMEA string
+@param[In]  len  length of the NMEA string
+
+@return     true when the NMEA is consumed by the method.
+******************************************************************************/
+bool SystemStatus::setNmeaString(const char *data, uint32_t len)
+{
+    if (!loc_nmea_is_debug(data, len)) {
+        return false;
+    }
+
+    char buf[SystemStatusNmeaBase::NMEA_MAXSIZE + 1] = { 0 };
+    strlcpy(buf, data, sizeof(buf));
+
+    pthread_mutex_lock(&mMutexSystemStatus);
+
+    // parse the received nmea strings here
+    if (0 == strncmp(data, "$PQWM1", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        SystemStatusPQWM1 s = SystemStatusPQWM1parser(buf, len).get();
+        setIteminReport(mCache.mTimeAndClock, SystemStatusTimeAndClock(s));
+        setIteminReport(mCache.mXoState, SystemStatusXoState(s));
+        setIteminReport(mCache.mRfAndParams, SystemStatusRfAndParams(s));
+        setIteminReport(mCache.mErrRecovery, SystemStatusErrRecovery(s));
+    }
+    else if (0 == strncmp(data, "$PQWP1", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        setIteminReport(mCache.mInjectedPosition,
+                SystemStatusInjectedPosition(SystemStatusPQWP1parser(buf, len).get()));
+    }
+    else if (0 == strncmp(data, "$PQWP2", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        setIteminReport(mCache.mBestPosition,
+                SystemStatusBestPosition(SystemStatusPQWP2parser(buf, len).get()));
+    }
+    else if (0 == strncmp(data, "$PQWP3", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        setIteminReport(mCache.mXtra,
+                SystemStatusXtra(SystemStatusPQWP3parser(buf, len).get()));
+    }
+    else if (0 == strncmp(data, "$PQWP4", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        setIteminReport(mCache.mEphemeris,
+                SystemStatusEphemeris(SystemStatusPQWP4parser(buf, len).get()));
+    }
+    else if (0 == strncmp(data, "$PQWP5", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        setIteminReport(mCache.mSvHealth,
+                SystemStatusSvHealth(SystemStatusPQWP5parser(buf, len).get()));
+    }
+    else if (0 == strncmp(data, "$PQWP6", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        setIteminReport(mCache.mPdr,
+                SystemStatusPdr(SystemStatusPQWP6parser(buf, len).get()));
+    }
+    else if (0 == strncmp(data, "$PQWP7", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        setIteminReport(mCache.mNavData,
+                SystemStatusNavData(SystemStatusPQWP7parser(buf, len).get()));
+    }
+    else if (0 == strncmp(data, "$PQWS1", SystemStatusNmeaBase::NMEA_MINSIZE)) {
+        setIteminReport(mCache.mPositionFailure,
+                SystemStatusPositionFailure(SystemStatusPQWS1parser(buf, len).get()));
+    }
+    else {
+        // do nothing
+    }
+
+    pthread_mutex_unlock(&mMutexSystemStatus);
+    return true;
+}
+
+/******************************************************************************
+@brief      API to set report position data into internal buffer
+
+@param[In]  UlpLocation
+
+@return     true when successfully done
+******************************************************************************/
+bool SystemStatus::eventPosition(const UlpLocation& location,
+                                 const GpsLocationExtended& locationEx)
+{
+    bool ret = false;
+    pthread_mutex_lock(&mMutexSystemStatus);
+
+    ret = setIteminReport(mCache.mLocation, SystemStatusLocation(location, locationEx));
+    LOC_LOGV("eventPosition - lat=%f lon=%f alt=%f speed=%f",
+             location.gpsLocation.latitude,
+             location.gpsLocation.longitude,
+             location.gpsLocation.altitude,
+             location.gpsLocation.speed);
+
+    pthread_mutex_unlock(&mMutexSystemStatus);
+    return ret;
+}
+
+/******************************************************************************
+@brief      API to set report DataItem event into internal buffer
+
+@param[In]  DataItem
+
+@return     true when info is updatated
+******************************************************************************/
+bool SystemStatus::eventDataItemNotify(IDataItemCore* dataitem)
+{
+    bool ret = false;
+    pthread_mutex_lock(&mMutexSystemStatus);
+    switch(dataitem->getId())
+    {
+        case AIRPLANEMODE_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mAirplaneMode,
+                    SystemStatusAirplaneMode(*(static_cast<AirplaneModeDataItemBase*>(dataitem))));
+            break;
+        case ENH_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mENH,
+                    SystemStatusENH(*(static_cast<ENHDataItemBase*>(dataitem))));
+            break;
+        case GPSSTATE_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mGPSState,
+                    SystemStatusGpsState(*(static_cast<GPSStateDataItemBase*>(dataitem))));
+            break;
+        case NLPSTATUS_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mNLPStatus,
+                    SystemStatusNLPStatus(*(static_cast<NLPStatusDataItemBase*>(dataitem))));
+            break;
+        case WIFIHARDWARESTATE_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mWifiHardwareState,
+                    SystemStatusWifiHardwareState(*(static_cast<WifiHardwareStateDataItemBase*>(dataitem))));
+            break;
+        case NETWORKINFO_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mNetworkInfo,
+                    SystemStatusNetworkInfo(*(static_cast<NetworkInfoDataItemBase*>(dataitem))));
+            break;
+        case RILSERVICEINFO_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mRilServiceInfo,
+                    SystemStatusServiceInfo(*(static_cast<RilServiceInfoDataItemBase*>(dataitem))));
+            break;
+        case RILCELLINFO_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mRilCellInfo,
+                    SystemStatusRilCellInfo(*(static_cast<RilCellInfoDataItemBase*>(dataitem))));
+            break;
+        case SERVICESTATUS_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mServiceStatus,
+                    SystemStatusServiceStatus(*(static_cast<ServiceStatusDataItemBase*>(dataitem))));
+            break;
+        case MODEL_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mModel,
+                    SystemStatusModel(*(static_cast<ModelDataItemBase*>(dataitem))));
+            break;
+        case MANUFACTURER_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mManufacturer,
+                    SystemStatusManufacturer(*(static_cast<ManufacturerDataItemBase*>(dataitem))));
+            break;
+        case ASSISTED_GPS_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mAssistedGps,
+                    SystemStatusAssistedGps(*(static_cast<AssistedGpsDataItemBase*>(dataitem))));
+            break;
+        case SCREEN_STATE_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mScreenState,
+                    SystemStatusScreenState(*(static_cast<ScreenStateDataItemBase*>(dataitem))));
+            break;
+        case POWER_CONNECTED_STATE_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mPowerConnectState,
+                    SystemStatusPowerConnectState(*(static_cast<PowerConnectStateDataItemBase*>(dataitem))));
+            break;
+        case TIMEZONE_CHANGE_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mTimeZoneChange,
+                    SystemStatusTimeZoneChange(*(static_cast<TimeZoneChangeDataItemBase*>(dataitem))));
+            break;
+        case TIME_CHANGE_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mTimeChange,
+                    SystemStatusTimeChange(*(static_cast<TimeChangeDataItemBase*>(dataitem))));
+            break;
+        case WIFI_SUPPLICANT_STATUS_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mWifiSupplicantStatus,
+                    SystemStatusWifiSupplicantStatus(*(static_cast<WifiSupplicantStatusDataItemBase*>(dataitem))));
+            break;
+        case SHUTDOWN_STATE_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mShutdownState,
+                    SystemStatusShutdownState(*(static_cast<ShutdownStateDataItemBase*>(dataitem))));
+            break;
+        case TAC_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mTac,
+                    SystemStatusTac(*(static_cast<TacDataItemBase*>(dataitem))));
+            break;
+        case MCCMNC_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mMccMnc,
+                    SystemStatusMccMnc(*(static_cast<MccmncDataItemBase*>(dataitem))));
+            break;
+        case BTLE_SCAN_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mBtDeviceScanDetail,
+                    SystemStatusBtDeviceScanDetail(*(static_cast<BtDeviceScanDetailsDataItemBase*>(dataitem))));
+            break;
+        case BT_SCAN_DATA_ITEM_ID:
+            ret = setIteminReport(mCache.mBtLeDeviceScanDetail,
+                    SystemStatusBtleDeviceScanDetail(*(static_cast<BtLeDeviceScanDetailsDataItemBase*>(dataitem))));
+            break;
+        default:
+            break;
+    }
+    pthread_mutex_unlock(&mMutexSystemStatus);
+    LOC_LOGv("DataItemId: %d, whether to record dateitem in cache: %d", dataitem->getId(), ret);
+    return ret;
+}
+
+/******************************************************************************
+@brief      API to get report data into a given buffer
+
+@param[In]  reference to report buffer
+@param[In]  bool flag to identify latest only or entire buffer
+
+@return     true when successfully done
+******************************************************************************/
+bool SystemStatus::getReport(SystemStatusReports& report, bool isLatestOnly) const
+{
+    pthread_mutex_lock(&mMutexSystemStatus);
+
+    if (isLatestOnly) {
+        // push back only the latest report and return it
+        getIteminReport(report.mLocation, mCache.mLocation);
+
+        getIteminReport(report.mTimeAndClock, mCache.mTimeAndClock);
+        getIteminReport(report.mXoState, mCache.mXoState);
+        getIteminReport(report.mRfAndParams, mCache.mRfAndParams);
+        getIteminReport(report.mErrRecovery, mCache.mErrRecovery);
+
+        getIteminReport(report.mInjectedPosition, mCache.mInjectedPosition);
+        getIteminReport(report.mBestPosition, mCache.mBestPosition);
+        getIteminReport(report.mXtra, mCache.mXtra);
+        getIteminReport(report.mEphemeris, mCache.mEphemeris);
+        getIteminReport(report.mSvHealth, mCache.mSvHealth);
+        getIteminReport(report.mPdr, mCache.mPdr);
+        getIteminReport(report.mNavData, mCache.mNavData);
+
+        getIteminReport(report.mPositionFailure, mCache.mPositionFailure);
+
+        getIteminReport(report.mAirplaneMode, mCache.mAirplaneMode);
+        getIteminReport(report.mENH, mCache.mENH);
+        getIteminReport(report.mGPSState, mCache.mGPSState);
+        getIteminReport(report.mNLPStatus, mCache.mNLPStatus);
+        getIteminReport(report.mWifiHardwareState, mCache.mWifiHardwareState);
+        getIteminReport(report.mNetworkInfo, mCache.mNetworkInfo);
+        getIteminReport(report.mRilServiceInfo, mCache.mRilServiceInfo);
+        getIteminReport(report.mRilCellInfo, mCache.mRilCellInfo);
+        getIteminReport(report.mServiceStatus, mCache.mServiceStatus);
+        getIteminReport(report.mModel, mCache.mModel);
+        getIteminReport(report.mManufacturer, mCache.mManufacturer);
+        getIteminReport(report.mAssistedGps, mCache.mAssistedGps);
+        getIteminReport(report.mScreenState, mCache.mScreenState);
+        getIteminReport(report.mPowerConnectState, mCache.mPowerConnectState);
+        getIteminReport(report.mTimeZoneChange, mCache.mTimeZoneChange);
+        getIteminReport(report.mTimeChange, mCache.mTimeChange);
+        getIteminReport(report.mWifiSupplicantStatus, mCache.mWifiSupplicantStatus);
+        getIteminReport(report.mShutdownState, mCache.mShutdownState);
+        getIteminReport(report.mTac, mCache.mTac);
+        getIteminReport(report.mMccMnc, mCache.mMccMnc);
+        getIteminReport(report.mBtDeviceScanDetail, mCache.mBtDeviceScanDetail);
+        getIteminReport(report.mBtLeDeviceScanDetail, mCache.mBtLeDeviceScanDetail);
+    }
+    else {
+        // copy entire reports and return them
+        report.mLocation.clear();
+
+        report.mTimeAndClock.clear();
+        report.mXoState.clear();
+        report.mRfAndParams.clear();
+        report.mErrRecovery.clear();
+
+        report.mInjectedPosition.clear();
+        report.mBestPosition.clear();
+        report.mXtra.clear();
+        report.mEphemeris.clear();
+        report.mSvHealth.clear();
+        report.mPdr.clear();
+        report.mNavData.clear();
+
+        report.mPositionFailure.clear();
+
+        report.mAirplaneMode.clear();
+        report.mENH.clear();
+        report.mGPSState.clear();
+        report.mNLPStatus.clear();
+        report.mWifiHardwareState.clear();
+        report.mNetworkInfo.clear();
+        report.mRilServiceInfo.clear();
+        report.mRilCellInfo.clear();
+        report.mServiceStatus.clear();
+        report.mModel.clear();
+        report.mManufacturer.clear();
+        report.mAssistedGps.clear();
+        report.mScreenState.clear();
+        report.mPowerConnectState.clear();
+        report.mTimeZoneChange.clear();
+        report.mTimeChange.clear();
+        report.mWifiSupplicantStatus.clear();
+        report.mShutdownState.clear();
+        report.mTac.clear();
+        report.mMccMnc.clear();
+        report.mBtDeviceScanDetail.clear();
+        report.mBtLeDeviceScanDetail.clear();
+
+        report = mCache;
+    }
+
+    pthread_mutex_unlock(&mMutexSystemStatus);
+    return true;
+}
+
+/******************************************************************************
+@brief      API to set default report data
+
+@param[In]  none
+
+@return     true when successfully done
+******************************************************************************/
+bool SystemStatus::setDefaultGnssEngineStates(void)
+{
+    pthread_mutex_lock(&mMutexSystemStatus);
+
+    setDefaultIteminReport(mCache.mLocation, SystemStatusLocation());
+
+    setDefaultIteminReport(mCache.mTimeAndClock, SystemStatusTimeAndClock());
+    setDefaultIteminReport(mCache.mXoState, SystemStatusXoState());
+    setDefaultIteminReport(mCache.mRfAndParams, SystemStatusRfAndParams());
+    setDefaultIteminReport(mCache.mErrRecovery, SystemStatusErrRecovery());
+
+    setDefaultIteminReport(mCache.mInjectedPosition, SystemStatusInjectedPosition());
+    setDefaultIteminReport(mCache.mBestPosition, SystemStatusBestPosition());
+    setDefaultIteminReport(mCache.mXtra, SystemStatusXtra());
+    setDefaultIteminReport(mCache.mEphemeris, SystemStatusEphemeris());
+    setDefaultIteminReport(mCache.mSvHealth, SystemStatusSvHealth());
+    setDefaultIteminReport(mCache.mPdr, SystemStatusPdr());
+    setDefaultIteminReport(mCache.mNavData, SystemStatusNavData());
+
+    setDefaultIteminReport(mCache.mPositionFailure, SystemStatusPositionFailure());
+
+    pthread_mutex_unlock(&mMutexSystemStatus);
+    return true;
+}
+
+/******************************************************************************
+@brief      API to handle connection status update event from GnssRil
+
+@param[In]  Connection status
+
+@return     true when successfully done
+******************************************************************************/
+bool SystemStatus::eventConnectionStatus(bool connected, int8_t type,
+                                         bool roaming, NetworkHandle networkHandle,
+                                         string& apn)
+{
+    // send networkinof dataitem to systemstatus observer clients
+    SystemStatusNetworkInfo s(type, "", "", connected, roaming,
+                              (uint64_t) networkHandle, apn);
+    mSysStatusObsvr.notify({&s});
+
+    return true;
+}
+
+/******************************************************************************
+@brief      API to update power connect state
+
+@param[In]  power connect status
+
+@return     true when successfully done
+******************************************************************************/
+bool SystemStatus::updatePowerConnectState(bool charging)
+{
+    SystemStatusPowerConnectState s(charging);
+    mSysStatusObsvr.notify({&s});
+    return true;
+}
+} // namespace loc_core
+
diff --git a/gps/core/SystemStatus.h b/gps/core/SystemStatus.h
new file mode 100644
index 0000000..638933a
--- /dev/null
+++ b/gps/core/SystemStatus.h
@@ -0,0 +1,926 @@
+/* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __SYSTEM_STATUS__
+#define __SYSTEM_STATUS__
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <vector>
+#include <algorithm>
+#include <iterator>
+#include <loc_pla.h>
+#include <log_util.h>
+#include <MsgTask.h>
+#include <IDataItemCore.h>
+#include <IOsObserver.h>
+#include <DataItemConcreteTypesBase.h>
+#include <SystemStatusOsObserver.h>
+
+#include <gps_extended_c.h>
+
+#define GPS_MIN    (1)   //1-32
+#define SBAS_MIN   (33)
+#define GLO_MIN    (65)  //65-88
+#define QZSS_MIN   (193) //193-197
+#define BDS_MIN    (201) //201-237
+#define GAL_MIN    (301) //301-336
+#define NAVIC_MIN  (401) //401-414
+
+#define GPS_NUM     (32)
+#define SBAS_NUM    (32)
+#define GLO_NUM     (24)
+#define QZSS_NUM    (5)
+#define BDS_NUM     (37)
+#define GAL_NUM     (36)
+#define NAVIC_NUM   (14)
+#define SV_ALL_NUM_MIN  (GPS_NUM + GLO_NUM + QZSS_NUM + BDS_NUM + GAL_NUM) //=134
+#define SV_ALL_NUM      (SV_ALL_NUM_MIN + NAVIC_NUM) //=148
+
+namespace loc_core
+{
+
+/******************************************************************************
+ SystemStatus report data structure
+******************************************************************************/
+class SystemStatusItemBase
+{
+public:
+    timespec  mUtcTime;
+    timespec  mUtcReported;
+    static const uint32_t maxItem = 5;
+
+    SystemStatusItemBase() {
+        timeval tv;
+        gettimeofday(&tv, NULL);
+        mUtcTime.tv_sec  = tv.tv_sec;
+        mUtcTime.tv_nsec = tv.tv_usec*1000ULL;
+        mUtcReported = mUtcTime;
+    };
+    virtual ~SystemStatusItemBase() {};
+    inline virtual SystemStatusItemBase& collate(SystemStatusItemBase&) {
+        return *this;
+    }
+    virtual void dump(void) {};
+    inline virtual bool ignore() { return false; };
+};
+
+class SystemStatusLocation : public SystemStatusItemBase
+{
+public:
+    bool mValid;
+    UlpLocation mLocation;
+    GpsLocationExtended mLocationEx;
+    inline SystemStatusLocation() :
+        mValid(false) {}
+    inline SystemStatusLocation(const UlpLocation& location,
+                         const GpsLocationExtended& locationEx) :
+        mValid(true),
+        mLocation(location),
+        mLocationEx(locationEx) {}
+    bool equals(const SystemStatusLocation& peer);
+    void dump(void) override;
+};
+
+class SystemStatusPQWM1;
+class SystemStatusTimeAndClock : public SystemStatusItemBase
+{
+public:
+    uint16_t mGpsWeek;
+    uint32_t mGpsTowMs;
+    uint8_t  mTimeValid;
+    uint8_t  mTimeSource;
+    int32_t  mTimeUnc;
+    int32_t  mClockFreqBias;
+    int32_t  mClockFreqBiasUnc;
+    int32_t  mLeapSeconds;
+    int32_t  mLeapSecUnc;
+    uint64_t mTimeUncNs;
+    inline SystemStatusTimeAndClock() :
+        mGpsWeek(0),
+        mGpsTowMs(0),
+        mTimeValid(0),
+        mTimeSource(0),
+        mTimeUnc(0),
+        mClockFreqBias(0),
+        mClockFreqBiasUnc(0),
+        mLeapSeconds(0),
+        mLeapSecUnc(0),
+        mTimeUncNs(0ULL) {}
+    inline SystemStatusTimeAndClock(const SystemStatusPQWM1& nmea);
+    bool equals(const SystemStatusTimeAndClock& peer);
+    void dump(void) override;
+};
+
+class SystemStatusXoState : public SystemStatusItemBase
+{
+public:
+    uint8_t  mXoState;
+    inline SystemStatusXoState() :
+        mXoState(0) {}
+    inline SystemStatusXoState(const SystemStatusPQWM1& nmea);
+    bool equals(const SystemStatusXoState& peer);
+    void dump(void) override;
+};
+
+class SystemStatusRfAndParams : public SystemStatusItemBase
+{
+public:
+    int32_t  mPgaGain;
+    uint32_t mGpsBpAmpI;
+    uint32_t mGpsBpAmpQ;
+    uint32_t mAdcI;
+    uint32_t mAdcQ;
+    uint32_t mJammerGps;
+    uint32_t mJammerGlo;
+    uint32_t mJammerBds;
+    uint32_t mJammerGal;
+    double   mAgcGps;
+    double   mAgcGlo;
+    double   mAgcBds;
+    double   mAgcGal;
+    uint32_t mGloBpAmpI;
+    uint32_t mGloBpAmpQ;
+    uint32_t mBdsBpAmpI;
+    uint32_t mBdsBpAmpQ;
+    uint32_t mGalBpAmpI;
+    uint32_t mGalBpAmpQ;
+    inline SystemStatusRfAndParams() :
+        mPgaGain(0),
+        mGpsBpAmpI(0),
+        mGpsBpAmpQ(0),
+        mAdcI(0),
+        mAdcQ(0),
+        mJammerGps(0),
+        mJammerGlo(0),
+        mJammerBds(0),
+        mJammerGal(0),
+        mAgcGps(0),
+        mAgcGlo(0),
+        mAgcBds(0),
+        mAgcGal(0),
+        mGloBpAmpI(0),
+        mGloBpAmpQ(0),
+        mBdsBpAmpI(0),
+        mBdsBpAmpQ(0),
+        mGalBpAmpI(0),
+        mGalBpAmpQ(0) {}
+    inline SystemStatusRfAndParams(const SystemStatusPQWM1& nmea);
+    bool equals(const SystemStatusRfAndParams& peer);
+    void dump(void) override;
+};
+
+class SystemStatusErrRecovery : public SystemStatusItemBase
+{
+public:
+    uint32_t mRecErrorRecovery;
+    inline SystemStatusErrRecovery() :
+        mRecErrorRecovery(0) {};
+    inline SystemStatusErrRecovery(const SystemStatusPQWM1& nmea);
+    bool equals(const SystemStatusErrRecovery& peer);
+    inline bool ignore() override { return 0 == mRecErrorRecovery; };
+    void dump(void) override;
+};
+
+class SystemStatusPQWP1;
+class SystemStatusInjectedPosition : public SystemStatusItemBase
+{
+public:
+    uint8_t  mEpiValidity;
+    float    mEpiLat;
+    float    mEpiLon;
+    float    mEpiAlt;
+    float    mEpiHepe;
+    float    mEpiAltUnc;
+    uint8_t  mEpiSrc;
+    inline SystemStatusInjectedPosition() :
+        mEpiValidity(0),
+        mEpiLat(0),
+        mEpiLon(0),
+        mEpiAlt(0),
+        mEpiHepe(0),
+        mEpiAltUnc(0),
+        mEpiSrc(0) {}
+    inline SystemStatusInjectedPosition(const SystemStatusPQWP1& nmea);
+    bool equals(const SystemStatusInjectedPosition& peer);
+    void dump(void) override;
+};
+
+class SystemStatusPQWP2;
+class SystemStatusBestPosition : public SystemStatusItemBase
+{
+public:
+    bool     mValid;
+    float    mBestLat;
+    float    mBestLon;
+    float    mBestAlt;
+    float    mBestHepe;
+    float    mBestAltUnc;
+    inline SystemStatusBestPosition() :
+        mValid(false),
+        mBestLat(0),
+        mBestLon(0),
+        mBestAlt(0),
+        mBestHepe(0),
+        mBestAltUnc(0) {}
+    inline SystemStatusBestPosition(const SystemStatusPQWP2& nmea);
+    bool equals(const SystemStatusBestPosition& peer);
+    void dump(void) override;
+};
+
+class SystemStatusPQWP3;
+class SystemStatusXtra : public SystemStatusItemBase
+{
+public:
+    uint8_t   mXtraValidMask;
+    uint32_t  mGpsXtraAge;
+    uint32_t  mGloXtraAge;
+    uint32_t  mBdsXtraAge;
+    uint32_t  mGalXtraAge;
+    uint32_t  mQzssXtraAge;
+    uint32_t  mNavicXtraAge;
+    uint32_t  mGpsXtraValid;
+    uint32_t  mGloXtraValid;
+    uint64_t  mBdsXtraValid;
+    uint64_t  mGalXtraValid;
+    uint8_t   mQzssXtraValid;
+    uint32_t  mNavicXtraValid;
+    inline SystemStatusXtra() :
+        mXtraValidMask(0),
+        mGpsXtraAge(0),
+        mGloXtraAge(0),
+        mBdsXtraAge(0),
+        mGalXtraAge(0),
+        mQzssXtraAge(0),
+        mNavicXtraAge(0),
+        mGpsXtraValid(0),
+        mGloXtraValid(0),
+        mBdsXtraValid(0ULL),
+        mGalXtraValid(0ULL),
+        mQzssXtraValid(0),
+        mNavicXtraValid(0) {}
+    inline SystemStatusXtra(const SystemStatusPQWP3& nmea);
+    bool equals(const SystemStatusXtra& peer);
+    void dump(void) override;
+};
+
+class SystemStatusPQWP4;
+class SystemStatusEphemeris : public SystemStatusItemBase
+{
+public:
+    uint32_t  mGpsEpheValid;
+    uint32_t  mGloEpheValid;
+    uint64_t  mBdsEpheValid;
+    uint64_t  mGalEpheValid;
+    uint8_t   mQzssEpheValid;
+    inline SystemStatusEphemeris() :
+        mGpsEpheValid(0),
+        mGloEpheValid(0),
+        mBdsEpheValid(0ULL),
+        mGalEpheValid(0ULL),
+        mQzssEpheValid(0) {}
+    inline SystemStatusEphemeris(const SystemStatusPQWP4& nmea);
+    bool equals(const SystemStatusEphemeris& peer);
+    void dump(void) override;
+};
+
+class SystemStatusPQWP5;
+class SystemStatusSvHealth : public SystemStatusItemBase
+{
+public:
+    uint32_t  mGpsUnknownMask;
+    uint32_t  mGloUnknownMask;
+    uint64_t  mBdsUnknownMask;
+    uint64_t  mGalUnknownMask;
+    uint8_t   mQzssUnknownMask;
+    uint32_t  mNavicUnknownMask;
+    uint32_t  mGpsGoodMask;
+    uint32_t  mGloGoodMask;
+    uint64_t  mBdsGoodMask;
+    uint64_t  mGalGoodMask;
+    uint8_t   mQzssGoodMask;
+    uint32_t  mNavicGoodMask;
+    uint32_t  mGpsBadMask;
+    uint32_t  mGloBadMask;
+    uint64_t  mBdsBadMask;
+    uint64_t  mGalBadMask;
+    uint8_t   mQzssBadMask;
+    uint32_t  mNavicBadMask;
+    inline SystemStatusSvHealth() :
+        mGpsUnknownMask(0),
+        mGloUnknownMask(0),
+        mBdsUnknownMask(0ULL),
+        mGalUnknownMask(0ULL),
+        mQzssUnknownMask(0),
+        mNavicUnknownMask(0),
+        mGpsGoodMask(0),
+        mGloGoodMask(0),
+        mBdsGoodMask(0ULL),
+        mGalGoodMask(0ULL),
+        mQzssGoodMask(0),
+        mNavicGoodMask(0),
+        mGpsBadMask(0),
+        mGloBadMask(0),
+        mBdsBadMask(0ULL),
+        mGalBadMask(0ULL),
+        mQzssBadMask(0),
+        mNavicBadMask(0) {}
+    inline SystemStatusSvHealth(const SystemStatusPQWP5& nmea);
+    bool equals(const SystemStatusSvHealth& peer);
+    void dump(void) override;
+};
+
+class SystemStatusPQWP6;
+class SystemStatusPdr : public SystemStatusItemBase
+{
+public:
+    uint32_t  mFixInfoMask;
+    inline SystemStatusPdr() :
+        mFixInfoMask(0) {}
+    inline SystemStatusPdr(const SystemStatusPQWP6& nmea);
+    bool equals(const SystemStatusPdr& peer);
+    void dump(void) override;
+};
+
+class SystemStatusPQWP7;
+struct SystemStatusNav
+{
+    GnssEphemerisType   mType;
+    GnssEphemerisSource mSource;
+    int32_t             mAgeSec;
+};
+
+class SystemStatusNavData : public SystemStatusItemBase
+{
+public:
+    SystemStatusNav mNav[SV_ALL_NUM];
+    inline SystemStatusNavData() {
+        for (uint32_t i=0; i<SV_ALL_NUM; i++) {
+            mNav[i].mType = GNSS_EPH_TYPE_UNKNOWN;
+            mNav[i].mSource = GNSS_EPH_SOURCE_UNKNOWN;
+            mNav[i].mAgeSec = 0;
+        }
+    }
+    inline SystemStatusNavData(const SystemStatusPQWP7& nmea);
+    bool equals(const SystemStatusNavData& peer);
+    void dump(void) override;
+};
+
+class SystemStatusPQWS1;
+class SystemStatusPositionFailure : public SystemStatusItemBase
+{
+public:
+    uint32_t  mFixInfoMask;
+    uint32_t  mHepeLimit;
+    inline SystemStatusPositionFailure() :
+        mFixInfoMask(0),
+        mHepeLimit(0) {}
+    inline SystemStatusPositionFailure(const SystemStatusPQWS1& nmea);
+    bool equals(const SystemStatusPositionFailure& peer);
+    void dump(void) override;
+};
+
+/******************************************************************************
+ SystemStatus report data structure - from DataItem observer
+******************************************************************************/
+class SystemStatusAirplaneMode : public SystemStatusItemBase,
+        public AirplaneModeDataItemBase
+{
+public:
+    inline SystemStatusAirplaneMode(bool mode=false) :
+            AirplaneModeDataItemBase(mode) {}
+    inline SystemStatusAirplaneMode(const AirplaneModeDataItemBase& itemBase) :
+            AirplaneModeDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusAirplaneMode& peer) {
+        return (mMode == peer.mMode);
+    }
+};
+
+class SystemStatusENH : public SystemStatusItemBase,
+        public ENHDataItemBase
+{
+public:
+    inline SystemStatusENH(bool enabled=false) :
+            ENHDataItemBase(enabled) {}
+    inline SystemStatusENH(const ENHDataItemBase& itemBase) :
+            ENHDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusENH& peer) {
+        return (mEnabled == peer.mEnabled);
+    }
+};
+
+class SystemStatusGpsState : public SystemStatusItemBase,
+        public GPSStateDataItemBase
+{
+public:
+    inline SystemStatusGpsState(bool enabled=false) :
+            GPSStateDataItemBase(enabled) {}
+    inline SystemStatusGpsState(const GPSStateDataItemBase& itemBase) :
+            GPSStateDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusGpsState& peer) {
+        return (mEnabled == peer.mEnabled);
+    }
+    inline void dump(void) override {
+        LOC_LOGD("GpsState: state=%u", mEnabled);
+    }
+};
+
+class SystemStatusNLPStatus : public SystemStatusItemBase,
+        public NLPStatusDataItemBase
+{
+public:
+    inline SystemStatusNLPStatus(bool enabled=false) :
+            NLPStatusDataItemBase(enabled) {}
+    inline SystemStatusNLPStatus(const NLPStatusDataItemBase& itemBase) :
+            NLPStatusDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusNLPStatus& peer) {
+        return (mEnabled == peer.mEnabled);
+    }
+};
+
+class SystemStatusWifiHardwareState : public SystemStatusItemBase,
+        public WifiHardwareStateDataItemBase
+{
+public:
+    inline SystemStatusWifiHardwareState(bool enabled=false) :
+            WifiHardwareStateDataItemBase(enabled) {}
+    inline SystemStatusWifiHardwareState(const WifiHardwareStateDataItemBase& itemBase) :
+            WifiHardwareStateDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusWifiHardwareState& peer) {
+        return (mEnabled == peer.mEnabled);
+    }
+};
+
+class SystemStatusNetworkInfo : public SystemStatusItemBase,
+        public NetworkInfoDataItemBase
+{
+    NetworkInfoDataItemBase* mSrcObjPtr;
+public:
+    inline SystemStatusNetworkInfo(
+            int32_t type = 0,
+            std::string typeName = "",
+            string subTypeName = "",
+            bool connected = false,
+            bool roaming = false,
+            uint64_t networkHandle = NETWORK_HANDLE_UNKNOWN,
+            string apn = "") :
+            NetworkInfoDataItemBase(
+                    (NetworkType)type,
+                    type,
+                    typeName,
+                    subTypeName,
+                    connected && (!roaming),
+                    connected,
+                    roaming,
+                    networkHandle, apn),
+            mSrcObjPtr(nullptr) {}
+    inline SystemStatusNetworkInfo(const NetworkInfoDataItemBase& itemBase) :
+            NetworkInfoDataItemBase(itemBase),
+            mSrcObjPtr((NetworkInfoDataItemBase*)&itemBase) {
+        mType = (int32_t)itemBase.getType();
+    }
+    inline bool equals(const SystemStatusNetworkInfo& peer) {
+        bool rtv = (peer.mConnected == mConnected);
+        for (uint8_t i = 0; rtv && i < MAX_NETWORK_HANDLES; ++i) {
+            rtv &= (mAllNetworkHandles[i] == peer.mAllNetworkHandles[i]);
+        }
+        return rtv && !peer.mApn.compare(mApn);
+    }
+    inline virtual SystemStatusItemBase& collate(SystemStatusItemBase& curInfo) {
+        LOC_LOGv("NetworkInfo: mAllTypes=%" PRIx64 " connected=%u mType=%x mApn=%s",
+                 mAllTypes, mConnected, mType, mApn.c_str());
+        uint64_t allTypes = (static_cast<SystemStatusNetworkInfo&>(curInfo)).mAllTypes;
+        string& apn = (static_cast<SystemStatusNetworkInfo&>(curInfo)).mApn;
+        // Replace current with cached table for now and then update
+        memcpy(mAllNetworkHandles,
+               (static_cast<SystemStatusNetworkInfo&>(curInfo)).getNetworkHandle(),
+               sizeof(mAllNetworkHandles));
+        // Update the apn for non-mobile type connections.
+        if (TYPE_MOBILE != mType && apn.compare("") != 0) {
+            mApn = apn;
+        }
+        if (mConnected) {
+            mAllTypes |= allTypes;
+            for (uint8_t i = 0; i < MAX_NETWORK_HANDLES; ++i) {
+                if (mNetworkHandle == mAllNetworkHandles[i].networkHandle) {
+                    LOC_LOGD("collate duplicate detected, not updating");
+                    break;
+                }
+                if (NETWORK_HANDLE_UNKNOWN == mAllNetworkHandles[i].networkHandle) {
+                    mAllNetworkHandles[i].networkHandle = mNetworkHandle;
+                    mAllNetworkHandles[i].networkType = (loc_core::NetworkType) mType;
+                    break;
+                }
+            }
+        } else if (0 != mAllTypes) {
+            uint8_t deletedIndex = MAX_NETWORK_HANDLES;
+            uint8_t lastValidIndex = 0;
+            uint8_t typeCount = 0;
+            for (; lastValidIndex < MAX_NETWORK_HANDLES &&
+                     NETWORK_HANDLE_UNKNOWN != mAllNetworkHandles[lastValidIndex].networkHandle;
+                 ++lastValidIndex) {
+                // Maintain count for number of network handles still
+                // connected for given type
+                if (mType == (int32_t)mAllNetworkHandles[lastValidIndex].networkType) {
+                    if (mNetworkHandle == mAllNetworkHandles[lastValidIndex].networkHandle) {
+                        deletedIndex = lastValidIndex;
+                    } else {
+                        typeCount++;
+                    }
+                }
+
+            }
+            if (lastValidIndex > 0) {
+                --lastValidIndex;
+            }
+
+            if (MAX_NETWORK_HANDLES != deletedIndex) {
+                LOC_LOGd("deletedIndex:%u, lastValidIndex:%u, typeCount:%u",
+                        deletedIndex, lastValidIndex, typeCount);
+                mAllNetworkHandles[deletedIndex] = mAllNetworkHandles[lastValidIndex];
+                mAllNetworkHandles[lastValidIndex].networkHandle = NETWORK_HANDLE_UNKNOWN;
+                mAllNetworkHandles[lastValidIndex].networkType = TYPE_UNKNOWN;
+            }
+
+            // If no more handles of given type, set bitmask
+            if (0 == typeCount) {
+                mAllTypes = (allTypes & (~mAllTypes));
+                LOC_LOGD("mAllTypes:%" PRIx64, mAllTypes);
+            }
+        } // else (mConnected == false && mAllTypes == 0)
+          // we keep mAllTypes as 0, which means no more connections.
+
+        if (nullptr != mSrcObjPtr) {
+            // this is critical, changing mAllTypes of the original obj
+            mSrcObjPtr->mAllTypes = mAllTypes;
+            memcpy(mSrcObjPtr->mAllNetworkHandles,
+                   mAllNetworkHandles,
+                   sizeof(mSrcObjPtr->mAllNetworkHandles));
+        }
+        return *this;
+    }
+    inline void dump(void) override {
+        LOC_LOGD("NetworkInfo: mAllTypes=%" PRIx64 " connected=%u mType=%x mApn=%s",
+                 mAllTypes, mConnected, mType, mApn.c_str());
+    }
+};
+
+class SystemStatusServiceInfo : public SystemStatusItemBase,
+        public RilServiceInfoDataItemBase
+{
+public:
+    inline SystemStatusServiceInfo() :
+            RilServiceInfoDataItemBase() {}
+    inline SystemStatusServiceInfo(const RilServiceInfoDataItemBase& itemBase) :
+            RilServiceInfoDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusServiceInfo& peer) {
+        return static_cast<const RilServiceInfoDataItemBase&>(peer) ==
+                static_cast<const RilServiceInfoDataItemBase&>(*this);
+    }
+};
+
+class SystemStatusRilCellInfo : public SystemStatusItemBase,
+        public RilCellInfoDataItemBase
+{
+public:
+    inline SystemStatusRilCellInfo() :
+            RilCellInfoDataItemBase() {}
+    inline SystemStatusRilCellInfo(const RilCellInfoDataItemBase& itemBase) :
+            RilCellInfoDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusRilCellInfo& peer) {
+        return static_cast<const RilCellInfoDataItemBase&>(peer) ==
+                static_cast<const RilCellInfoDataItemBase&>(*this);
+    }
+};
+
+class SystemStatusServiceStatus : public SystemStatusItemBase,
+        public ServiceStatusDataItemBase
+{
+public:
+    inline SystemStatusServiceStatus(int32_t mServiceState=0) :
+            ServiceStatusDataItemBase(mServiceState) {}
+    inline SystemStatusServiceStatus(const ServiceStatusDataItemBase& itemBase) :
+            ServiceStatusDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusServiceStatus& peer) {
+        return (mServiceState == peer.mServiceState);
+    }
+};
+
+class SystemStatusModel : public SystemStatusItemBase,
+        public ModelDataItemBase
+{
+public:
+    inline SystemStatusModel(string name="") :
+            ModelDataItemBase(name) {}
+    inline SystemStatusModel(const ModelDataItemBase& itemBase) :
+            ModelDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusModel& peer) {
+        return (mModel == peer.mModel);
+        }
+};
+
+class SystemStatusManufacturer : public SystemStatusItemBase,
+        public ManufacturerDataItemBase
+{
+public:
+    inline SystemStatusManufacturer(string name="") :
+            ManufacturerDataItemBase(name) {}
+    inline SystemStatusManufacturer(const ManufacturerDataItemBase& itemBase) :
+            ManufacturerDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusManufacturer& peer) {
+        return (mManufacturer == peer.mManufacturer);
+    }
+};
+
+class SystemStatusAssistedGps : public SystemStatusItemBase,
+        public AssistedGpsDataItemBase
+{
+public:
+    inline SystemStatusAssistedGps(bool enabled=false) :
+            AssistedGpsDataItemBase(enabled) {}
+    inline SystemStatusAssistedGps(const AssistedGpsDataItemBase& itemBase) :
+            AssistedGpsDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusAssistedGps& peer) {
+        return (mEnabled == peer.mEnabled);
+    }
+};
+
+class SystemStatusScreenState : public SystemStatusItemBase,
+        public ScreenStateDataItemBase
+{
+public:
+    inline SystemStatusScreenState(bool state=false) :
+            ScreenStateDataItemBase(state) {}
+    inline SystemStatusScreenState(const ScreenStateDataItemBase& itemBase) :
+            ScreenStateDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusScreenState& peer) {
+        return (mState == peer.mState);
+    }
+};
+
+class SystemStatusPowerConnectState : public SystemStatusItemBase,
+        public PowerConnectStateDataItemBase
+{
+public:
+    inline SystemStatusPowerConnectState(bool state=false) :
+            PowerConnectStateDataItemBase(state) {}
+    inline SystemStatusPowerConnectState(const PowerConnectStateDataItemBase& itemBase) :
+            PowerConnectStateDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusPowerConnectState& peer) {
+        return (mState == peer.mState);
+    }
+};
+
+class SystemStatusTimeZoneChange : public SystemStatusItemBase,
+        public TimeZoneChangeDataItemBase
+{
+public:
+    inline SystemStatusTimeZoneChange(
+            int64_t currTimeMillis=0ULL, int32_t rawOffset=0, int32_t dstOffset=0) :
+            TimeZoneChangeDataItemBase(currTimeMillis, rawOffset, dstOffset) {}
+    inline SystemStatusTimeZoneChange(const TimeZoneChangeDataItemBase& itemBase) :
+            TimeZoneChangeDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusTimeZoneChange& peer) {
+        return ((mCurrTimeMillis == peer.mCurrTimeMillis) &&
+                (mRawOffsetTZ == peer.mRawOffsetTZ) &&
+                (mDstOffsetTZ == peer.mDstOffsetTZ));
+    }
+};
+
+class SystemStatusTimeChange : public SystemStatusItemBase,
+        public TimeChangeDataItemBase
+{
+public:
+    inline SystemStatusTimeChange(
+            int64_t currTimeMillis=0ULL, int32_t rawOffset=0, int32_t dstOffset=0) :
+            TimeChangeDataItemBase(currTimeMillis, rawOffset, dstOffset) {}
+    inline SystemStatusTimeChange(const TimeChangeDataItemBase& itemBase) :
+            TimeChangeDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusTimeChange& peer) {
+        return ((mCurrTimeMillis == peer.mCurrTimeMillis) &&
+                (mRawOffsetTZ == peer.mRawOffsetTZ) &&
+                (mDstOffsetTZ == peer.mDstOffsetTZ));
+    }
+};
+
+class SystemStatusWifiSupplicantStatus : public SystemStatusItemBase,
+        public WifiSupplicantStatusDataItemBase
+{
+public:
+    inline SystemStatusWifiSupplicantStatus() :
+            WifiSupplicantStatusDataItemBase() {}
+    inline SystemStatusWifiSupplicantStatus(const WifiSupplicantStatusDataItemBase& itemBase) :
+            WifiSupplicantStatusDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusWifiSupplicantStatus& peer) {
+        return ((mState == peer.mState) &&
+                (mApMacAddressValid == peer.mApMacAddressValid) &&
+                (mWifiApSsidValid == peer.mWifiApSsidValid) &&
+                (mWifiApSsid == peer.mWifiApSsid));
+        }
+};
+
+class SystemStatusShutdownState : public SystemStatusItemBase,
+        public ShutdownStateDataItemBase
+{
+public:
+    inline SystemStatusShutdownState(bool state=false) :
+            ShutdownStateDataItemBase(state) {}
+    inline SystemStatusShutdownState(const ShutdownStateDataItemBase& itemBase) :
+            ShutdownStateDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusShutdownState& peer) {
+        return (mState == peer.mState);
+    }
+};
+
+class SystemStatusTac : public SystemStatusItemBase,
+        public TacDataItemBase
+{
+public:
+    inline SystemStatusTac(std::string value="") :
+            TacDataItemBase(value) {}
+    inline SystemStatusTac(const TacDataItemBase& itemBase) :
+            TacDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusTac& peer) {
+        return (mValue == peer.mValue);
+    }
+    inline void dump(void) override {
+        LOC_LOGD("Tac: value=%s", mValue.c_str());
+    }
+};
+
+class SystemStatusMccMnc : public SystemStatusItemBase,
+        public MccmncDataItemBase
+{
+public:
+    inline SystemStatusMccMnc(std::string value="") :
+            MccmncDataItemBase(value) {}
+    inline SystemStatusMccMnc(const MccmncDataItemBase& itemBase) :
+            MccmncDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusMccMnc& peer) {
+        return (mValue == peer.mValue);
+    }
+    inline void dump(void) override {
+        LOC_LOGD("TacMccMnc value=%s", mValue.c_str());
+    }
+};
+
+class SystemStatusBtDeviceScanDetail : public SystemStatusItemBase,
+        public BtDeviceScanDetailsDataItemBase
+{
+public:
+    inline SystemStatusBtDeviceScanDetail() :
+            BtDeviceScanDetailsDataItemBase() {}
+    inline SystemStatusBtDeviceScanDetail(const BtDeviceScanDetailsDataItemBase& itemBase) :
+            BtDeviceScanDetailsDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusBtDeviceScanDetail& peer) {
+        return ((mApSrnRssi == peer.mApSrnRssi) &&
+                (0 == memcmp(mApSrnMacAddress, peer.mApSrnMacAddress, sizeof(mApSrnMacAddress))) &&
+                (mApSrnTimestamp == peer.mApSrnTimestamp) &&
+                (mRequestTimestamp == peer.mRequestTimestamp) &&
+                (mReceiveTimestamp == peer.mReceiveTimestamp));
+    }
+};
+
+class SystemStatusBtleDeviceScanDetail : public SystemStatusItemBase,
+        public BtLeDeviceScanDetailsDataItemBase
+{
+public:
+    inline SystemStatusBtleDeviceScanDetail() :
+            BtLeDeviceScanDetailsDataItemBase() {}
+    inline SystemStatusBtleDeviceScanDetail(const BtLeDeviceScanDetailsDataItemBase& itemBase) :
+            BtLeDeviceScanDetailsDataItemBase(itemBase) {}
+    inline bool equals(const SystemStatusBtleDeviceScanDetail& peer) {
+        return ((mApSrnRssi == peer.mApSrnRssi) &&
+                (0 == memcmp(mApSrnMacAddress, peer.mApSrnMacAddress, sizeof(mApSrnMacAddress))) &&
+                (mApSrnTimestamp == peer.mApSrnTimestamp) &&
+                (mRequestTimestamp == peer.mRequestTimestamp) &&
+                (mReceiveTimestamp == peer.mReceiveTimestamp));
+    }
+};
+
+/******************************************************************************
+ SystemStatusReports
+******************************************************************************/
+class SystemStatusReports
+{
+public:
+    // from QMI_LOC indication
+    std::vector<SystemStatusLocation>         mLocation;
+
+    // from ME debug NMEA
+    std::vector<SystemStatusTimeAndClock>     mTimeAndClock;
+    std::vector<SystemStatusXoState>          mXoState;
+    std::vector<SystemStatusRfAndParams>      mRfAndParams;
+    std::vector<SystemStatusErrRecovery>      mErrRecovery;
+
+    // from PE debug NMEA
+    std::vector<SystemStatusInjectedPosition> mInjectedPosition;
+    std::vector<SystemStatusBestPosition>     mBestPosition;
+    std::vector<SystemStatusXtra>             mXtra;
+    std::vector<SystemStatusEphemeris>        mEphemeris;
+    std::vector<SystemStatusSvHealth>         mSvHealth;
+    std::vector<SystemStatusPdr>              mPdr;
+    std::vector<SystemStatusNavData>          mNavData;
+
+    // from SM debug NMEA
+    std::vector<SystemStatusPositionFailure>  mPositionFailure;
+
+    // from dataitems observer
+    std::vector<SystemStatusAirplaneMode>     mAirplaneMode;
+    std::vector<SystemStatusENH>              mENH;
+    std::vector<SystemStatusGpsState>         mGPSState;
+    std::vector<SystemStatusNLPStatus>        mNLPStatus;
+    std::vector<SystemStatusWifiHardwareState> mWifiHardwareState;
+    std::vector<SystemStatusNetworkInfo>      mNetworkInfo;
+    std::vector<SystemStatusServiceInfo>      mRilServiceInfo;
+    std::vector<SystemStatusRilCellInfo>      mRilCellInfo;
+    std::vector<SystemStatusServiceStatus>    mServiceStatus;
+    std::vector<SystemStatusModel>            mModel;
+    std::vector<SystemStatusManufacturer>     mManufacturer;
+    std::vector<SystemStatusAssistedGps>      mAssistedGps;
+    std::vector<SystemStatusScreenState>      mScreenState;
+    std::vector<SystemStatusPowerConnectState> mPowerConnectState;
+    std::vector<SystemStatusTimeZoneChange>   mTimeZoneChange;
+    std::vector<SystemStatusTimeChange>       mTimeChange;
+    std::vector<SystemStatusWifiSupplicantStatus> mWifiSupplicantStatus;
+    std::vector<SystemStatusShutdownState>    mShutdownState;
+    std::vector<SystemStatusTac>              mTac;
+    std::vector<SystemStatusMccMnc>           mMccMnc;
+    std::vector<SystemStatusBtDeviceScanDetail> mBtDeviceScanDetail;
+    std::vector<SystemStatusBtleDeviceScanDetail> mBtLeDeviceScanDetail;
+};
+
+/******************************************************************************
+ SystemStatus
+******************************************************************************/
+class SystemStatus
+{
+private:
+    static SystemStatus                       *mInstance;
+    SystemStatusOsObserver                    mSysStatusObsvr;
+    // ctor
+    SystemStatus(const MsgTask* msgTask);
+    // dtor
+    inline ~SystemStatus() {}
+
+    // Data members
+    static pthread_mutex_t                    mMutexSystemStatus;
+    SystemStatusReports mCache;
+
+    template <typename TYPE_REPORT, typename TYPE_ITEM>
+    bool setIteminReport(TYPE_REPORT& report, TYPE_ITEM&& s);
+
+    // set default dataitem derived item in report cache
+    template <typename TYPE_REPORT, typename TYPE_ITEM>
+    void setDefaultIteminReport(TYPE_REPORT& report, const TYPE_ITEM& s);
+
+    template <typename TYPE_REPORT, typename TYPE_ITEM>
+    void getIteminReport(TYPE_REPORT& reportout, const TYPE_ITEM& c) const;
+
+public:
+    // Static methods
+    static SystemStatus* getInstance(const MsgTask* msgTask);
+    static void destroyInstance();
+    IOsObserver* getOsObserver();
+
+    // Helpers
+    bool eventPosition(const UlpLocation& location,const GpsLocationExtended& locationEx);
+    bool eventDataItemNotify(IDataItemCore* dataitem);
+    bool setNmeaString(const char *data, uint32_t len);
+    bool getReport(SystemStatusReports& reports, bool isLatestonly = false) const;
+    bool setDefaultGnssEngineStates(void);
+    bool eventConnectionStatus(bool connected, int8_t type,
+                               bool roaming, NetworkHandle networkHandle, string& apn);
+    bool updatePowerConnectState(bool charging);
+    void resetNetworkInfo();
+};
+
+} // namespace loc_core
+
+#endif //__SYSTEM_STATUS__
+
diff --git a/gps/core/SystemStatusOsObserver.cpp b/gps/core/SystemStatusOsObserver.cpp
new file mode 100644
index 0000000..8fd9564
--- /dev/null
+++ b/gps/core/SystemStatusOsObserver.cpp
@@ -0,0 +1,592 @@
+/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_TAG "LocSvc_SystemStatusOsObserver"
+
+#include <algorithm>
+#include <SystemStatus.h>
+#include <SystemStatusOsObserver.h>
+#include <IDataItemCore.h>
+#include <DataItemsFactoryProxy.h>
+
+namespace loc_core
+{
+template <typename CINT, typename COUT>
+COUT SystemStatusOsObserver::containerTransfer(CINT& inContainer) {
+    COUT outContainer = {};
+    for (auto item : inContainer) {
+        outContainer.insert(outContainer.begin(), item);
+    }
+    return outContainer;
+}
+
+SystemStatusOsObserver::~SystemStatusOsObserver() {
+    // Close data-item library handle
+    DataItemsFactoryProxy::closeDataItemLibraryHandle();
+
+    // Destroy cache
+    for (auto each : mDataItemCache) {
+        if (nullptr != each.second) {
+            delete each.second;
+        }
+    }
+
+    mDataItemCache.clear();
+}
+
+void SystemStatusOsObserver::setSubscriptionObj(IDataItemSubscription* subscriptionObj)
+{
+    struct SetSubsObj : public LocMsg {
+        ObserverContext& mContext;
+        IDataItemSubscription* mSubsObj;
+        inline SetSubsObj(ObserverContext& context, IDataItemSubscription* subscriptionObj) :
+                mContext(context), mSubsObj(subscriptionObj) {}
+        void proc() const {
+            LOC_LOGi("SetSubsObj::enter");
+            mContext.mSubscriptionObj = mSubsObj;
+
+            if (!mContext.mSSObserver->mDataItemToClients.empty()) {
+                list<DataItemId> dis(
+                        containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+                                mContext.mSSObserver->mDataItemToClients.getKeys()));
+                mContext.mSubscriptionObj->subscribe(dis, mContext.mSSObserver);
+                mContext.mSubscriptionObj->requestData(dis, mContext.mSSObserver);
+            }
+            LOC_LOGi("SetSubsObj::exit");
+        }
+    };
+
+    if (nullptr == subscriptionObj) {
+        LOC_LOGw("subscriptionObj is NULL");
+    } else {
+        mContext.mMsgTask->sendMsg(new SetSubsObj(mContext, subscriptionObj));
+    }
+}
+
+/******************************************************************************
+ IDataItemSubscription Overrides
+******************************************************************************/
+void SystemStatusOsObserver::subscribe(const list<DataItemId>& l, IDataItemObserver* client,
+                                       bool toRequestData)
+{
+    struct HandleSubscribeReq : public LocMsg {
+        inline HandleSubscribeReq(SystemStatusOsObserver* parent,
+                list<DataItemId>& l, IDataItemObserver* client, bool requestData) :
+                mParent(parent), mClient(client),
+                mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)),
+                diItemlist(l),
+                mToRequestData(requestData) {}
+
+        void proc() const {
+            unordered_set<DataItemId> dataItemsToSubscribe = {};
+            mParent->mDataItemToClients.add(mDataItemSet, {mClient}, &dataItemsToSubscribe);
+            mParent->mClientToDataItems.add(mClient, mDataItemSet);
+
+            mParent->sendCachedDataItems(mDataItemSet, mClient);
+
+            // Send subscription set to framework
+            if (nullptr != mParent->mContext.mSubscriptionObj) {
+                if (mToRequestData) {
+                    LOC_LOGD("Request Data sent to framework for the following");
+                    mParent->mContext.mSubscriptionObj->requestData(diItemlist, mParent);
+                } else if (!dataItemsToSubscribe.empty()) {
+                    LOC_LOGD("Subscribe Request sent to framework for the following");
+                    mParent->logMe(dataItemsToSubscribe);
+                    mParent->mContext.mSubscriptionObj->subscribe(
+                            containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+                                    std::move(dataItemsToSubscribe)),
+                            mParent);
+                }
+            }
+        }
+        mutable SystemStatusOsObserver* mParent;
+        IDataItemObserver* mClient;
+        const unordered_set<DataItemId> mDataItemSet;
+        const list<DataItemId> diItemlist;
+        bool mToRequestData;
+    };
+
+    if (l.empty() || nullptr == client) {
+        LOC_LOGw("Data item set is empty or client is nullptr");
+    } else {
+        mContext.mMsgTask->sendMsg(
+                new HandleSubscribeReq(this, (list<DataItemId>&)l, client, toRequestData));
+    }
+}
+
+void SystemStatusOsObserver::updateSubscription(
+        const list<DataItemId>& l, IDataItemObserver* client)
+{
+    struct HandleUpdateSubscriptionReq : public LocMsg {
+        HandleUpdateSubscriptionReq(SystemStatusOsObserver* parent,
+                                    list<DataItemId>& l, IDataItemObserver* client) :
+                mParent(parent), mClient(client),
+                mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {}
+
+        void proc() const {
+            unordered_set<DataItemId> dataItemsToSubscribe = {};
+            unordered_set<DataItemId> dataItemsToUnsubscribe = {};
+            unordered_set<IDataItemObserver*> clients({mClient});
+            // below removes clients from all entries keyed with the return of the
+            // mClientToDataItems.update() call. If leaving an empty set of clients as the
+            // result, the entire entry will be removed. dataItemsToUnsubscribe will be
+            // populated to keep the keys of the removed entries.
+            mParent->mDataItemToClients.trimOrRemove(
+                    // this call updates <IDataItemObserver*, DataItemId> map; removes
+                    // the DataItemId's that are not new to the clietn from mDataItemSet;
+                    // and returns a set of mDataItemSet's that are no longer used by client.
+                    // This unused set of mDataItemSet's is passed to trimOrRemove method of
+                    // <DataItemId, IDataItemObserver*> map to remove the client from the
+                    // corresponding entries, and gets a set of the entries that are
+                    // removed from the <DataItemId, IDataItemObserver*> map as a result.
+                    mParent->mClientToDataItems.update(mClient,
+                                                       (unordered_set<DataItemId>&)mDataItemSet),
+                    clients, &dataItemsToUnsubscribe, nullptr);
+            // below adds mClient to <DataItemId, IDataItemObserver*> map, and populates
+            // new keys added to that map, which are DataItemIds to be subscribed.
+            mParent->mDataItemToClients.add(mDataItemSet, clients, &dataItemsToSubscribe);
+
+            // Send First Response
+            mParent->sendCachedDataItems(mDataItemSet, mClient);
+
+            if (nullptr != mParent->mContext.mSubscriptionObj) {
+                // Send subscription set to framework
+                if (!dataItemsToSubscribe.empty()) {
+                    LOC_LOGD("Subscribe Request sent to framework for the following");
+                    mParent->logMe(dataItemsToSubscribe);
+
+                    mParent->mContext.mSubscriptionObj->subscribe(
+                            containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+                                    std::move(dataItemsToSubscribe)),
+                            mParent);
+                }
+
+                // Send unsubscribe to framework
+                if (!dataItemsToUnsubscribe.empty()) {
+                    LOC_LOGD("Unsubscribe Request sent to framework for the following");
+                    mParent->logMe(dataItemsToUnsubscribe);
+
+                    mParent->mContext.mSubscriptionObj->unsubscribe(
+                            containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+                                    std::move(dataItemsToUnsubscribe)),
+                            mParent);
+                }
+            }
+        }
+        SystemStatusOsObserver* mParent;
+        IDataItemObserver* mClient;
+        unordered_set<DataItemId> mDataItemSet;
+    };
+
+    if (l.empty() || nullptr == client) {
+        LOC_LOGw("Data item set is empty or client is nullptr");
+    } else {
+        mContext.mMsgTask->sendMsg(
+                new HandleUpdateSubscriptionReq(this, (list<DataItemId>&)l, client));
+    }
+}
+
+void SystemStatusOsObserver::unsubscribe(
+        const list<DataItemId>& l, IDataItemObserver* client)
+{
+    struct HandleUnsubscribeReq : public LocMsg {
+        HandleUnsubscribeReq(SystemStatusOsObserver* parent,
+                list<DataItemId>& l, IDataItemObserver* client) :
+                mParent(parent), mClient(client),
+                mDataItemSet(containerTransfer<list<DataItemId>, unordered_set<DataItemId>>(l)) {}
+
+        void proc() const {
+            unordered_set<DataItemId> dataItemsUnusedByClient = {};
+            unordered_set<IDataItemObserver*> clientToRemove = {};
+            unordered_set<DataItemId> dataItemsToUnsubscribe = {};
+            mParent->mClientToDataItems.trimOrRemove({mClient}, mDataItemSet,  &clientToRemove,
+                                                     &dataItemsUnusedByClient);
+            mParent->mDataItemToClients.trimOrRemove(dataItemsUnusedByClient, {mClient},
+                                                     &dataItemsToUnsubscribe, nullptr);
+
+            if (nullptr != mParent->mContext.mSubscriptionObj && !dataItemsToUnsubscribe.empty()) {
+                LOC_LOGD("Unsubscribe Request sent to framework for the following data items");
+                mParent->logMe(dataItemsToUnsubscribe);
+
+                // Send unsubscribe to framework
+                mParent->mContext.mSubscriptionObj->unsubscribe(
+                        containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+                                  std::move(dataItemsToUnsubscribe)),
+                        mParent);
+            }
+        }
+        SystemStatusOsObserver* mParent;
+        IDataItemObserver* mClient;
+        unordered_set<DataItemId> mDataItemSet;
+    };
+
+    if (l.empty() || nullptr == client) {
+        LOC_LOGw("Data item set is empty or client is nullptr");
+    } else {
+        mContext.mMsgTask->sendMsg(new HandleUnsubscribeReq(this, (list<DataItemId>&)l, client));
+    }
+}
+
+void SystemStatusOsObserver::unsubscribeAll(IDataItemObserver* client)
+{
+    struct HandleUnsubscribeAllReq : public LocMsg {
+        HandleUnsubscribeAllReq(SystemStatusOsObserver* parent,
+                IDataItemObserver* client) :
+                mParent(parent), mClient(client) {}
+
+        void proc() const {
+            unordered_set<DataItemId> diByClient = mParent->mClientToDataItems.getValSet(mClient);
+
+            if (!diByClient.empty()) {
+                unordered_set<DataItemId> dataItemsToUnsubscribe;
+                mParent->mClientToDataItems.remove(mClient);
+                mParent->mDataItemToClients.trimOrRemove(diByClient, {mClient},
+                                                         &dataItemsToUnsubscribe, nullptr);
+
+                if (!dataItemsToUnsubscribe.empty() &&
+                    nullptr != mParent->mContext.mSubscriptionObj) {
+
+                    LOC_LOGD("Unsubscribe Request sent to framework for the following data items");
+                    mParent->logMe(dataItemsToUnsubscribe);
+
+                    // Send unsubscribe to framework
+                    mParent->mContext.mSubscriptionObj->unsubscribe(
+                            containerTransfer<unordered_set<DataItemId>, list<DataItemId>>(
+                                    std::move(dataItemsToUnsubscribe)),
+                            mParent);
+                }
+            }
+        }
+        SystemStatusOsObserver* mParent;
+        IDataItemObserver* mClient;
+    };
+
+    if (nullptr == client) {
+        LOC_LOGw("Data item set is empty or client is nullptr");
+    } else {
+        mContext.mMsgTask->sendMsg(new HandleUnsubscribeAllReq(this, client));
+    }
+}
+
+/******************************************************************************
+ IDataItemObserver Overrides
+******************************************************************************/
+void SystemStatusOsObserver::notify(const list<IDataItemCore*>& dlist)
+{
+    struct HandleNotify : public LocMsg {
+        HandleNotify(SystemStatusOsObserver* parent, vector<IDataItemCore*>& v) :
+                mParent(parent), mDiVec(std::move(v)) {}
+
+        inline virtual ~HandleNotify() {
+            for (auto item : mDiVec) {
+                delete item;
+            }
+        }
+
+        void proc() const {
+            // Update Cache with received data items and prepare
+            // list of data items to be sent.
+            unordered_set<DataItemId> dataItemIdsToBeSent = {};
+            for (auto item : mDiVec) {
+                if (mParent->updateCache(item)) {
+                    dataItemIdsToBeSent.insert(item->getId());
+                }
+            }
+
+            // Send data item to all subscribed clients
+            unordered_set<IDataItemObserver*> clientSet = {};
+            for (auto each : dataItemIdsToBeSent) {
+                auto clients = mParent->mDataItemToClients.getValSetPtr(each);
+                if (nullptr != clients) {
+                    clientSet.insert(clients->begin(), clients->end());
+                }
+            }
+
+            for (auto client : clientSet) {
+                unordered_set<DataItemId> dataItemIdsForThisClient(
+                        mParent->mClientToDataItems.getValSet(client));
+                for (auto itr = dataItemIdsForThisClient.begin();
+                        itr != dataItemIdsForThisClient.end(); ) {
+                    if (dataItemIdsToBeSent.find(*itr) == dataItemIdsToBeSent.end()) {
+                        itr = dataItemIdsForThisClient.erase(itr);
+                    } else {
+                        itr++;
+                    }
+                }
+
+                mParent->sendCachedDataItems(dataItemIdsForThisClient, client);
+            }
+        }
+        SystemStatusOsObserver* mParent;
+        const vector<IDataItemCore*> mDiVec;
+    };
+
+    if (!dlist.empty()) {
+        vector<IDataItemCore*> dataItemVec(dlist.size());
+
+        for (auto each : dlist) {
+
+            IDataItemCore* di = DataItemsFactoryProxy::createNewDataItem(each->getId());
+            if (nullptr == di) {
+                LOC_LOGw("Unable to create dataitem:%d", each->getId());
+                continue;
+            }
+
+            // Copy contents into the newly created data item
+            di->copy(each);
+
+            // add this dataitem if updated from last one
+            dataItemVec.push_back(di);
+            IF_LOC_LOGD {
+                string dv;
+                di->stringify(dv);
+                LOC_LOGd("notify: DataItem In Value:%s", dv.c_str());
+            }
+        }
+
+        if (!dataItemVec.empty()) {
+            mContext.mMsgTask->sendMsg(new HandleNotify(this, dataItemVec));
+        }
+    }
+}
+
+/******************************************************************************
+ IFrameworkActionReq Overrides
+******************************************************************************/
+void SystemStatusOsObserver::turnOn(DataItemId dit, int timeOut)
+{
+    if (nullptr == mContext.mFrameworkActionReqObj) {
+        LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__);
+        return;
+    }
+
+    // Check if data item exists in mActiveRequestCount
+    DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit);
+    if (citer == mActiveRequestCount.end()) {
+        // Data item not found in map
+        // Add reference count as 1 and add dataitem to map
+        pair<DataItemId, int> cpair(dit, 1);
+        mActiveRequestCount.insert(cpair);
+        LOC_LOGD("Sending turnOn request");
+
+        // Send action turn on to framework
+        struct HandleTurnOnMsg : public LocMsg {
+            HandleTurnOnMsg(IFrameworkActionReq* framework,
+                    DataItemId dit, int timeOut) :
+                    mFrameworkActionReqObj(framework), mDataItemId(dit), mTimeOut(timeOut) {}
+            virtual ~HandleTurnOnMsg() {}
+            void proc() const {
+                mFrameworkActionReqObj->turnOn(mDataItemId, mTimeOut);
+            }
+            IFrameworkActionReq* mFrameworkActionReqObj;
+            DataItemId mDataItemId;
+            int mTimeOut;
+        };
+        mContext.mMsgTask->sendMsg(
+                new (nothrow) HandleTurnOnMsg(mContext.mFrameworkActionReqObj, dit, timeOut));
+    }
+    else {
+        // Found in map, update reference count
+        citer->second++;
+        LOC_LOGD("turnOn - Data item:%d Num_refs:%d", dit, citer->second);
+    }
+}
+
+void SystemStatusOsObserver::turnOff(DataItemId dit)
+{
+    if (nullptr == mContext.mFrameworkActionReqObj) {
+        LOC_LOGE("%s:%d]: Framework action request object is NULL", __func__, __LINE__);
+        return;
+    }
+
+    // Check if data item exists in mActiveRequestCount
+    DataItemIdToInt::iterator citer = mActiveRequestCount.find(dit);
+    if (citer != mActiveRequestCount.end()) {
+        // found
+        citer->second--;
+        LOC_LOGD("turnOff - Data item:%d Remaining:%d", dit, citer->second);
+        if(citer->second == 0) {
+            // if this was last reference, remove item from map and turn off module
+            mActiveRequestCount.erase(citer);
+
+            // Send action turn off to framework
+            struct HandleTurnOffMsg : public LocMsg {
+                HandleTurnOffMsg(IFrameworkActionReq* framework, DataItemId dit) :
+                    mFrameworkActionReqObj(framework), mDataItemId(dit) {}
+                virtual ~HandleTurnOffMsg() {}
+                void proc() const {
+                    mFrameworkActionReqObj->turnOff(mDataItemId);
+                }
+                IFrameworkActionReq* mFrameworkActionReqObj;
+                DataItemId mDataItemId;
+            };
+            mContext.mMsgTask->sendMsg(
+                    new (nothrow) HandleTurnOffMsg(mContext.mFrameworkActionReqObj, dit));
+        }
+    }
+}
+
+#ifdef USE_GLIB
+bool SystemStatusOsObserver::connectBackhaul(const string& clientName)
+{
+    bool result = false;
+
+    if (mContext.mFrameworkActionReqObj != NULL) {
+        struct HandleConnectBackhaul : public LocMsg {
+            HandleConnectBackhaul(IFrameworkActionReq* fwkActReq, const string& clientName) :
+                    mClientName(clientName), mFwkActionReqObj(fwkActReq) {}
+            virtual ~HandleConnectBackhaul() {}
+            void proc() const {
+                LOC_LOGi("HandleConnectBackhaul::enter");
+                mFwkActionReqObj->connectBackhaul(mClientName);
+                LOC_LOGi("HandleConnectBackhaul::exit");
+            }
+            IFrameworkActionReq* mFwkActionReqObj;
+            string mClientName;
+        };
+        mContext.mMsgTask->sendMsg(
+                new (nothrow) HandleConnectBackhaul(mContext.mFrameworkActionReqObj, clientName));
+        result = true;
+    }
+    else {
+        LOC_LOGe("Framework action request object is NULL.Caching connect request: %s",
+                clientName.c_str());
+        ClientBackhaulReqCache::const_iterator iter = mBackHaulConnReqCache.find(clientName);
+        if (iter == mBackHaulConnReqCache.end()) {
+            // not found in set. first time receiving from request from client
+            LOC_LOGe("Adding client to BackHaulConnReqCache list");
+            mBackHaulConnReqCache.insert(clientName);
+        }
+        result = false;
+    }
+    return result;
+
+}
+
+bool SystemStatusOsObserver::disconnectBackhaul(const string& clientName)
+{
+    bool result = false;
+
+    if (mContext.mFrameworkActionReqObj != NULL) {
+        struct HandleDisconnectBackhaul : public LocMsg {
+            HandleDisconnectBackhaul(IFrameworkActionReq* fwkActReq, const string& clientName) :
+                    mClientName(clientName), mFwkActionReqObj(fwkActReq) {}
+            virtual ~HandleDisconnectBackhaul() {}
+            void proc() const {
+                LOC_LOGi("HandleDisconnectBackhaul::enter");
+                mFwkActionReqObj->disconnectBackhaul(mClientName);
+                LOC_LOGi("HandleDisconnectBackhaul::exit");
+            }
+            IFrameworkActionReq* mFwkActionReqObj;
+            string mClientName;
+        };
+        mContext.mMsgTask->sendMsg(
+                new (nothrow) HandleDisconnectBackhaul(mContext.mFrameworkActionReqObj,
+                        clientName));
+    }
+    else {
+        LOC_LOGe("Framework action request object is NULL.Caching disconnect request: %s",
+                clientName.c_str());
+        // Check if client has requested for backhaul connection.
+        ClientBackhaulReqCache::const_iterator iter = mBackHaulConnReqCache.find(clientName);
+        if (iter != mBackHaulConnReqCache.end()) {
+            // client found, remove from set.
+            LOC_LOGd("Removing client from BackHaulConnReqCache list");
+            mBackHaulConnReqCache.erase(iter);
+        }
+        result = false;
+    }
+    return result;
+}
+#endif
+/******************************************************************************
+ Helpers
+******************************************************************************/
+void SystemStatusOsObserver::sendCachedDataItems(
+        const unordered_set<DataItemId>& s, IDataItemObserver* to)
+{
+    if (nullptr == to) {
+        LOC_LOGv("client pointer is NULL.");
+    } else {
+        string clientName;
+        to->getName(clientName);
+        list<IDataItemCore*> dataItems = {};
+
+        for (auto each : s) {
+            auto citer = mDataItemCache.find(each);
+            if (citer != mDataItemCache.end()) {
+                string dv;
+                citer->second->stringify(dv);
+                LOC_LOGI("DataItem: %s >> %s", dv.c_str(), clientName.c_str());
+                dataItems.push_front(citer->second);
+            }
+        }
+
+        if (dataItems.empty()) {
+            LOC_LOGv("No items to notify.");
+        } else {
+            to->notify(dataItems);
+        }
+    }
+}
+
+bool SystemStatusOsObserver::updateCache(IDataItemCore* d)
+{
+    bool dataItemUpdated = false;
+
+    // Request systemstatus to record this dataitem in its cache
+    // if the return is false, it means that SystemStatus is not
+    // handling it, so SystemStatusOsObserver also doesn't.
+    // So it has to be true to proceed.
+    if (nullptr != d && mSystemStatus->eventDataItemNotify(d)) {
+        auto citer = mDataItemCache.find(d->getId());
+        if (citer == mDataItemCache.end()) {
+            // New data item; not found in cache
+            IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(d->getId());
+            if (nullptr != dataitem) {
+                // Copy the contents of the data item
+                dataitem->copy(d);
+                // Insert in mDataItemCache
+                mDataItemCache.insert(std::make_pair(d->getId(), dataitem));
+                dataItemUpdated = true;
+            }
+        } else {
+            // Found in cache; Update cache if necessary
+            citer->second->copy(d, &dataItemUpdated);
+        }
+
+        if (dataItemUpdated) {
+            LOC_LOGV("DataItem:%d updated:%d", d->getId(), dataItemUpdated);
+        }
+    }
+
+    return dataItemUpdated;
+}
+
+} // namespace loc_core
+
diff --git a/gps/core/SystemStatusOsObserver.h b/gps/core/SystemStatusOsObserver.h
new file mode 100644
index 0000000..c0f56d8
--- /dev/null
+++ b/gps/core/SystemStatusOsObserver.h
@@ -0,0 +1,181 @@
+/* Copyright (c) 2015-2017, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __SYSTEM_STATUS_OSOBSERVER__
+#define __SYSTEM_STATUS_OSOBSERVER__
+
+#include <cinttypes>
+#include <string>
+#include <list>
+#include <map>
+#include <new>
+#include <vector>
+
+#include <MsgTask.h>
+#include <DataItemId.h>
+#include <IOsObserver.h>
+#include <loc_pla.h>
+#include <log_util.h>
+#include <LocUnorderedSetMap.h>
+
+namespace loc_core
+{
+/******************************************************************************
+ SystemStatusOsObserver
+******************************************************************************/
+using namespace std;
+using namespace loc_util;
+
+// Forward Declarations
+class IDataItemCore;
+class SystemStatus;
+class SystemStatusOsObserver;
+typedef map<IDataItemObserver*, list<DataItemId>> ObserverReqCache;
+typedef LocUnorderedSetMap<IDataItemObserver*, DataItemId> ClientToDataItems;
+typedef LocUnorderedSetMap<DataItemId, IDataItemObserver*> DataItemToClients;
+typedef unordered_map<DataItemId, IDataItemCore*> DataItemIdToCore;
+typedef unordered_map<DataItemId, int> DataItemIdToInt;
+#ifdef USE_GLIB
+// Cache details of backhaul client requests
+typedef unordered_set<string> ClientBackhaulReqCache;
+#endif
+
+struct ObserverContext {
+    IDataItemSubscription* mSubscriptionObj;
+    IFrameworkActionReq* mFrameworkActionReqObj;
+    const MsgTask* mMsgTask;
+    SystemStatusOsObserver* mSSObserver;
+
+    inline ObserverContext(const MsgTask* msgTask, SystemStatusOsObserver* observer) :
+            mSubscriptionObj(NULL), mFrameworkActionReqObj(NULL),
+            mMsgTask(msgTask), mSSObserver(observer) {}
+};
+
+// Clients wanting to get data from OS/Framework would need to
+// subscribe with OSObserver using IDataItemSubscription interface.
+// Such clients would need to implement IDataItemObserver interface
+// to receive data when it becomes available.
+class SystemStatusOsObserver : public IOsObserver {
+
+public:
+    // ctor
+    inline SystemStatusOsObserver(SystemStatus* systemstatus, const MsgTask* msgTask) :
+            mSystemStatus(systemstatus), mContext(msgTask, this),
+            mAddress("SystemStatusOsObserver"),
+            mClientToDataItems(MAX_DATA_ITEM_ID), mDataItemToClients(MAX_DATA_ITEM_ID) {}
+
+    // dtor
+    ~SystemStatusOsObserver();
+
+    template <typename CINT, typename COUT>
+    static COUT containerTransfer(CINT& s);
+    template <typename CINT, typename COUT>
+    inline static COUT containerTransfer(CINT&& s) {
+        return containerTransfer<CINT, COUT>(s);
+    }
+
+    // To set the subscription object
+    virtual void setSubscriptionObj(IDataItemSubscription* subscriptionObj);
+
+    // To set the framework action request object
+    inline void setFrameworkActionReqObj(IFrameworkActionReq* frameworkActionReqObj) {
+        mContext.mFrameworkActionReqObj = frameworkActionReqObj;
+#ifdef USE_GLIB
+        uint32_t numBackHaulClients = mBackHaulConnReqCache.size();
+        if (numBackHaulClients > 0) {
+            // For each client, invoke connectbackhaul.
+            for (auto clientName : mBackHaulConnReqCache) {
+                LOC_LOGd("Invoke connectBackhaul for client: %s", clientName.c_str());
+                connectBackhaul(clientName);
+            }
+            // Clear the set
+            mBackHaulConnReqCache.clear();
+        }
+#endif
+    }
+
+    // IDataItemSubscription Overrides
+    inline virtual void subscribe(const list<DataItemId>& l, IDataItemObserver* client) override {
+        subscribe(l, client, false);
+    }
+    virtual void updateSubscription(const list<DataItemId>& l, IDataItemObserver* client) override;
+    inline virtual void requestData(const list<DataItemId>& l, IDataItemObserver* client) override {
+        subscribe(l, client, true);
+    }
+    virtual void unsubscribe(const list<DataItemId>& l, IDataItemObserver* client) override;
+    virtual void unsubscribeAll(IDataItemObserver* client) override;
+
+    // IDataItemObserver Overrides
+    virtual void notify(const list<IDataItemCore*>& dlist) override;
+    inline virtual void getName(string& name) override {
+        name = mAddress;
+    }
+
+    // IFrameworkActionReq Overrides
+    virtual void turnOn(DataItemId dit, int timeOut = 0) override;
+    virtual void turnOff(DataItemId dit) override;
+#ifdef USE_GLIB
+    virtual bool connectBackhaul(const string& clientName) override;
+    virtual bool disconnectBackhaul(const string& clientName) override;
+#endif
+
+private:
+    SystemStatus*                                    mSystemStatus;
+    ObserverContext                                  mContext;
+    const string                                     mAddress;
+    ClientToDataItems                                mClientToDataItems;
+    DataItemToClients                                mDataItemToClients;
+    DataItemIdToCore                                 mDataItemCache;
+    DataItemIdToInt                                  mActiveRequestCount;
+
+    // Cache the subscribe and requestData till subscription obj is obtained
+    void cacheObserverRequest(ObserverReqCache& reqCache,
+            const list<DataItemId>& l, IDataItemObserver* client);
+#ifdef USE_GLIB
+    // Cache the framework action request for connect/disconnect
+    ClientBackhaulReqCache  mBackHaulConnReqCache;
+#endif
+
+    void subscribe(const list<DataItemId>& l, IDataItemObserver* client, bool toRequestData);
+
+    // Helpers
+    void sendCachedDataItems(const unordered_set<DataItemId>& s, IDataItemObserver* to);
+    bool updateCache(IDataItemCore* d);
+    inline void logMe(const unordered_set<DataItemId>& l) {
+        IF_LOC_LOGD {
+            for (auto id : l) {
+                LOC_LOGD("DataItem %d", id);
+            }
+        }
+    }
+};
+
+} // namespace loc_core
+
+#endif //__SYSTEM_STATUS__
+
diff --git a/gps/core/configure.ac b/gps/core/configure.ac
new file mode 100644
index 0000000..19db9cf
--- /dev/null
+++ b/gps/core/configure.ac
@@ -0,0 +1,107 @@
+# configure.ac -- Autoconf script for gps loc-core
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps loc-hal package version 1.0.0
+AC_INIT([loc-core],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([loc-core.pc.in])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+AC_ARG_WITH([core_includes],
+      AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
+         [Specify the location of the core headers]),
+      [core_incdir=$withval],
+      with_core_includes=no)
+
+if test "x$with_core_includes" != "xno"; then
+   CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
+fi
+
+AC_ARG_WITH([locpla_includes],
+      AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+         [specify the path to locpla-includes in loc-pla_git.bb]),
+      [locpla_incdir=$withval],
+      with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+   AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_SUBST([CPPFLAGS])
+
+AC_ARG_WITH([glib],
+      AC_HELP_STRING([--with-glib],
+         [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+        AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+        PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GThread >= 2.16 is required))
+        PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GLib >= 2.16 is required))
+        GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+        GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+        AC_SUBST(GLIB_CFLAGS)
+        AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_ARG_WITH([auto_feature],
+    AC_HELP_STRING([--with-auto_feature=@<:@dir@:>@],
+        [Using Automotive feature]),
+    [],
+    with_auto_feature=no)
+
+if test "x$with_auto_feature" != "xno"; then
+    CPPFLAGS="${CPPFLAGS} -DFEATURE_AUTOMOTIVE"
+fi
+
+AM_CONDITIONAL(USE_FEATURE_AUTOMOTIVE, test "x${with_auto_feature}" = "xyes")
+
+# External AP
+AC_ARG_WITH([external_ap],
+    AC_HELP_STRING([--with-external_ap=@<:@dir@:>@],
+        [Using External Application Processor]),
+    [],
+    with_external_ap=no)
+
+if test "x$with_external_ap" != "xno"; then
+    CPPFLAGS="${CPPFLAGS} -DFEATURE_EXTERNAL_AP"
+fi
+
+AM_CONDITIONAL(USE_EXTERNAL_AP, test "x${with_external_ap}" = "xyes")
+
+AC_CONFIG_FILES([ \
+        Makefile \
+        loc-core.pc \
+        ])
+
+AC_OUTPUT
diff --git a/gps/core/data-items/DataItemConcreteTypesBase.h b/gps/core/data-items/DataItemConcreteTypesBase.h
new file mode 100644
index 0000000..11a3cce
--- /dev/null
+++ b/gps/core/data-items/DataItemConcreteTypesBase.h
@@ -0,0 +1,555 @@
+/* Copyright (c) 2015-2017, 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __DATAITEMCONCRETEBASETYPES__
+#define __DATAITEMCONCRETEBASETYPES__
+
+#include <string>
+#include <cstring>
+#include <sstream>
+#include <DataItemId.h>
+#include <IDataItemCore.h>
+#include <gps_extended_c.h>
+#include <inttypes.h>
+
+#define MAC_ADDRESS_LENGTH    6
+// MAC address length in bytes
+// QMI_LOC_SRN_MAC_ADDR_LENGTH_V02
+#define SRN_MAC_ADDRESS_LENGTH    6
+#define WIFI_SUPPLICANT_DEFAULT_STATE    0
+
+static constexpr char sDelimit = ':';
+
+namespace loc_core
+{
+using namespace std;
+
+enum NetworkType {
+    TYPE_MOBILE = 0,
+    TYPE_WIFI,
+    TYPE_ETHERNET,
+    TYPE_BLUETOOTH,
+    TYPE_MMS,
+    TYPE_SUPL,
+    TYPE_DUN,
+    TYPE_HIPRI,
+    TYPE_WIMAX,
+    TYPE_PROXY,
+    TYPE_UNKNOWN,
+};
+
+typedef struct NetworkInfoType
+{
+    // Unique network handle ID
+    uint64_t networkHandle;
+    // Type of network for corresponding network handle
+    NetworkType networkType;
+    NetworkInfoType() : networkHandle(NETWORK_HANDLE_UNKNOWN), networkType(TYPE_UNKNOWN) {}
+    NetworkInfoType(string strObj) {
+        size_t posDelimit = strObj.find(sDelimit);
+
+        if ( posDelimit != string::npos) {
+            int32_t type = TYPE_UNKNOWN;
+            string handleStr = strObj.substr(0, posDelimit);
+            string typeStr = strObj.substr(posDelimit + 1, strObj.length() - posDelimit - 1);
+            stringstream(handleStr) >> networkHandle;
+            stringstream(typeStr) >> type;
+            networkType = (NetworkType) type;
+        } else {
+            networkHandle = NETWORK_HANDLE_UNKNOWN;
+            networkType = TYPE_UNKNOWN;
+        }
+    }
+    bool operator== (const NetworkInfoType& other) {
+        return ((networkHandle == other.networkHandle) && (networkType == other.networkType));
+    }
+    string toString() {
+        string valueStr;
+        valueStr.clear ();
+        char nethandle [32];
+        memset (nethandle, 0, 32);
+        snprintf(nethandle, sizeof(nethandle), "%" PRIu64, networkHandle);
+        valueStr += string(nethandle);
+        valueStr += sDelimit;
+        char type [12];
+        memset (type, 0, 12);
+        snprintf (type, 12, "%u", networkType);
+        valueStr += string (type);
+        return valueStr;
+    }
+} NetworkInfoType;
+
+
+class AirplaneModeDataItemBase : public IDataItemCore  {
+public:
+    AirplaneModeDataItemBase(bool mode):
+        mMode(mode),
+        mId(AIRPLANEMODE_DATA_ITEM_ID) {}
+    virtual ~AirplaneModeDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    bool mMode;
+
+protected:
+    DataItemId mId;
+};
+
+class ENHDataItemBase : public IDataItemCore {
+public:
+    ENHDataItemBase(bool enabled) :
+        mEnabled(enabled),
+        mId(ENH_DATA_ITEM_ID) {}
+    virtual ~ENHDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    bool mEnabled;
+protected:
+    DataItemId mId;
+};
+
+class GPSStateDataItemBase : public IDataItemCore {
+public:
+    GPSStateDataItemBase(bool enabled) :
+        mEnabled(enabled),
+        mId(GPSSTATE_DATA_ITEM_ID) {}
+    virtual ~GPSStateDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    bool mEnabled;
+protected:
+    DataItemId mId;
+};
+
+class NLPStatusDataItemBase : public IDataItemCore {
+public:
+    NLPStatusDataItemBase(bool enabled) :
+        mEnabled(enabled),
+        mId(NLPSTATUS_DATA_ITEM_ID) {}
+    virtual ~NLPStatusDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    bool mEnabled;
+protected:
+    DataItemId mId;
+};
+
+class WifiHardwareStateDataItemBase : public IDataItemCore {
+public:
+    WifiHardwareStateDataItemBase(bool enabled) :
+        mEnabled(enabled),
+        mId(WIFIHARDWARESTATE_DATA_ITEM_ID) {}
+    virtual ~WifiHardwareStateDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    bool mEnabled;
+protected:
+    DataItemId mId;
+};
+
+class ScreenStateDataItemBase : public IDataItemCore {
+public:
+    ScreenStateDataItemBase(bool state) :
+        mState(state),
+        mId(SCREEN_STATE_DATA_ITEM_ID) {}
+    virtual ~ScreenStateDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    bool mState;
+protected:
+    DataItemId mId;
+};
+
+class PowerConnectStateDataItemBase : public IDataItemCore {
+public:
+    PowerConnectStateDataItemBase(bool state) :
+        mState(state),
+        mId(POWER_CONNECTED_STATE_DATA_ITEM_ID) {}
+    virtual ~PowerConnectStateDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    bool mState;
+protected:
+    DataItemId mId;
+};
+
+class TimeZoneChangeDataItemBase : public IDataItemCore {
+public:
+    TimeZoneChangeDataItemBase(int64_t currTimeMillis, int32_t rawOffset, int32_t dstOffset) :
+        mCurrTimeMillis (currTimeMillis),
+        mRawOffsetTZ (rawOffset),
+        mDstOffsetTZ (dstOffset),
+        mId(TIMEZONE_CHANGE_DATA_ITEM_ID) {}
+    virtual ~TimeZoneChangeDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    int64_t mCurrTimeMillis;
+    int32_t mRawOffsetTZ;
+    int32_t mDstOffsetTZ;
+protected:
+    DataItemId mId;
+};
+
+class TimeChangeDataItemBase : public IDataItemCore {
+public:
+    TimeChangeDataItemBase(int64_t currTimeMillis, int32_t rawOffset, int32_t dstOffset) :
+        mCurrTimeMillis (currTimeMillis),
+        mRawOffsetTZ (rawOffset),
+        mDstOffsetTZ (dstOffset),
+        mId(TIME_CHANGE_DATA_ITEM_ID) {}
+    virtual ~TimeChangeDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    int64_t mCurrTimeMillis;
+    int32_t mRawOffsetTZ;
+    int32_t mDstOffsetTZ;
+protected:
+    DataItemId mId;
+};
+
+class ShutdownStateDataItemBase : public IDataItemCore {
+public:
+    ShutdownStateDataItemBase(bool state) :
+        mState (state),
+        mId(SHUTDOWN_STATE_DATA_ITEM_ID) {}
+    virtual ~ShutdownStateDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    bool mState;
+protected:
+    DataItemId mId;
+};
+
+class AssistedGpsDataItemBase : public IDataItemCore {
+public:
+    AssistedGpsDataItemBase(bool enabled) :
+        mEnabled(enabled),
+        mId(ASSISTED_GPS_DATA_ITEM_ID) {}
+    virtual ~AssistedGpsDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    bool mEnabled;
+protected:
+    DataItemId mId;
+};
+
+class NetworkInfoDataItemBase : public IDataItemCore {
+public:
+    NetworkInfoDataItemBase(
+    NetworkType initialType, int32_t type, string typeName, string subTypeName,
+    bool available, bool connected, bool roaming, uint64_t networkHandle, string apn):
+            mAllTypes(typeToAllTypes(initialType)),
+            mType(type),
+            mTypeName(typeName),
+            mSubTypeName(subTypeName),
+            mAvailable(available),
+            mConnected(connected),
+            mRoaming(roaming),
+            mNetworkHandle(networkHandle),
+            mId(NETWORKINFO_DATA_ITEM_ID), mApn(apn) {
+                mAllNetworkHandles[0].networkHandle = networkHandle;
+                mAllNetworkHandles[0].networkType = initialType;
+            }
+    virtual ~NetworkInfoDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+    inline virtual NetworkType getType(void) const {
+        return (NetworkType)mType;
+    }
+    inline uint64_t getAllTypes() { return mAllTypes; }
+    inline NetworkInfoType* getNetworkHandle() {
+        return &mAllNetworkHandles[0];
+    }
+    // Data members
+    uint64_t mAllTypes;
+    int32_t mType;
+    string mTypeName;
+    string mSubTypeName;
+    bool mAvailable;
+    bool mConnected;
+    bool mRoaming;
+    NetworkInfoType mAllNetworkHandles[MAX_NETWORK_HANDLES];
+    uint64_t mNetworkHandle;
+    string mApn;
+protected:
+    DataItemId mId;
+    inline uint64_t typeToAllTypes(NetworkType type) {
+        return (type >= TYPE_UNKNOWN || type < TYPE_MOBILE) ?  0 : (1<<type);
+    }
+};
+
+class ServiceStatusDataItemBase : public IDataItemCore {
+public:
+    ServiceStatusDataItemBase(int32_t serviceState) :
+        mServiceState (serviceState),
+        mId(SERVICESTATUS_DATA_ITEM_ID) {}
+    virtual ~ServiceStatusDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    int32_t mServiceState;
+protected:
+    DataItemId mId;
+};
+
+class ModelDataItemBase : public IDataItemCore {
+public:
+    ModelDataItemBase(const string & name) :
+        mModel (name),
+        mId(MODEL_DATA_ITEM_ID) {}
+    virtual ~ModelDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    string mModel;
+protected:
+    DataItemId mId;
+};
+
+class ManufacturerDataItemBase : public IDataItemCore {
+public:
+    ManufacturerDataItemBase(const string & name) :
+        mManufacturer (name),
+        mId(MANUFACTURER_DATA_ITEM_ID) {}
+    virtual ~ManufacturerDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    string mManufacturer;
+protected:
+    DataItemId mId;
+};
+
+class RilServiceInfoDataItemBase : public IDataItemCore {
+public:
+    inline RilServiceInfoDataItemBase() :
+            mData(nullptr), mId(RILSERVICEINFO_DATA_ITEM_ID) {}
+    inline virtual ~RilServiceInfoDataItemBase() { if (nullptr != mData) free(mData); }
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+    inline RilServiceInfoDataItemBase(const RilServiceInfoDataItemBase& peer) :
+            RilServiceInfoDataItemBase() {
+        peer.setPeerData(*this);
+    }
+    inline virtual bool operator==(const RilServiceInfoDataItemBase& other) const {
+        return other.mData == mData;
+    }
+    inline virtual void setPeerData(RilServiceInfoDataItemBase& /*peer*/) const {}
+    void* mData;
+protected:
+    DataItemId mId;
+};
+
+class RilCellInfoDataItemBase : public IDataItemCore {
+public:
+    inline RilCellInfoDataItemBase() :
+            mData(nullptr), mId(RILCELLINFO_DATA_ITEM_ID) {}
+    inline virtual ~RilCellInfoDataItemBase() { if (nullptr != mData) free(mData); }
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+    inline RilCellInfoDataItemBase(const RilCellInfoDataItemBase& peer) :
+            RilCellInfoDataItemBase() {
+        peer.setPeerData(*this);
+    }
+    inline virtual bool operator==(const RilCellInfoDataItemBase& other) const {
+        return other.mData == mData;
+    }
+    inline virtual void setPeerData(RilCellInfoDataItemBase& /*peer*/) const {}
+    void* mData;
+protected:
+    DataItemId mId;
+};
+
+class WifiSupplicantStatusDataItemBase : public IDataItemCore {
+public:
+    WifiSupplicantStatusDataItemBase() :
+        mState((WifiSupplicantState)WIFI_SUPPLICANT_DEFAULT_STATE),
+        mApMacAddressValid(false),
+        mWifiApSsidValid(false),
+        mId(WIFI_SUPPLICANT_STATUS_DATA_ITEM_ID) {
+            memset (&mApMacAddress, 0, sizeof (mApMacAddress));
+            mWifiApSsid.clear();
+        }
+    virtual ~WifiSupplicantStatusDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+    // Data members
+    typedef enum WifiSupplicantState {
+        DISCONNECTED,
+        INTERFACE_DISABLED,
+        INACTIVE,
+        SCANNING,
+        AUTHENTICATING,
+        ASSOCIATING,
+        ASSOCIATED,
+        FOUR_WAY_HANDSHAKE,
+        GROUP_HANDSHAKE,
+        COMPLETED,
+        DORMANT,
+        UNINITIALIZED,
+        INVALID
+    } WifiSupplicantState;
+    /* Represents whether access point attach state*/
+    WifiSupplicantState mState;
+    /* Represents info on whether ap mac address is valid */
+    bool mApMacAddressValid;
+    /* Represents mac address of the wifi access point*/
+    uint8_t mApMacAddress[MAC_ADDRESS_LENGTH];
+    /* Represents info on whether ap SSID is valid */
+    bool mWifiApSsidValid;
+    /* Represents Wifi SSID string*/
+    string mWifiApSsid;
+protected:
+    DataItemId mId;
+};
+
+class TacDataItemBase : public IDataItemCore {
+public:
+    TacDataItemBase(const string & name) :
+        mValue (name),
+        mId(TAC_DATA_ITEM_ID) {}
+    virtual ~TacDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    string mValue;
+protected:
+    DataItemId mId;
+};
+
+class MccmncDataItemBase : public IDataItemCore {
+public:
+    MccmncDataItemBase(const string & name) :
+        mValue(name),
+        mId(MCCMNC_DATA_ITEM_ID) {}
+    virtual ~MccmncDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+// Data members
+    string mValue;
+protected:
+    DataItemId mId;
+};
+
+class SrnDeviceScanDetailsDataItemBase : public IDataItemCore {
+public:
+    SrnDeviceScanDetailsDataItemBase(DataItemId Id) :
+        mValidSrnData(false),
+        mApSrnRssi(-1),
+        mApSrnTimestamp(0),
+        mRequestTimestamp(0),
+        mReceiveTimestamp(0),
+        mErrorCause(-1),
+        mId(Id) {}
+    virtual ~SrnDeviceScanDetailsDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+    // Data members common to all SRN tech types
+    /* Represents info on whether SRN data is valid (no error)*/
+    bool mValidSrnData;
+    /* SRN device RSSI reported */
+    int32_t mApSrnRssi;
+    /* MAC adress of SRN device */
+    uint8_t mApSrnMacAddress[SRN_MAC_ADDRESS_LENGTH];
+    /* UTC timestamp at which the scan was requested.for this SRN device*/
+    int64_t mApSrnTimestamp;
+    /* UTC timestamp at which the scan was started. */
+    int64_t mRequestTimestamp;
+    /* UTC timestamp at which the scan was received.*/
+    int64_t mReceiveTimestamp;
+    /* Reason for the error/failure if SRN details are not valid */
+    int32_t mErrorCause;
+protected:
+    DataItemId mId;
+};
+
+class BtDeviceScanDetailsDataItemBase : public SrnDeviceScanDetailsDataItemBase {
+
+public:
+    BtDeviceScanDetailsDataItemBase() :
+        SrnDeviceScanDetailsDataItemBase(BT_SCAN_DATA_ITEM_ID) {}
+    virtual ~BtDeviceScanDetailsDataItemBase() {}
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+};
+
+class BtLeDeviceScanDetailsDataItemBase : public SrnDeviceScanDetailsDataItemBase {
+
+public:
+    BtLeDeviceScanDetailsDataItemBase() :
+        SrnDeviceScanDetailsDataItemBase(BTLE_SCAN_DATA_ITEM_ID) {}
+    virtual ~BtLeDeviceScanDetailsDataItemBase() {}
+    virtual void stringify(string& /*valueStr*/) {}
+    virtual int32_t copy(IDataItemCore* /*src*/, bool* /*dataItemCopied = NULL*/) {return 1;}
+};
+
+class BatteryLevelDataItemBase : public IDataItemCore {
+public:
+    inline BatteryLevelDataItemBase(uint8_t batteryPct) :
+            mBatteryPct(batteryPct), mId(BATTERY_LEVEL_DATA_ITEM_ID) {}
+    inline ~BatteryLevelDataItemBase() {}
+    inline virtual DataItemId getId() { return mId; }
+// Data members
+    uint8_t mBatteryPct;
+protected:
+    DataItemId mId;
+};
+
+} // namespace loc_core
+
+#endif //__DATAITEMCONCRETEBASETYPES__
diff --git a/gps/core/data-items/DataItemId.h b/gps/core/data-items/DataItemId.h
new file mode 100644
index 0000000..1661be6
--- /dev/null
+++ b/gps/core/data-items/DataItemId.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __DATAITEMID_H__
+#define __DATAITEMID_H__
+
+/**
+ * Enumeration of Data Item types
+ * When add/remove/update changes are made to Data Items, this file needs to be updated
+ * accordingly
+ */
+typedef enum e_DataItemId {
+    INVALID_DATA_ITEM_ID = -1,
+    // 0 - 4
+    AIRPLANEMODE_DATA_ITEM_ID,
+    ENH_DATA_ITEM_ID,
+    GPSSTATE_DATA_ITEM_ID,
+    NLPSTATUS_DATA_ITEM_ID,
+    WIFIHARDWARESTATE_DATA_ITEM_ID,
+    // 5 - 9
+    NETWORKINFO_DATA_ITEM_ID,
+    RILVERSION_DATA_ITEM_ID,
+    RILSERVICEINFO_DATA_ITEM_ID,
+    RILCELLINFO_DATA_ITEM_ID,
+    SERVICESTATUS_DATA_ITEM_ID,
+    // 10 - 14
+    MODEL_DATA_ITEM_ID,
+    MANUFACTURER_DATA_ITEM_ID,
+    VOICECALL_DATA_ITEM,
+    ASSISTED_GPS_DATA_ITEM_ID,
+    SCREEN_STATE_DATA_ITEM_ID,
+    // 15 - 19
+    POWER_CONNECTED_STATE_DATA_ITEM_ID,
+    TIMEZONE_CHANGE_DATA_ITEM_ID,
+    TIME_CHANGE_DATA_ITEM_ID,
+    WIFI_SUPPLICANT_STATUS_DATA_ITEM_ID,
+    SHUTDOWN_STATE_DATA_ITEM_ID,
+    // 20 - 24
+    TAC_DATA_ITEM_ID,
+    MCCMNC_DATA_ITEM_ID,
+    BTLE_SCAN_DATA_ITEM_ID,
+    BT_SCAN_DATA_ITEM_ID,
+    OEM_GTP_UPLOAD_TRIGGER_READY_ITEM_ID,
+
+    MAX_DATA_ITEM_ID,
+
+    // 26 -
+    BATTERY_LEVEL_DATA_ITEM_ID,
+
+    MAX_DATA_ITEM_ID_1_1,
+} DataItemId;
+
+#endif // #ifndef __DATAITEMID_H__
diff --git a/gps/core/data-items/DataItemsFactoryProxy.cpp b/gps/core/data-items/DataItemsFactoryProxy.cpp
new file mode 100644
index 0000000..10f73f4
--- /dev/null
+++ b/gps/core/data-items/DataItemsFactoryProxy.cpp
@@ -0,0 +1,82 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_TAG "DataItemsFactoryProxy"
+
+#include <dlfcn.h>
+#include <DataItemId.h>
+#include <IDataItemCore.h>
+#include <DataItemsFactoryProxy.h>
+#include <loc_pla.h>
+#include <log_util.h>
+#include "loc_misc_utils.h"
+
+namespace loc_core
+{
+void* DataItemsFactoryProxy::dataItemLibHandle = NULL;
+get_concrete_data_item_fn* DataItemsFactoryProxy::getConcreteDIFunc = NULL;
+
+IDataItemCore* DataItemsFactoryProxy::createNewDataItem(DataItemId id)
+{
+    IDataItemCore *mydi = nullptr;
+
+    if (NULL != getConcreteDIFunc) {
+        mydi = (*getConcreteDIFunc)(id);
+    }
+    else {
+        getConcreteDIFunc = (get_concrete_data_item_fn * )
+                dlGetSymFromLib(dataItemLibHandle, DATA_ITEMS_LIB_NAME, DATA_ITEMS_GET_CONCRETE_DI);
+
+        if (NULL != getConcreteDIFunc) {
+            LOC_LOGd("Loaded function %s : %p", DATA_ITEMS_GET_CONCRETE_DI, getConcreteDIFunc);
+            mydi = (*getConcreteDIFunc)(id);
+        }
+        else {
+            // dlysm failed.
+            const char * err = dlerror();
+            if (NULL == err)
+            {
+                err = "Unknown";
+            }
+            LOC_LOGe("failed to find symbol %s; error=%s", DATA_ITEMS_GET_CONCRETE_DI, err);
+        }
+    }
+    return mydi;
+}
+
+void DataItemsFactoryProxy::closeDataItemLibraryHandle()
+{
+    if (NULL != dataItemLibHandle) {
+        dlclose(dataItemLibHandle);
+        dataItemLibHandle = NULL;
+    }
+}
+
+} // namespace loc_core
+
+
diff --git a/gps/core/data-items/DataItemsFactoryProxy.h b/gps/core/data-items/DataItemsFactoryProxy.h
new file mode 100644
index 0000000..cfd447d
--- /dev/null
+++ b/gps/core/data-items/DataItemsFactoryProxy.h
@@ -0,0 +1,55 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __DATAITEMFACTORYBASE__
+#define __DATAITEMFACTORYBASE__
+
+#include <DataItemId.h>
+#include <IDataItemCore.h>
+
+namespace loc_core
+{
+
+#define DATA_ITEMS_LIB_NAME "libdataitems.so"
+#define DATA_ITEMS_GET_CONCRETE_DI "getConcreteDataItem"
+
+typedef IDataItemCore * (get_concrete_data_item_fn)(DataItemId);
+
+class DataItemsFactoryProxy {
+public:
+    static IDataItemCore* createNewDataItem(DataItemId id);
+    static void closeDataItemLibraryHandle();
+    static void *dataItemLibHandle;
+    static get_concrete_data_item_fn *getConcreteDIFunc;
+};
+
+} // namespace loc_core
+
+#endif //__DATAITEMFACTORYBASE__
+
diff --git a/gps/core/data-items/IDataItemCore.h b/gps/core/data-items/IDataItemCore.h
new file mode 100644
index 0000000..6084c92
--- /dev/null
+++ b/gps/core/data-items/IDataItemCore.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __IDATAITEMCORE_H__
+#define __IDATAITEMCORE_H__
+
+#include <string>
+#include <DataItemId.h>
+
+namespace loc_core {
+
+using namespace std;
+
+/**
+ * @brief IDataItemCore interface.
+ * @details IDataItemCore interface.
+ *
+ */
+class IDataItemCore {
+public:
+    /**
+     * @brief Gets Data item id.
+     * @details Gets Data item id.
+     * @return Data item id.
+     */
+    virtual DataItemId getId () = 0;
+
+    /**
+     * @brief Stringify.
+     * @details Stringify.
+     *
+     * @param valueStr Reference to string.
+     */
+    virtual void stringify (string & valueStr) = 0;
+
+    /**
+     * @brief copy.
+     * @details copy.
+     *
+     * @param src Where to copy from.
+     * @param dataItemCopied Boolean flag indicated whether or not copied.
+     *
+     * @return Zero for success or non zero for failure.
+     */
+    virtual int32_t copy (IDataItemCore * src, bool *dataItemCopied = nullptr) = 0;
+
+    /**
+     * @brief Destructor.
+     * @details Destructor.
+     */
+    virtual ~IDataItemCore () {}
+};
+
+} // namespace loc_core
+
+#endif // __IDATAITEMCORE_H__
diff --git a/gps/core/loc-core.pc.in b/gps/core/loc-core.pc.in
new file mode 100644
index 0000000..76b514c
--- /dev/null
+++ b/gps/core/loc-core.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: loc-core
+Description: QTI GPS Loc Core
+Version: @VERSION@
+Libs: -L${libdir} -lloc_core
+Cflags: -I${includedir}/loc-core
diff --git a/gps/core/loc_core_log.cpp b/gps/core/loc_core_log.cpp
new file mode 100644
index 0000000..904f94b
--- /dev/null
+++ b/gps/core/loc_core_log.cpp
@@ -0,0 +1,215 @@
+/* Copyright (c) 2011-2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_core_log"
+
+#include <log_util.h>
+#include <loc_log.h>
+#include <loc_core_log.h>
+#include <loc_pla.h>
+
+void LocPosMode::logv() const
+{
+    LOC_LOGV ("Position mode: %s\n  Position recurrence: %s\n  "
+              "min interval: %d\n  preferred accuracy: %d\n  "
+              "preferred time: %d\n  credentials: %s  provider: %s \n  "
+              "power mode: %d\n  tbm %d",
+              loc_get_position_mode_name(mode),
+              loc_get_position_recurrence_name(recurrence),
+              min_interval,
+              preferred_accuracy,
+              preferred_time,
+              credentials,
+              provider,
+              powerMode,
+              timeBetweenMeasurements);
+}
+
+/* GPS status names */
+DECLARE_TBL(gps_status_name) =
+{
+    NAME_VAL( LOC_GPS_STATUS_NONE ),
+    NAME_VAL( LOC_GPS_STATUS_SESSION_BEGIN ),
+    NAME_VAL( LOC_GPS_STATUS_SESSION_END ),
+    NAME_VAL( LOC_GPS_STATUS_ENGINE_ON ),
+    NAME_VAL( LOC_GPS_STATUS_ENGINE_OFF ),
+};
+
+/* Find Android GPS status name */
+const char* loc_get_gps_status_name(LocGpsStatusValue gps_status)
+{
+    return loc_get_name_from_val(gps_status_name_tbl, (int64_t) gps_status);
+}
+
+
+
+DECLARE_TBL(loc_eng_position_modes) =
+{
+    NAME_VAL( LOC_POSITION_MODE_STANDALONE ),
+    NAME_VAL( LOC_POSITION_MODE_MS_BASED ),
+    NAME_VAL( LOC_POSITION_MODE_MS_ASSISTED ),
+    NAME_VAL( LOC_POSITION_MODE_RESERVED_1 ),
+    NAME_VAL( LOC_POSITION_MODE_RESERVED_2 ),
+    NAME_VAL( LOC_POSITION_MODE_RESERVED_3 ),
+    NAME_VAL( LOC_POSITION_MODE_RESERVED_4 ),
+    NAME_VAL( LOC_POSITION_MODE_RESERVED_5 )
+};
+
+const char* loc_get_position_mode_name(LocGpsPositionMode mode)
+{
+    return loc_get_name_from_val(loc_eng_position_modes_tbl, (int64_t) mode);
+}
+
+
+
+DECLARE_TBL(loc_eng_position_recurrences) =
+{
+    NAME_VAL( LOC_GPS_POSITION_RECURRENCE_PERIODIC ),
+    NAME_VAL( LOC_GPS_POSITION_RECURRENCE_SINGLE )
+};
+
+const char* loc_get_position_recurrence_name(LocGpsPositionRecurrence recur)
+{
+    return loc_get_name_from_val(loc_eng_position_recurrences_tbl, (int64_t) recur);
+}
+
+const char* loc_get_aiding_data_mask_names(LocGpsAidingData /*data*/)
+{
+    return NULL;
+}
+
+
+DECLARE_TBL(loc_eng_agps_types) =
+{
+    NAME_VAL( LOC_AGPS_TYPE_INVALID ),
+    NAME_VAL( LOC_AGPS_TYPE_ANY ),
+    NAME_VAL( LOC_AGPS_TYPE_SUPL ),
+    NAME_VAL( LOC_AGPS_TYPE_C2K ),
+    NAME_VAL( LOC_AGPS_TYPE_WWAN_ANY )
+};
+
+const char* loc_get_agps_type_name(LocAGpsType type)
+{
+    return loc_get_name_from_val(loc_eng_agps_types_tbl, (int64_t) type);
+}
+
+
+DECLARE_TBL(loc_eng_ni_types) =
+{
+    NAME_VAL( LOC_GPS_NI_TYPE_VOICE ),
+    NAME_VAL( LOC_GPS_NI_TYPE_UMTS_SUPL ),
+    NAME_VAL( LOC_GPS_NI_TYPE_UMTS_CTRL_PLANE ),
+    NAME_VAL( LOC_GPS_NI_TYPE_EMERGENCY_SUPL )
+};
+
+const char* loc_get_ni_type_name(LocGpsNiType type)
+{
+    return loc_get_name_from_val(loc_eng_ni_types_tbl, (int64_t) type);
+}
+
+
+DECLARE_TBL(loc_eng_ni_responses) =
+{
+    NAME_VAL( LOC_GPS_NI_RESPONSE_ACCEPT ),
+    NAME_VAL( LOC_GPS_NI_RESPONSE_DENY ),
+    NAME_VAL( LOC_GPS_NI_RESPONSE_DENY )
+};
+
+const char* loc_get_ni_response_name(LocGpsUserResponseType response)
+{
+    return loc_get_name_from_val(loc_eng_ni_responses_tbl, (int64_t) response);
+}
+
+
+DECLARE_TBL(loc_eng_ni_encodings) =
+{
+    NAME_VAL( LOC_GPS_ENC_NONE ),
+    NAME_VAL( LOC_GPS_ENC_SUPL_GSM_DEFAULT ),
+    NAME_VAL( LOC_GPS_ENC_SUPL_UTF8 ),
+    NAME_VAL( LOC_GPS_ENC_SUPL_UCS2 ),
+    NAME_VAL( LOC_GPS_ENC_UNKNOWN )
+};
+
+const char* loc_get_ni_encoding_name(LocGpsNiEncodingType encoding)
+{
+    return loc_get_name_from_val(loc_eng_ni_encodings_tbl, (int64_t) encoding);
+}
+
+DECLARE_TBL(loc_eng_agps_bears) =
+{
+    NAME_VAL( AGPS_APN_BEARER_INVALID ),
+    NAME_VAL( AGPS_APN_BEARER_IPV4 ),
+    NAME_VAL( AGPS_APN_BEARER_IPV6 ),
+    NAME_VAL( AGPS_APN_BEARER_IPV4V6 )
+};
+
+const char* loc_get_agps_bear_name(AGpsBearerType bearer)
+{
+    return loc_get_name_from_val(loc_eng_agps_bears_tbl, (int64_t) bearer);
+}
+
+DECLARE_TBL(loc_eng_server_types) =
+{
+    NAME_VAL( LOC_AGPS_CDMA_PDE_SERVER ),
+    NAME_VAL( LOC_AGPS_CUSTOM_PDE_SERVER ),
+    NAME_VAL( LOC_AGPS_MPC_SERVER ),
+    NAME_VAL( LOC_AGPS_SUPL_SERVER )
+};
+
+const char* loc_get_server_type_name(LocServerType type)
+{
+    return loc_get_name_from_val(loc_eng_server_types_tbl, (int64_t) type);
+}
+
+DECLARE_TBL(loc_eng_position_sess_status_types) =
+{
+    NAME_VAL( LOC_SESS_SUCCESS ),
+    NAME_VAL( LOC_SESS_INTERMEDIATE ),
+    NAME_VAL( LOC_SESS_FAILURE )
+};
+
+const char* loc_get_position_sess_status_name(enum loc_sess_status status)
+{
+    return loc_get_name_from_val(loc_eng_position_sess_status_types_tbl, (int64_t) status);
+}
+
+DECLARE_TBL(loc_eng_agps_status_names) =
+{
+    NAME_VAL( LOC_GPS_REQUEST_AGPS_DATA_CONN ),
+    NAME_VAL( LOC_GPS_RELEASE_AGPS_DATA_CONN ),
+    NAME_VAL( LOC_GPS_AGPS_DATA_CONNECTED ),
+    NAME_VAL( LOC_GPS_AGPS_DATA_CONN_DONE ),
+    NAME_VAL( LOC_GPS_AGPS_DATA_CONN_FAILED )
+};
+
+const char* loc_get_agps_status_name(LocAGpsStatusValue status)
+{
+    return loc_get_name_from_val(loc_eng_agps_status_names_tbl, (int64_t) status);
+}
diff --git a/gps/core/loc_core_log.h b/gps/core/loc_core_log.h
new file mode 100644
index 0000000..2beb687
--- /dev/null
+++ b/gps/core/loc_core_log.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2011-2013, 2016-2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOC_CORE_LOG_H
+#define LOC_CORE_LOG_H
+
+#include <ctype.h>
+#include <gps_extended.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+const char* loc_get_gps_status_name(LocGpsStatusValue gps_status);
+const char* loc_get_position_mode_name(LocGpsPositionMode mode);
+const char* loc_get_position_recurrence_name(LocGpsPositionRecurrence recur);
+const char* loc_get_aiding_data_mask_names(LocGpsAidingData data);
+const char* loc_get_agps_type_name(LocAGpsType type);
+const char* loc_get_ni_type_name(LocGpsNiType type);
+const char* loc_get_ni_response_name(LocGpsUserResponseType response);
+const char* loc_get_ni_encoding_name(LocGpsNiEncodingType encoding);
+const char* loc_get_agps_bear_name(AGpsBearerType bear);
+const char* loc_get_server_type_name(LocServerType type);
+const char* loc_get_position_sess_status_name(enum loc_sess_status status);
+const char* loc_get_agps_status_name(LocAGpsStatusValue status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LOC_CORE_LOG_H */
diff --git a/gps/core/observer/IDataItemObserver.h b/gps/core/observer/IDataItemObserver.h
new file mode 100644
index 0000000..7954d85
--- /dev/null
+++ b/gps/core/observer/IDataItemObserver.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __IDATAITEMOBSERVER_H__
+#define __IDATAITEMOBSERVER_H__
+
+#include  <list>
+#include <string>
+
+using namespace std;
+
+namespace loc_core
+{
+class IDataItemCore;
+
+/**
+ * @brief IDataItemObserver interface
+ * @details IDataItemObserver interface;
+ *          In OS dependent code this type serves as a handle to an OS independent instance of this interface.
+ */
+class IDataItemObserver {
+
+public:
+
+    /**
+     * @brief Gets name of Data Item Observer
+     * @details Gets name of Data Item Observer
+     *
+     * @param name reference to name of Data Item Observer
+     */
+    virtual void getName (string & name) = 0;
+
+    /**
+     * @brief Notify updated values of Data Items
+     * @details Notifys updated values of Data items
+     *
+     * @param dlist List of updated data items
+     */
+    virtual void notify (const std :: list <IDataItemCore *> & dlist)  = 0;
+
+    /**
+     * @brief Destructor
+     * @details Destructor
+     */
+    virtual ~IDataItemObserver () {}
+};
+
+} // namespace loc_core
+
+#endif // #ifndef __IDATAITEMOBSERVER_H__
diff --git a/gps/core/observer/IDataItemSubscription.h b/gps/core/observer/IDataItemSubscription.h
new file mode 100644
index 0000000..7e8b8c8
--- /dev/null
+++ b/gps/core/observer/IDataItemSubscription.h
@@ -0,0 +1,129 @@
+/* Copyright (c) 2015, 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __IDATAITEMSUBSCRIPTION_H__
+#define __IDATAITEMSUBSCRIPTION_H__
+
+#include  <list>
+#include  <DataItemId.h>
+
+namespace loc_core
+{
+class IDataItemObserver;
+
+/**
+ * @brief IDataItemSubscription interface
+ * @details IDataItemSubscription interface;
+ *          Defines an interface for operations such as subscribe,
+ *          unsubscribe data items by their IDs.
+ *          Must be implemented by OS dependent code.
+ */
+class IDataItemSubscription {
+
+public:
+    /**
+     * @brief Subscribe for data items by their IDs
+     * @details Subscribe for data items by their IDs;
+     *          An IDataItemObserver implementer invokes this method to subscribe
+     *          for a list of DataItems by passing in their Ids.
+     *          A symbolic invocation of this method in the following order
+     *          subscribe ( {1,2,3}, &obj), subscribe ( {2,3,4,5}, &obj)
+     *          where the numbers enclosed in braces indicate a list of data item Ids
+     *          will cause this class implementer to update its subscription list for
+     *          &obj to only contain the following Data Item Ids 1,2,3,4,5.
+     *
+     * @param l List of DataItemId
+     * @param o Pointer to an instance of IDataItemObserver
+     */
+    virtual void subscribe (const std :: list <DataItemId> & l, IDataItemObserver * o = NULL) = 0;
+
+    /**
+     * @brief Update subscription for Data items
+     * @details Update subscription for Data items;
+     *          An IDataItemObserver implementer invokes this method to update their
+     *          subscription for a list of DataItems by passing in their Ids
+     *          A symbolic invocation of this method in the following order
+     *          updateSubscription ( {1,2,3}, &obj),updateSubscription ( {2,3,4,5}, &obj)
+     *          where the numbers enclosed in braces indicate a list of data item Ids
+     *          will cause this class implementer to update its subscription list for
+     *          &obj to only contain the following Data Item Ids 2,3,4,5.
+     *          Note that this method may or may not be called.
+     *
+     * @param l List of DataItemId
+     * @param o Pointer to an instance of IDataItemObserver
+     */
+    virtual void updateSubscription (const std :: list <DataItemId> & l, IDataItemObserver * o = NULL) = 0;
+
+    /**
+     * @brief Request Data
+     * @details Request Data
+     *
+     * @param l List of DataItemId
+     * @param o Pointer to an instance of IDataItemObserver
+     */
+    virtual void requestData (const std :: list <DataItemId> & l, IDataItemObserver * o = NULL) = 0;
+
+    /**
+     * @brief Unsubscribe Data items
+     * @details Unsubscrbe Data items;
+     *          An IDataItemObserver implementer invokes this method to unsubscribe their
+     *          subscription for a list of DataItems by passing in their Ids
+     *          Suppose this class implementor has a currently active subscription list
+     *          containing 1,2,3,4,5,6,7 for &obj then a symbolic invocation of this
+     *          method in the following order
+     *          unsubscribe ( {1,2,3}, &obj), unsubscribe (  {1,2,3,4}, &obj),
+     *          unsubscribe ( {7}, &obj)
+     *          where the numbers enclosed in braces indicate a list of data item Ids
+     *          will cause this class implementer to update its subscription list for
+     *          &obj to only contain the following data item id 5,6.
+     *
+     * @param l List of DataItemId
+     * @param o Pointer to an instance of IDataItemObserver
+     */
+    virtual void unsubscribe (const std :: list <DataItemId> & l, IDataItemObserver * o = NULL) = 0;
+
+    /**
+     * @brief Unsubscribe all data items
+     * @details Unsubscribe all data items
+     *
+     * @param o Pointer to an instance of IDataItemObserver
+     */
+    virtual void unsubscribeAll (IDataItemObserver * o = NULL) = 0;
+
+    /**
+     * @brief Destructor
+     * @details Destructor
+     */
+    virtual ~IDataItemSubscription () {}
+};
+
+} // namespace loc_core
+
+#endif // #ifndef __IDATAITEMSUBSCRIPTION_H__
+
diff --git a/gps/core/observer/IFrameworkActionReq.h b/gps/core/observer/IFrameworkActionReq.h
new file mode 100644
index 0000000..138508c
--- /dev/null
+++ b/gps/core/observer/IFrameworkActionReq.h
@@ -0,0 +1,104 @@
+/* Copyright (c) 2017, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __IFRAMEWORKACTIONREQ_H__
+#define __IFRAMEWORKACTIONREQ_H__
+
+#include <string>
+#include  <DataItemId.h>
+
+using namespace std;
+
+namespace loc_core
+{
+
+/**
+ * @brief IFrameworkActionReq interface
+ * @details IFrameworkActionReq interface;
+ *          Defines an interface for operations such as turnOn, turnOff a
+ *          framework module described by the data item. Framework module
+ *          could be bluetooth, wifi etc.
+ *          Must be implemented by OS dependent code.
+ *
+ */
+class IFrameworkActionReq {
+
+public:
+    /**
+     * @brief Turn on the framework module described by the data item.
+     * @details  Turn on the framework module described by the data item;
+     *          An IFrameworkActionReq implementer invokes this method to
+     *          turn on the framework module described by the data item.
+     *          Framework module could be bluetooth, wifi etc.
+     *
+     * @param dit DataItemId
+     * @param timeout Timeout after which to turn off the framework module.
+     */
+    virtual void turnOn (DataItemId dit, int timeOut = 0) = 0;
+
+    /**
+     * @brief Turn off the framework module described by the data item.
+     * @details  Turn off the framework module described by the data item;
+     *          An IFrameworkActionReq implementer invokes this method to
+     *          turn off the framework module described by the data item.
+     *          Framework module could be bluetooth, wifi etc.
+     *
+     * @param dit DataItemId
+     */
+    virtual void turnOff (DataItemId dit) = 0;
+
+#ifdef USE_GLIB
+    /**
+     * @brief Setup WWAN backhaul
+     * @details  Setup WWAN backhaul
+     *
+     * @param None
+     */
+    virtual bool connectBackhaul(const string& clientName) = 0;
+
+    /**
+     * @brief Disconnects the WWANbackhaul
+     * @details Disconnects the WWANbackhaul, only if it was setup by us
+     *
+     * @param None
+     */
+    virtual bool disconnectBackhaul(const string& clientName) = 0;
+#endif
+
+    /**
+     * @brief Destructor
+     * @details Destructor
+     */
+    virtual ~IFrameworkActionReq () {}
+};
+
+} // namespace loc_core
+
+#endif // #ifndef __IFRAMEWORKACTIONREQ_H__
+
diff --git a/gps/core/observer/IOsObserver.h b/gps/core/observer/IOsObserver.h
new file mode 100644
index 0000000..a25bb9f
--- /dev/null
+++ b/gps/core/observer/IOsObserver.h
@@ -0,0 +1,107 @@
+/* Copyright (c) 2017, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __IOSOBSERVER_H__
+#define __IOSOBSERVER_H__
+
+#include  <list>
+#include <string>
+#include <IDataItemObserver.h>
+#include <IDataItemSubscription.h>
+#include <IFrameworkActionReq.h>
+
+using namespace std;
+
+namespace loc_core
+{
+
+/**
+ * @brief IOsObserver interface
+ * @details IOsObserver interface;
+ *          In OS dependent code this type serves as a handle to
+ *          an OS independent instance of this interface.
+ */
+class IOsObserver :
+                public IDataItemObserver,
+                public IDataItemSubscription,
+                public IFrameworkActionReq {
+
+public:
+
+    // To set the subscription object
+    virtual void setSubscriptionObj(IDataItemSubscription *subscriptionObj) = 0;
+
+    // To set the framework action request object
+    virtual void setFrameworkActionReqObj(IFrameworkActionReq *frameworkActionReqObj) = 0;
+
+    // IDataItemObserver Overrides
+    inline virtual void getName (string & /*name*/) {}
+    inline virtual void notify (const std::list <IDataItemCore *> & /*dlist*/) {}
+
+    // IDataItemSubscription Overrides
+    inline virtual void subscribe
+    (
+        const std :: list <DataItemId> & /*l*/,
+        IDataItemObserver * /*client*/
+    ){}
+    inline virtual void updateSubscription
+    (
+        const std :: list <DataItemId> & /*l*/,
+        IDataItemObserver * /*client*/
+    ){}
+    inline virtual void requestData
+    (
+        const std :: list <DataItemId> & /*l*/,
+        IDataItemObserver * /*client*/
+    ){}
+    inline virtual void unsubscribe
+    (
+        const std :: list <DataItemId> & /*l*/,
+        IDataItemObserver * /*client*/
+    ){}
+    inline virtual void unsubscribeAll (IDataItemObserver * /*client*/){}
+
+    // IFrameworkActionReq Overrides
+    inline virtual void turnOn (DataItemId /*dit*/, int /*timeOut*/){}
+    inline virtual void turnOff (DataItemId /*dit*/) {}
+#ifdef USE_GLIB
+    inline virtual bool connectBackhaul(const string& clientName) { return false; }
+    inline virtual bool disconnectBackhaul(const string& clientName) { return false; }
+#endif
+
+    /**
+     * @brief Destructor
+     * @details Destructor
+     */
+    virtual ~IOsObserver () {}
+};
+
+} // namespace loc_core
+
+#endif // #ifndef __IOSOBSERVER_H__
diff --git a/gps/etc/Android.bp b/gps/etc/Android.bp
new file mode 100644
index 0000000..897c3f3
--- /dev/null
+++ b/gps/etc/Android.bp
@@ -0,0 +1,49 @@
+
+prebuilt_etc {
+
+    name: "gps.conf",
+    vendor: true,
+    src: "gps.conf",
+}
+
+prebuilt_etc {
+
+    name: "flp.conf",
+    vendor: true,
+    src: "flp.conf",
+}
+
+prebuilt_etc {
+
+    name: "gnss_antenna_info.conf",
+    vendor: true,
+    src: "gnss_antenna_info.conf",
+}
+
+prebuilt_etc {
+    name: "gnss@2.0-base.policy",
+    vendor: true,
+    sub_dir: "seccomp_policy",
+    src: "seccomp_policy/gnss@2.0-base.policy",
+}
+
+prebuilt_etc {
+    name: "gnss@2.0-xtra-daemon.policy",
+    vendor: true,
+    sub_dir: "seccomp_policy",
+    src: "seccomp_policy/gnss@2.0-xtra-daemon.policy",
+}
+
+prebuilt_etc {
+    name: "gnss@2.0-xtwifi-client.policy",
+    vendor: true,
+    sub_dir: "seccomp_policy",
+    src: "seccomp_policy/gnss@2.0-xtwifi-client.policy",
+}
+
+prebuilt_etc {
+    name: "gnss@2.0-xtwifi-inet-agent.policy",
+    vendor: true,
+    sub_dir: "seccomp_policy",
+    src: "seccomp_policy/gnss@2.0-xtwifi-inet-agent.policy",
+}
diff --git a/gps/etc/flp.conf b/gps/etc/flp.conf
new file mode 100644
index 0000000..65d54d3
--- /dev/null
+++ b/gps/etc/flp.conf
@@ -0,0 +1,60 @@
+###################################
+#####       FLP settings      #####
+###################################
+
+###################################
+# FLP BATCH SIZE
+###################################
+# The number of batched locations
+# requested to modem. The desired number
+# defined below may not be satisfied, as
+# the modem can only return the number
+# of batched locations that can be allocated,
+# which is limited by memory. The default
+# batch size defined as 20 as below.
+BATCH_SIZE=20
+
+###################################
+# FLP OUTDOOR TRIP BATCH SIZE
+###################################
+# The number of batched locations
+# requested to modem for outdoor
+# trip batching. The desired number
+# defined below may not be satisfied, as
+# the modem can only return the number
+# of batched locations that can be allocated,
+# which is limited by memory. The default
+# trip batch size defined as 600 as below.
+OUTDOOR_TRIP_BATCH_SIZE=600
+
+###################################
+# FLP BATCHING SESSION TIMEOUT
+###################################
+# Duration with which batch session timeout
+# happens in milliseconds. If not specified
+# or set to zero, batching session timeout
+# defaults to 20 seconds by the modem.
+# BATCH_SESSION_TIMEOUT=20000
+
+###################################
+# FLP BATCHING ACCURACY
+###################################
+# Set to one of the defined values below
+# to define the accuracy of batching.
+# If not specified, accuracy defaults
+# to LOW.
+# FLP BATCHING ACCURACY values:
+# Low accuracy = 0
+# Medium accuracy = 1
+# High accuracy = 2
+ACCURACY=1
+
+####################################
+# By default if network fixes are not sensor assisted
+# these fixes must be dropped. This parameter adds an exception
+# for targets where there is no PDR and we still want to
+# report out network fixes
+# 0: MUST NOT ALLOW NETWORK FIXES
+# 1: ALLOW NETWORK FIXES
+####################################
+ALLOW_NETWORK_FIXES = 0
diff --git a/gps/etc/gnss_antenna_info.conf b/gps/etc/gnss_antenna_info.conf
new file mode 100644
index 0000000..e037daa
--- /dev/null
+++ b/gps/etc/gnss_antenna_info.conf
@@ -0,0 +1,135 @@
+###################################
+#####   ANTENNA INFORMATION   #####
+###################################
+
+###################################
+# ANTENNA INFO VECTOR SIZE
+###################################
+# The number of antenna info
+# structures in the vector. Each
+# entry in this vector is a structure
+# with the following elements:
+#
+# - CARRIER_FREQUENCY
+# - PC_OFFSET
+# - PC_VARIATION_CORRECTION
+# - PC_VARIATION_CORRECTION_UNC
+# - SIGNAL_GAIN_CORRECTION
+# - SIGNAL_GAIN_CORRECTION_UNC
+#
+# Notes:
+# CARRIER_FREQUENCY
+#   The carrier frequency in MHz.
+#
+# PC = PHASE CENTER
+#   PC_OFFSET is a structure with six
+#   elements: x, y, z and their associated uncertainties
+#   Phase center offset (PCO) is defined with
+#   respect to the origin of the Android sensor coordinate system, e.g.,
+#   center of primary screen for mobiles
+#
+# PC_VARIATION_CORRECTION
+#   2D vectors representing the phase center variation (PCV) corrections,
+#   in millimeters, at regularly spaced azimuthal angle (theta) and zenith angle
+#   (phi). The PCV correction is added to the phase measurement to obtain the
+#   corrected value.
+#   The azimuthal angle, theta, is defined with respect to the X axis of the
+#   Android sensor coordinate system, increasing toward the Y axis. The zenith
+#   angle, phi, is defined with respect to the Z axis of the Android Sensor
+#   coordinate system, increasing toward the X-Y plane.
+#   Each row vector (outer vectors) represents a fixed theta. The first row
+#   corresponds to a theta angle of 0 degrees. The last row corresponds to a
+#   theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular
+#   spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows).
+#   The columns (inner vectors) represent fixed zenith angles, beginning at 0
+#   degrees and ending at 180 degrees. They are separated by deltaPhi, the regular
+#   spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1).
+#
+# PC_VARIATION_CORRECTION_UNC
+#   2D vectors of 1-sigma uncertainty in millimeters associated with the PCV
+#   correction values.
+#
+# SIGNAL_GAIN_CORRECTION
+#   2D vectors representing the signal gain corrections at regularly spaced
+#   azimuthal angle (theta) and zenith angle (phi). The values are calculated or
+#   measured at the antenna feed point without considering the radio and receiver
+#   noise figure and path loss contribution, in dBi, i.e., decibel over isotropic
+#   antenna with the same total power. The signal gain correction is added the
+#   signal gain measurement to obtain the corrected value.
+#   The azimuthal angle, theta, is defined with respect to the X axis of the
+#   Android sensor coordinate system, increasing toward the Y axis. The zenith
+#   angle, phi, is defined with respect to the Z axis of the Android Sensor
+#   coordinate system, increasing toward the X-Y plane.
+#   Each row vector (outer vectors) represents a fixed theta. The first row
+#   corresponds to a theta angle of 0 degrees. The last row corresponds to a
+#   theta angle of (360 - deltaTheta) degrees, where deltaTheta is the regular
+#   spacing between azimuthal angles, i.e., deltaTheta = 360 / (number of rows).
+#   The columns (inner vectors) represent fixed zenith angles, beginning at 0
+#   degrees and ending at 180 degrees. They are separated by deltaPhi, the regular
+#   spacing between zenith angles, i.e., deltaPhi = 180 / (number of columns - 1).
+#
+# SIGNAL_GAIN_CORRECTION_UNC
+#   2D vectors of 1-sigma uncertainty in dBi associated with the signal
+#   gain correction values.
+#
+# The number of rows and columns could be the same for PC variation correction
+# and signal gain corrections, or could be different
+# If the former then NUMBER_OF_ROWS_ and NUMBER_OF_COLUMNS_ are specified once
+# only, if the latter then NUMBER_OF_ROWS_ and NUMBER_OF_COLUMNS_ represent
+# the number of rows/columns for PC variation correction and
+# NUMBER_OF_ROWS_SGC_ and NUMBER_OF_COLUMNS_SGC_ represent the number of
+# rows/columns for signal gain corrections
+
+# ANTENNA_INFO_VECTOR_SIZE must be non zero if antenna corrections are sent
+# ANTENNA_INFO_VECTOR_SIZE = 2
+
+CARRIER_FREQUENCY_0 = 1575.42
+
+PC_OFFSET_0 = 1.2 0.1 3.4 0.2 5.6 0.3
+
+NUMBER_OF_ROWS_0 = 3
+NUMBER_OF_COLUMNS_0 = 4
+
+PC_VARIATION_CORRECTION_0_ROW_0 = 11.22 33.44 55.66 77.88
+PC_VARIATION_CORRECTION_0_ROW_1 = 10.2 30.4 50.6 70.8
+PC_VARIATION_CORRECTION_0_ROW_2 = 12.2 34.4 56.6 78.8
+
+PC_VARIATION_CORRECTION_UNC_0_ROW_0 = 0.1 0.2 0.3 0.4
+PC_VARIATION_CORRECTION_UNC_0_ROW_1 = 1.1 1.2 1.3 1.4
+PC_VARIATION_CORRECTION_UNC_0_ROW_2 = 2.1 2.2 2.3 2.4
+
+SIGNAL_GAIN_CORRECTION_0_ROW_0 = 9.8 8.7 7.6 6.5
+SIGNAL_GAIN_CORRECTION_0_ROW_1 = 5.4 4.3 3.2 2.1
+SIGNAL_GAIN_CORRECTION_0_ROW_2 = 1.3 2.4 3.5 4.6
+
+SIGNAL_GAIN_CORRECTION_UNC_0_ROW_0 = 0.11 0.22 0.33 0.44
+SIGNAL_GAIN_CORRECTION_UNC_0_ROW_1 = 0.55 0.66 0.77 0.88
+SIGNAL_GAIN_CORRECTION_UNC_0_ROW_2 = 0.91 0.92 0.93 0.94
+
+
+CARRIER_FREQUENCY_1 = 1227.6
+
+PC_OFFSET_1 = 3.4 0.2 5.6 0.3 1.2 0.1
+
+NUMBER_OF_ROWS_1 = 4
+NUMBER_OF_COLUMNS_1 = 2
+NUMBER_OF_ROWS_SGC_1 = 3
+NUMBER_OF_COLUMNS_SGC_1 = 4
+
+PC_VARIATION_CORRECTION_1_ROW_0 = 55.66 77.88
+PC_VARIATION_CORRECTION_1_ROW_1 = 11.22 33.44
+PC_VARIATION_CORRECTION_1_ROW_2 = 56.6 78.8
+PC_VARIATION_CORRECTION_1_ROW_3 = 12.2 34.4
+
+PC_VARIATION_CORRECTION_UNC_1_ROW_0 = 0.3 0.4
+PC_VARIATION_CORRECTION_UNC_1_ROW_1 = 1.1 1.2
+PC_VARIATION_CORRECTION_UNC_1_ROW_2 = 2.1 2.2
+PC_VARIATION_CORRECTION_UNC_1_ROW_3 = 0.1 0.2
+
+SIGNAL_GAIN_CORRECTION_1_ROW_0 = 7.6 6.5 5.4 4.3
+SIGNAL_GAIN_CORRECTION_1_ROW_1 = 1.3 2.4 9.8 8.7
+SIGNAL_GAIN_CORRECTION_1_ROW_2 = 1.4 2.5 3.6 4.7
+
+SIGNAL_GAIN_CORRECTION_UNC_1_ROW_0 = 0.91 0.92 0.55 0.66
+SIGNAL_GAIN_CORRECTION_UNC_1_ROW_1 = 0.11 0.22 0.93 0.94
+SIGNAL_GAIN_CORRECTION_UNC_1_ROW_2 = 0.95 0.96 0.33 0.44
diff --git a/gps/etc/gps.conf b/gps/etc/gps.conf
new file mode 100644
index 0000000..75f12f2
--- /dev/null
+++ b/gps/etc/gps.conf
@@ -0,0 +1,391 @@
+# Error Estimate
+# _SET = 1
+# _CLEAR = 0
+ERR_ESTIMATE=0
+
+#NTP server
+NTP_SERVER=time.xtracloud.net
+
+#XTRA CA path
+XTRA_CA_PATH=/usr/lib/ssl-1.1/certs
+
+# DEBUG LEVELS: 0 - none, 1 - Error, 2 - Warning, 3 - Info
+#               4 - Debug, 5 - Verbose
+# If DEBUG_LEVEL is commented, Android's logging levels will be used
+DEBUG_LEVEL = 3
+
+# Intermediate position report, 1=enable, 0=disable
+INTERMEDIATE_POS=0
+
+# supl version 1.0
+SUPL_VER=0x10000
+
+# Emergency SUPL, 1=enable, 0=disable
+#SUPL_ES=1
+
+#Choose PDN for Emergency SUPL
+#1 - Use emergency PDN
+#0 - Use regular SUPL PDN for Emergency SUPL
+#USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL=0
+
+#SUPL_MODE is a bit mask set in config.xml per carrier by default.
+#If it is uncommented here, this value will overwrite the value from
+#config.xml.
+#MSA=0X2
+#MSB=0X1
+#SUPL_MODE=
+
+# GPS Capabilities bit mask
+# SCHEDULING = 0x01
+# MSB = 0x02
+# MSA = 0x04
+# ON_DEMAND_TIME = 0x10
+# default = ON_DEMAND_TIME | MSA | MSB | SCHEDULING
+CAPABILITIES=0x17
+
+# Accuracy threshold for intermediate positions
+# less accurate positions are ignored, 0 for passing all positions
+# ACCURACY_THRES=5000
+
+################################
+##### AGPS server settings #####
+################################
+
+# FOR SUPL SUPPORT, set the following
+# SUPL_HOST=supl.host.com or IP
+# SUPL_PORT=1234
+
+# FOR MO SUPL SUPPORT, set the following
+# MO_SUPL_HOST=supl.host.com or IP
+# MO_SUPL_PORT=1234
+
+# FOR C2K PDE SUPPORT, set the following
+# C2K_HOST=c2k.pde.com or IP
+# C2K_PORT=1234
+
+# Bitmask of slots that are available
+# for write/install to, where 1s indicate writable,
+# and the default value is 0 where no slots
+# are writable. For example, AGPS_CERT_WRITABLE_MASK
+# of b1000001010 makes 3 slots available
+# and the remaining 7 slots unwritable.
+#AGPS_CERT_WRITABLE_MASK=0
+
+####################################
+#  LTE Positioning Profile Settings
+####################################
+# LPP_PROFILE is a bit mask
+# 0: Enable RRLP on LTE(Default)
+# 0x1: LPP User Plane
+# 0x2: LPP Control Plane
+# 0x4: LPP User Plane for NR5G
+# 0x8: LPP Control Plane for NR5G
+LPP_PROFILE = 2
+
+####################################
+#Datum Type
+####################################
+# 0: WGS-84
+# 1: PZ-90
+DATUM_TYPE = 0
+
+################################
+# EXTRA SETTINGS
+################################
+# NMEA provider (1=Modem Processor, 0=Application Processor)
+NMEA_PROVIDER=0
+
+################################
+# NMEA TAG BLOCK GROUPING
+################################
+# NMEA tag block grouping is only applicable to GSA
+# Default is disabled
+# 0 - disabled
+# 1 - enabled
+NMEA_TAG_BLOCK_GROUPING_ENABLED = 0
+
+# Customized NMEA GGA fix quality that can be used to tell
+# whether SENSOR contributed to the fix.
+#
+# When this configuration item is not enabled (set to any value that is not 1),
+# GGA fix quality conforms to NMEA standard spec as below:
+# PPP/DGNSS/SBAS correction fix w/ or w/o sensor: 2
+# RTK fixed fix w/ or w/o sensor: 4
+# RTK float fix w/ or w/o sensor: 5
+# SPE fix w/ or w/o sensor: 1
+# Sensor dead reckoning fix: 6
+#
+# When this configuration is enabled (set to 1), GGA fix quality
+# will be output as below:
+# PPP fix w/o sensor: 59,                  w/ sensor: 69
+# DGNSS/SBAS correction fix w/o sensor: 2, w/ sensor: 62
+# RTK fixed fix w/o sensor: 4,             w/ sensor: 64
+# RTK float fix w/o sensor: 5,             w/ sensor: 65,
+# SPE fix w/o sensor: 1,               and w/ sensor: 61
+# Sensor dead reckoning fix: 6
+#
+# any value that is not 1 - disabled
+# 1 - enabled
+CUSTOM_NMEA_GGA_FIX_QUALITY_ENABLED = 0
+
+################################
+# NMEA Reporting Rate Config, valid only when NMEA_PROVIDER is set to "0"
+################################
+# NMEA Reporting Rate
+# Set it to "1HZ" for 1Hz NMEA Reporting
+# Set it to "NHZ" for NHz NMEA Reporting
+#Default : NHZ (overridden by position update rate if set to lower rates)
+NMEA_REPORT_RATE=NHZ
+
+# Mark if it is a SGLTE target (1=SGLTE, 0=nonSGLTE)
+SGLTE_TARGET=0
+
+##################################################
+# Select Positioning Protocol on A-GLONASS system
+##################################################
+# 0x1: RRC CPlane
+# 0x2: RRLP UPlane
+# 0x4: LLP Uplane
+A_GLONASS_POS_PROTOCOL_SELECT = 0
+
+##################################################
+# Select technology for LPPe Control Plane
+##################################################
+# 0x1: DBH for LPPe CP
+# 0x2: WLAN AP Measurements for LPPe CP
+# 0x4: SRN AP measurement for CP
+# 0x8: Sensor Barometer Measurement LPPe CP
+#LPPE_CP_TECHNOLOGY = 0
+
+##################################################
+# Select technology for LPPe User Plane
+##################################################
+# 0x1: DBH for LPPe UP
+# 0x2: WLAN AP Measurements for LPPe UP
+# 0x4: SRN AP measurement for UP
+# 0x8: Sensor Barometer Measurement LPPe UP
+#LPPE_UP_TECHNOLOGY = 0
+
+##################################################
+# AGPS_CONFIG_INJECT
+##################################################
+# enable/disable injection of AGPS configurations:
+#     SUPL_VER
+#     SUPL_HOST
+#     SUPL_PORT
+#     MO_SUPL_HOST
+#     MO_SUPL_PORT
+#     C2K_HOST
+#     C2K_PORT
+#     LPP_PROFILE
+#     A_GLONASS_POS_PROTOCOL_SELECT
+# 0: disable
+# 1: enable
+AGPS_CONFIG_INJECT = 1
+
+##################################################
+# GNSS settings for automotive use cases
+# Configurations in following section are
+# specific to automotive use cases, others
+# please do not change, keep the default values
+##################################################
+
+# AP Coarse Timestamp Uncertainty
+##################################################
+# default : 10
+# AP time stamp uncertainty, until GNSS receiver
+# is able to acquire better timing information
+AP_TIMESTAMP_UNCERTAINTY = 10
+
+#####################################
+# DR_SYNC Pulse Availability
+#####################################
+# 0 : DR_SYNC pulse not available (default)
+# 1 : DR_SYNC pulse available
+# This configuration enables the driver to make use
+# of PPS events generated by DR_SYNC pulse
+# Standard Linux PPS driver needs to be enabled
+DR_SYNC_ENABLED = 0
+
+#####################################
+# PPS Device name
+#####################################
+PPS_DEVICENAME = /dev/pps0
+
+#####################################
+# Ignore PPS at Startup and after long outage
+#####################################
+IGNORE_PPS_PULSE_COUNT = 1
+
+#####################################
+# Long GNSS RF outage in seconds
+#####################################
+GNSS_OUTAGE_DURATION = 10
+
+#####################################
+# AP Clock Accuracy
+#####################################
+# Quality of APPS processor clock (in PPM).
+# Value specified is used for calculation of
+# APPS time stamp uncertainty
+AP_CLOCK_PPM = 100
+
+#####################################
+# MAX ms difference to detect missing pulse
+#####################################
+# Specifies time threshold in ms to validate any missing PPS pulses
+MISSING_PULSE_TIME_DELTA = 900
+
+#####################################
+# Propagation time uncertainty
+#####################################
+# This settings enables time uncertainty propagation
+# logic incase of missing PPS pulse
+PROPAGATION_TIME_UNCERTAINTY = 1
+
+#######################################
+#  APN / IP Type Configuration
+#  APN and IP Type to use for setting
+#  up WWAN call.
+#  Use below values for IP Type:
+#  v4 = 4
+#  v6 = 6
+#  v4v6 = 10
+#######################################
+# INTERNET_APN = abc.xyz
+# INTERNET_IP_TYPE = 4
+# SUPL_APN = abc.xyz
+# SUPL_IP_TYPE = 4
+
+#####################################
+# Modem type
+#####################################
+# This setting configures modem type
+# (external=0 or internal=1)
+# comment out the next line to vote
+# for the first modem in the list
+MODEM_TYPE = 1
+
+##################################################
+# CONSTRAINED TIME UNCERTAINTY MODE
+##################################################
+# 0 : disabled (default)
+# 1 : enabled
+# This setting enables GPS engine to keep its time
+# uncertainty below the specified constraint
+#CONSTRAINED_TIME_UNCERTAINTY_ENABLED = 0
+
+# If constrained time uncertainty mode is enabled,
+# this setting specifies the time uncertainty
+# threshold that gps engine need to maintain.
+# In unit of milli-seconds.
+# Default is 0.0 meaning that modem default value
+# of time uncertainty threshold will be used.
+#CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD = 0.0
+
+# If constrained time uncertainty mode is enabled,
+# this setting specifies the power budget that
+# gps engine is allowed to spend to maintain the time
+# uncertainty.
+# Default is 0 meaning that GPS engine is not constained
+# by power budget and can spend as much power as needed.
+# In unit of 0.1 milli watt second.
+#CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET = 0
+
+##################################################
+# POSITION ASSISTED CLOCK ESTIMATOR
+##################################################
+# 0 : disabled (default)
+# 1 : enabled
+# This setting enables GPS engine to estimate clock
+# bias and drift when the signal from at least 1
+# SV is available and the UEÂ’s position is known by
+# other position engines.
+#POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED = 0
+
+#####################################
+# proxyAppPackageName
+#####################################
+# This is a string that is sent to the framework
+# in nfwNotifyCb callback
+PROXY_APP_PACKAGE_NAME = com.google.android.carrierlocation
+
+#####################################
+# CP_MTLR_ES
+#####################################
+# CP MTLR ES, 1=enable, 0=disable
+CP_MTLR_ES=0
+
+##################################################
+# GNSS_DEPLOYMENT
+##################################################
+# 0 : Enable QTI GNSS (default)
+# 1 : Enable QCSR SS5
+# 2 : Enable PDS API
+# This setting use to select between QTI GNSS,
+# QCSR SS5 hardware receiver, and PDS API.
+# By default QTI GNSS receiver is enabled.
+# GNSS_DEPLOYMENT = 0
+
+##################################################
+## LOG BUFFER CONFIGURATION
+##################################################
+#LOG_BUFFER_ENABLED, 1=enable, 0=disable
+#*_LEVEL_TIME_DEPTH, maximum time depth of level *
+#in log buffer, unit is second
+#*_LEVEL_MAX_CAPACITY, maximum numbers of level *
+#log print sentences in log buffer
+LOG_BUFFER_ENABLED = 0
+E_LEVEL_TIME_DEPTH = 600
+E_LEVEL_MAX_CAPACITY = 50
+W_LEVEL_TIME_DEPTH = 500
+W_LEVEL_MAX_CAPACITY = 100
+I_LEVEL_TIME_DEPTH = 400
+I_LEVEL_MAX_CAPACITY = 200
+D_LEVEL_TIME_DEPTH = 30
+D_LEVEL_MAX_CAPACITY = 300
+V_LEVEL_TIME_DEPTH = 200
+V_LEVEL_MAX_CAPACITY = 400
+
+##################################################
+# Allow buffer diag log packets when diag memory allocation
+# fails during boot up time.
+##################################################
+BUFFER_DIAG_LOGGING = 1
+
+#######################################
+#  NTRIP CLIENT LIBRARY NAME
+#######################################
+# NTRIP_CLIENT_LIB_NAME =
+
+##################################################
+# Correction Data Framework settings
+# Default values:
+# CDFW_SOURCE_PRIORITY_1 = INTERNAL_1 RTCM
+# CDFW_INJECT_DATA_INTERVAL = 600000 //10 mins
+# CDFW_RTCM_MESSAGE_INTERVAL = 1000  //1 second
+#
+# If multiple sources coexist on a PL,
+# the prorioty sequence can be set by the integer number.
+# PRIORITY_1 is higher than PRIORITY_2, for example,
+# CDFW_SOURCE_PRIORITY_1 = INTERNAL_1 RTCM
+# CDFW_SOURCE_PRIORITY_2 = CV2X RTCM
+##################################################
+
+##################################################
+# RF LOSS
+# The loss in 0.1 dbHz from the C/N0 at the antenna port
+# These values must be configured by OEM if not
+# supported in QMI LOC message
+# There is one entry for each signal type
+##################################################
+RF_LOSS_GPS = 0
+RF_LOSS_GPS_L5 = 0
+RF_LOSS_GLO_LEFT = 0
+RF_LOSS_GLO_CENTER = 0
+RF_LOSS_GLO_RIGHT = 0
+RF_LOSS_BDS = 0
+RF_LOSS_BDS_B2A = 0
+RF_LOSS_GAL = 0
+RF_LOSS_GAL_E5 = 0
+RF_LOSS_NAVIC = 0
diff --git a/gps/etc/seccomp_policy/gnss@2.0-base.policy b/gps/etc/seccomp_policy/gnss@2.0-base.policy
new file mode 100644
index 0000000..0a2e17b
--- /dev/null
+++ b/gps/etc/seccomp_policy/gnss@2.0-base.policy
@@ -0,0 +1,119 @@
+#*******************************************************************************
+#  Copyright (c) 2020 The Linux Foundation. All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions are
+#  met:
+#      * Redistributions of source code must retain the above copyright
+#        notice, this list of conditions and the following disclaimer.
+#      * Redistributions in binary form must reproduce the above
+#        copyright notice, this list of conditions and the following
+#        disclaimer in the documentation and/or other materials provided
+#        with the distribution.
+#      * Neither the name of The Linux Foundation, nor the names of its
+#        contributors may be used to endorse or promote products derived
+#        from this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+#  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+#  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+#  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+#  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+#  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#******************************************************************************
+
+clone: 1
+close: 1
+connect: 1
+execve: 1
+exit_group: 1
+exit: 1
+faccessat: 1
+fcntl: 1
+fstat: 1
+fstatfs: 1
+futex: 1
+getpid: 1
+getuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
+geteuid: 1
+umask: 1
+getrandom: 1
+mmap: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+mprotect: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+mremap: 1
+munmap: 1
+newfstatat: 1
+openat: 1
+#prctl: arg0 == PR_SET_VMA || arg0 == PR_SET_NO_NEW_PRIVS || arg0 == PR_GET_DUMPABLE || arg0 == PR_SET_SECCOMP || arg0 == 0x37 /* PR_??? */
+prctl: 1
+pread64: 1
+read: 1
+pwrite64: 1
+write: 1
+writev: 1
+readlinkat: 1
+restart_syscall: 1
+rt_sigaction: 1
+rt_sigprocmask: 1
+rt_sigreturn: 1
+sched_getscheduler: 1
+set_tid_address: 1
+sigaltstack: 1
+unlinkat: 1
+lseek: 1
+##ioctl: arg1 == _IOC(_IOC_NONE || arg1 == _IOC(_IOC_READ || arg1 == VSOC_MAYBE_SEND_INTERRUPT_TO_HOST
+ioctl: 1
+clock_gettime: 1
+
+
+socket: arg0 == AF_INET6 || arg0 == AF_UNIX || arg0 == AF_QIPCRTR
+connect: 1
+setsockopt: 1
+getsockname: 1
+socketpair: 1
+ppoll: 1
+pselect6: 1
+accept4: 1
+listen: 1
+bind: 1
+pipe2: 1
+
+recvmsg: 1
+sendmsg: 1
+
+sendto: 1
+recvfrom: 1
+
+getsockname: 1
+nanosleep: 1
+clone: 1
+setsockopt: 1
+getsockopt: 1
+madvise: 1
+
+getitimer: 1
+setitimer: 1
+getpid: 1
+bind: 1
+listen: 1
+getpeername: 1
+socketpair: 1
+wait4: 1
+chown: 1
+fchown: 1
+lchown: 1
+umask: 1
+mmap2: 1
+fstat64: 1
+fstatat64: 1
+_llseek: 1
+geteuid: 1
diff --git a/gps/etc/seccomp_policy/gnss@2.0-xtra-daemon.policy b/gps/etc/seccomp_policy/gnss@2.0-xtra-daemon.policy
new file mode 100644
index 0000000..19b67bb
--- /dev/null
+++ b/gps/etc/seccomp_policy/gnss@2.0-xtra-daemon.policy
@@ -0,0 +1,48 @@
+#*******************************************************************************
+#  Copyright (c) 2020 The Linux Foundation. All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions are
+#  met:
+#      * Redistributions of source code must retain the above copyright
+#        notice, this list of conditions and the following disclaimer.
+#      * Redistributions in binary form must reproduce the above
+#        copyright notice, this list of conditions and the following
+#        disclaimer in the documentation and/or other materials provided
+#        with the distribution.
+#      * Neither the name of The Linux Foundation, nor the names of its
+#        contributors may be used to endorse or promote products derived
+#        from this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+#  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+#  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+#  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+#  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+#  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#******************************************************************************
+bind: 1
+getrlimit: 1
+
+pipe2: 1
+
+sched_getaffinity: 1
+timerfd_create: 1
+unlinkat: 1
+setpriority: 1
+
+epoll_create1: 1
+epoll_ctl: 1
+epoll_pwait: 1
+timerfd_settime: 1
+
+fdatasync: 1
+madvise: 1
+ftruncate: 1
+
diff --git a/gps/etc/seccomp_policy/gnss@2.0-xtwifi-client.policy b/gps/etc/seccomp_policy/gnss@2.0-xtwifi-client.policy
new file mode 100644
index 0000000..38a41f9
--- /dev/null
+++ b/gps/etc/seccomp_policy/gnss@2.0-xtwifi-client.policy
@@ -0,0 +1,73 @@
+
+#*******************************************************************************
+#  Copyright (c) 2020 The Linux Foundation. All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions are
+#  met:
+#      * Redistributions of source code must retain the above copyright
+#        notice, this list of conditions and the following disclaimer.
+#      * Redistributions in binary form must reproduce the above
+#        copyright notice, this list of conditions and the following
+#        disclaimer in the documentation and/or other materials provided
+#        with the distribution.
+#      * Neither the name of The Linux Foundation, nor the names of its
+#        contributors may be used to endorse or promote products derived
+#        from this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+#  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+#  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+#  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+#  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+#  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#******************************************************************************
+
+fdatasync: 1
+getdents64: 1
+gettimeofday: 1
+ioctl: 1
+lseek: 1
+madvise: 1
+mkdirat: 1
+pwrite64: 1
+
+timerfd_create: 1
+timerfd_settime: 1
+epoll_create1: 1
+epoll_pwait: 1
+epoll_ctl: 1
+
+sched_getaffinity: 1
+gettid: 1
+fchown: 1
+fchmod: 1
+fchmodat: 1
+getsockopt: 1
+fchownat: 1
+fstat: 1
+fstatfs: 1
+newfstatat: 1
+sendmsg: 1
+recvmsg: 1
+gettimeofday: 1
+setsockopt: 1
+rt_tgsigqueueinfo: 1
+ioctl: 1
+mmap: 1
+getuid32: 1
+getuid: 1
+fstat64: 1
+fstatat64: 1
+mkdir: 1
+rmdir: 1
+creat: 1
+chmod: 1
+lseek: 1
+geteuid32: 1
diff --git a/gps/etc/seccomp_policy/gnss@2.0-xtwifi-inet-agent.policy b/gps/etc/seccomp_policy/gnss@2.0-xtwifi-inet-agent.policy
new file mode 100644
index 0000000..024600a
--- /dev/null
+++ b/gps/etc/seccomp_policy/gnss@2.0-xtwifi-inet-agent.policy
@@ -0,0 +1,43 @@
+
+#*******************************************************************************
+#  Copyright (c) 2020 The Linux Foundation. All rights reserved.
+#
+#  Redistribution and use in source and binary forms, with or without
+#  modification, are permitted provided that the following conditions are
+#  met:
+#      * Redistributions of source code must retain the above copyright
+#        notice, this list of conditions and the following disclaimer.
+#      * Redistributions in binary form must reproduce the above
+#        copyright notice, this list of conditions and the following
+#        disclaimer in the documentation and/or other materials provided
+#        with the distribution.
+#      * Neither the name of The Linux Foundation, nor the names of its
+#        contributors may be used to endorse or promote products derived
+#        from this software without specific prior written permission.
+#
+#  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+#  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+#  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+#  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+#  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+#  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+#  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#******************************************************************************
+
+unlinkat: 1
+sched_getaffinity: 1
+newfstatat: 1
+fchmodat: 1
+madvise: 1
+mmap: 1
+getuid: 1
+getuid32: 1
+fstat64: 1
+fstatat64: 1
+gettimeofday: 1
+getdents64: 1
diff --git a/gps/geofence/Android.bp b/gps/geofence/Android.bp
new file mode 100644
index 0000000..bf8474f
--- /dev/null
+++ b/gps/geofence/Android.bp
@@ -0,0 +1,31 @@
+
+
+cc_library_shared {
+
+    name: "libgeofencing",
+    vendor: true,
+
+
+
+    srcs: [
+        "GeofenceAdapter.cpp",
+        "location_geofence.cpp",
+    ],
+
+    shared_libs: [
+        "libutils",
+        "libcutils",
+        "libgps.utils",
+        "liblog",
+        "libloc_core",
+    ],
+
+    header_libs: [
+        "libgps.utils_headers",
+        "libloc_core_headers",
+        "libloc_pla_headers",
+        "liblocation_api_headers",
+    ],
+
+    cflags: GNSS_CFLAGS,
+}
diff --git a/gps/geofence/GeofenceAdapter.cpp b/gps/geofence/GeofenceAdapter.cpp
new file mode 100644
index 0000000..1aeea0a
--- /dev/null
+++ b/gps/geofence/GeofenceAdapter.cpp
@@ -0,0 +1,870 @@
+/* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_TAG "LocSvc_GeofenceAdapter"
+
+#include <GeofenceAdapter.h>
+#include "loc_log.h"
+#include <log_util.h>
+#include <string>
+
+using namespace loc_core;
+
+GeofenceAdapter::GeofenceAdapter() :
+    LocAdapterBase(0,
+                   LocContext::getLocContext(LocContext::mLocationHalName),
+                   true /*isMaster*/, nullptr, true)
+{
+    LOC_LOGD("%s]: Constructor", __func__);
+
+    // at last step, let us inform adapater base that we are done
+    // with initialization, e.g.: ready to process handleEngineUpEvent
+    doneInit();
+}
+
+void
+GeofenceAdapter::stopClientSessions(LocationAPI* client)
+{
+    LOC_LOGD("%s]: client %p", __func__, client);
+
+
+    for (auto it = mGeofenceIds.begin(); it != mGeofenceIds.end();) {
+        uint32_t hwId = it->second;
+        GeofenceKey key(it->first);
+        if (client == key.client) {
+            it = mGeofenceIds.erase(it);
+            mLocApi->removeGeofence(hwId, key.id,
+                    new LocApiResponse(*getContext(),
+                    [this, hwId] (LocationError err) {
+                if (LOCATION_ERROR_SUCCESS == err) {
+                    auto it2 = mGeofences.find(hwId);
+                    if (it2 != mGeofences.end()) {
+                        mGeofences.erase(it2);
+                    } else {
+                        LOC_LOGE("%s]:geofence item to erase not found. hwId %u", __func__, hwId);
+                    }
+                }
+            }));
+            continue;
+        }
+        ++it; // increment only when not erasing an iterator
+    }
+
+}
+
+void
+GeofenceAdapter::updateClientsEventMask()
+{
+    LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        if (it->second.geofenceBreachCb != nullptr) {
+            mask |= LOC_API_ADAPTER_BIT_BATCHED_GENFENCE_BREACH_REPORT;
+            mask |= LOC_API_ADAPTER_BIT_REPORT_GENFENCE_DWELL;
+        }
+        if (it->second.geofenceStatusCb != nullptr) {
+            mask |= LOC_API_ADAPTER_BIT_GEOFENCE_GEN_ALERT;
+        }
+    }
+    updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
+}
+
+LocationError
+GeofenceAdapter::getHwIdFromClient(LocationAPI* client, uint32_t clientId, uint32_t& hwId)
+{
+    GeofenceKey key(client, clientId);
+    auto it = mGeofenceIds.find(key);
+    if (it != mGeofenceIds.end()) {
+        hwId = it->second;
+        return LOCATION_ERROR_SUCCESS;
+    }
+    return LOCATION_ERROR_ID_UNKNOWN;
+}
+
+LocationError
+GeofenceAdapter::getGeofenceKeyFromHwId(uint32_t hwId, GeofenceKey& key)
+{
+    auto it = mGeofences.find(hwId);
+    if (it != mGeofences.end()) {
+        key = it->second.key;
+        return LOCATION_ERROR_SUCCESS;
+    }
+    return LOCATION_ERROR_ID_UNKNOWN;
+}
+
+void
+GeofenceAdapter::handleEngineUpEvent()
+{
+    struct MsgSSREvent : public LocMsg {
+        GeofenceAdapter& mAdapter;
+        inline MsgSSREvent(GeofenceAdapter& adapter) :
+            LocMsg(),
+            mAdapter(adapter) {}
+        virtual void proc() const {
+            mAdapter.setEngineCapabilitiesKnown(true);
+            mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+            mAdapter.restartGeofences();
+            for (auto msg: mAdapter.mPendingMsgs) {
+                mAdapter.sendMsg(msg);
+            }
+            mAdapter.mPendingMsgs.clear();
+        }
+    };
+
+    sendMsg(new MsgSSREvent(*this));
+}
+
+void
+GeofenceAdapter::restartGeofences()
+{
+    if (mGeofences.empty()) {
+        return;
+    }
+
+    GeofencesMap oldGeofences(mGeofences);
+    mGeofences.clear();
+    mGeofenceIds.clear();
+
+    for (auto it = oldGeofences.begin(); it != oldGeofences.end(); it++) {
+        GeofenceObject object = it->second;
+        GeofenceOption options = {sizeof(GeofenceOption),
+                                   object.breachMask,
+                                   object.responsiveness,
+                                   object.dwellTime};
+        GeofenceInfo info = {sizeof(GeofenceInfo),
+                             object.latitude,
+                             object.longitude,
+                             object.radius};
+        mLocApi->addGeofence(object.key.id,
+                              options,
+                              info,
+                              new LocApiResponseData<LocApiGeofenceData>(*getContext(),
+                [this, object, options, info] (LocationError err, LocApiGeofenceData data) {
+            if (LOCATION_ERROR_SUCCESS == err) {
+                if (true == object.paused) {
+                    mLocApi->pauseGeofence(data.hwId, object.key.id,
+                            new LocApiResponse(*getContext(), [] (LocationError err ) {}));
+                }
+                saveGeofenceItem(object.key.client, object.key.id, data.hwId, options, info);
+            }
+        }));
+    }
+}
+
+void
+GeofenceAdapter::reportResponse(LocationAPI* client, size_t count, LocationError* errs,
+        uint32_t* ids)
+{
+    IF_LOC_LOGD {
+        std::string idsString = "[";
+        std::string errsString = "[";
+        if (NULL != ids && NULL != errs) {
+            for (size_t i=0; i < count; ++i) {
+                idsString += std::to_string(ids[i]) + " ";
+                errsString += std::to_string(errs[i]) + " ";
+            }
+        }
+        idsString += "]";
+        errsString += "]";
+
+        LOC_LOGD("%s]: client %p ids %s errs %s",
+                 __func__, client, idsString.c_str(), errsString.c_str());
+    }
+
+    auto it = mClientData.find(client);
+    if (it != mClientData.end() && it->second.collectiveResponseCb != nullptr) {
+        it->second.collectiveResponseCb(count, errs, ids);
+    } else {
+        LOC_LOGE("%s]: client %p response not found in info", __func__, client);
+    }
+}
+
+uint32_t*
+GeofenceAdapter::addGeofencesCommand(LocationAPI* client, size_t count, GeofenceOption* options,
+        GeofenceInfo* infos)
+{
+    LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+    struct MsgAddGeofences : public LocMsg {
+        GeofenceAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        size_t mCount;
+        uint32_t* mIds;
+        GeofenceOption* mOptions;
+        GeofenceInfo* mInfos;
+        inline MsgAddGeofences(GeofenceAdapter& adapter,
+                               LocApiBase& api,
+                               LocationAPI* client,
+                               size_t count,
+                               uint32_t* ids,
+                               GeofenceOption* options,
+                               GeofenceInfo* infos) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mCount(count),
+            mIds(ids),
+            mOptions(options),
+            mInfos(infos) {}
+        inline virtual void proc() const {
+            LocationError* errs = new LocationError[mCount];
+            if (nullptr == errs) {
+                LOC_LOGE("%s]: new failed to allocate errs", __func__);
+                return;
+            }
+            for (size_t i=0; i < mCount; ++i) {
+                if (NULL == mIds || NULL == mOptions || NULL == mInfos) {
+                    errs[i] = LOCATION_ERROR_INVALID_PARAMETER;
+                } else {
+                    mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+                            [&mAdapter = mAdapter, mCount = mCount, mClient = mClient,
+                            mOptions = mOptions, mInfos = mInfos, mIds = mIds, &mApi = mApi,
+                            errs, i] (LocationError err ) {
+                        mApi.addGeofence(mIds[i], mOptions[i], mInfos[i],
+                        new LocApiResponseData<LocApiGeofenceData>(*mAdapter.getContext(),
+                        [&mAdapter = mAdapter, mOptions = mOptions, mClient = mClient,
+                        mCount = mCount, mIds = mIds, mInfos = mInfos, errs, i]
+                        (LocationError err, LocApiGeofenceData data) {
+                            if (LOCATION_ERROR_SUCCESS == err) {
+                                mAdapter.saveGeofenceItem(mClient,
+                                mIds[i],
+                                data.hwId,
+                                mOptions[i],
+                                mInfos[i]);
+                            }
+                            errs[i] = err;
+
+                            // Send aggregated response on last item and cleanup
+                            if (i == mCount-1) {
+                                mAdapter.reportResponse(mClient, mCount, errs, mIds);
+                                delete[] errs;
+                                delete[] mIds;
+                                delete[] mOptions;
+                                delete[] mInfos;
+                            }
+                        }));
+                    }));
+                }
+            }
+        }
+    };
+
+    if (0 == count) {
+        return NULL;
+    }
+    uint32_t* ids = new uint32_t[count];
+    if (nullptr == ids) {
+        LOC_LOGE("%s]: new failed to allocate ids", __func__);
+        return NULL;
+    }
+    if (NULL != ids) {
+        for (size_t i=0; i < count; ++i) {
+            ids[i] = generateSessionId();
+        }
+    }
+    GeofenceOption* optionsCopy;
+    if (options == NULL) {
+        optionsCopy = NULL;
+    } else {
+        optionsCopy = new GeofenceOption[count];
+        if (nullptr == optionsCopy) {
+            LOC_LOGE("%s]: new failed to allocate optionsCopy", __func__);
+            return NULL;
+        }
+        COPY_IF_NOT_NULL(optionsCopy, options, count);
+    }
+    GeofenceInfo* infosCopy;
+    if (infos == NULL) {
+        infosCopy = NULL;
+    } else {
+        infosCopy = new GeofenceInfo[count];
+        if (nullptr == infosCopy) {
+            LOC_LOGE("%s]: new failed to allocate infosCopy", __func__);
+            return NULL;
+        }
+        COPY_IF_NOT_NULL(infosCopy, infos, count);
+    }
+
+    sendMsg(new MsgAddGeofences(*this, *mLocApi, client, count, ids, optionsCopy, infosCopy));
+    return ids;
+}
+
+void
+GeofenceAdapter::removeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids)
+{
+    LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+    struct MsgRemoveGeofences : public LocMsg {
+        GeofenceAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        size_t mCount;
+        uint32_t* mIds;
+        inline MsgRemoveGeofences(GeofenceAdapter& adapter,
+                                  LocApiBase& api,
+                                  LocationAPI* client,
+                                  size_t count,
+                                  uint32_t* ids) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mCount(count),
+            mIds(ids) {}
+        inline virtual void proc() const  {
+            LocationError* errs = new LocationError[mCount];
+            if (nullptr == errs) {
+                LOC_LOGE("%s]: new failed to allocate errs", __func__);
+                return;
+            }
+            for (size_t i=0; i < mCount; ++i) {
+                mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+                        [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+                        &mApi = mApi, errs, i] (LocationError err ) {
+                    uint32_t hwId = 0;
+                    errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
+                    if (LOCATION_ERROR_SUCCESS == errs[i]) {
+                        mApi.removeGeofence(hwId, mIds[i],
+                        new LocApiResponse(*mAdapter.getContext(),
+                        [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+                        hwId, errs, i] (LocationError err ) {
+                            if (LOCATION_ERROR_SUCCESS == err) {
+                                mAdapter.removeGeofenceItem(hwId);
+                            }
+                            errs[i] = err;
+
+                            // Send aggregated response on last item and cleanup
+                            if (i == mCount-1) {
+                                mAdapter.reportResponse(mClient, mCount, errs, mIds);
+                                delete[] errs;
+                                delete[] mIds;
+                            }
+                        }));
+                    } else {
+                        // Send aggregated response on last item and cleanup
+                        if (i == mCount-1) {
+                            mAdapter.reportResponse(mClient, mCount, errs, mIds);
+                            delete[] errs;
+                            delete[] mIds;
+                        }
+                    }
+                }));
+            }
+        }
+    };
+
+    if (0 == count) {
+        return;
+    }
+    uint32_t* idsCopy = new uint32_t[count];
+    if (nullptr == idsCopy) {
+        LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
+        return;
+    }
+    COPY_IF_NOT_NULL(idsCopy, ids, count);
+    sendMsg(new MsgRemoveGeofences(*this, *mLocApi, client, count, idsCopy));
+}
+
+void
+GeofenceAdapter::pauseGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids)
+{
+    LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+    struct MsgPauseGeofences : public LocMsg {
+        GeofenceAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        size_t mCount;
+        uint32_t* mIds;
+        inline MsgPauseGeofences(GeofenceAdapter& adapter,
+                                 LocApiBase& api,
+                                 LocationAPI* client,
+                                 size_t count,
+                                 uint32_t* ids) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mCount(count),
+            mIds(ids) {}
+        inline virtual void proc() const  {
+            LocationError* errs = new LocationError[mCount];
+            if (nullptr == errs) {
+                LOC_LOGE("%s]: new failed to allocate errs", __func__);
+                return;
+            }
+            for (size_t i=0; i < mCount; ++i) {
+                mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+                        [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+                        &mApi = mApi, errs, i] (LocationError err ) {
+                    uint32_t hwId = 0;
+                    errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
+                    if (LOCATION_ERROR_SUCCESS == errs[i]) {
+                        mApi.pauseGeofence(hwId, mIds[i], new LocApiResponse(*mAdapter.getContext(),
+                        [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+                        hwId, errs, i] (LocationError err ) {
+                            if (LOCATION_ERROR_SUCCESS == err) {
+                                mAdapter.pauseGeofenceItem(hwId);
+                            }
+                            errs[i] = err;
+
+                            // Send aggregated response on last item and cleanup
+                            if (i == mCount-1) {
+                                mAdapter.reportResponse(mClient, mCount, errs, mIds);
+                                delete[] errs;
+                                delete[] mIds;
+                            }
+                        }));
+                    } else {
+                        // Send aggregated response on last item and cleanup
+                        if (i == mCount-1) {
+                            mAdapter.reportResponse(mClient, mCount, errs, mIds);
+                            delete[] errs;
+                            delete[] mIds;
+                        }
+                    }
+                }));
+            }
+        }
+    };
+
+    if (0 == count) {
+        return;
+    }
+    uint32_t* idsCopy = new uint32_t[count];
+    if (nullptr == idsCopy) {
+        LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
+        return;
+    }
+    COPY_IF_NOT_NULL(idsCopy, ids, count);
+    sendMsg(new MsgPauseGeofences(*this, *mLocApi, client, count, idsCopy));
+}
+
+void
+GeofenceAdapter::resumeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids)
+{
+    LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+    struct MsgResumeGeofences : public LocMsg {
+        GeofenceAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        size_t mCount;
+        uint32_t* mIds;
+        inline MsgResumeGeofences(GeofenceAdapter& adapter,
+                                  LocApiBase& api,
+                                  LocationAPI* client,
+                                  size_t count,
+                                  uint32_t* ids) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mCount(count),
+            mIds(ids) {}
+        inline virtual void proc() const  {
+            LocationError* errs = new LocationError[mCount];
+            if (nullptr == errs) {
+                LOC_LOGE("%s]: new failed to allocate errs", __func__);
+                return;
+            }
+            for (size_t i=0; i < mCount; ++i) {
+                mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+                        [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+                        &mApi = mApi, errs, i] (LocationError err ) {
+                    uint32_t hwId = 0;
+                    errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
+                    if (LOCATION_ERROR_SUCCESS == errs[i]) {
+                        mApi.resumeGeofence(hwId, mIds[i],
+                                new LocApiResponse(*mAdapter.getContext(),
+                                [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, hwId,
+                                errs, mIds = mIds, i] (LocationError err ) {
+                            if (LOCATION_ERROR_SUCCESS == err) {
+                                errs[i] = err;
+
+                                mAdapter.resumeGeofenceItem(hwId);
+                                // Send aggregated response on last item and cleanup
+                                if (i == mCount-1) {
+                                    mAdapter.reportResponse(mClient, mCount, errs, mIds);
+                                    delete[] errs;
+                                    delete[] mIds;
+                                }
+                            }
+                        }));
+                    } else {
+                        // Send aggregated response on last item and cleanup
+                        if (i == mCount-1) {
+                            mAdapter.reportResponse(mClient, mCount, errs, mIds);
+                            delete[] errs;
+                            delete[] mIds;
+                        }
+                    }
+                }));
+            }
+        }
+    };
+
+    if (0 == count) {
+        return;
+    }
+    uint32_t* idsCopy = new uint32_t[count];
+    if (nullptr == idsCopy) {
+        LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
+        return;
+    }
+    COPY_IF_NOT_NULL(idsCopy, ids, count);
+    sendMsg(new MsgResumeGeofences(*this, *mLocApi, client, count, idsCopy));
+}
+
+void
+GeofenceAdapter::modifyGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids,
+        GeofenceOption* options)
+{
+    LOC_LOGD("%s]: client %p count %zu", __func__, client, count);
+
+    struct MsgModifyGeofences : public LocMsg {
+        GeofenceAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        size_t mCount;
+        uint32_t* mIds;
+        GeofenceOption* mOptions;
+        inline MsgModifyGeofences(GeofenceAdapter& adapter,
+                                  LocApiBase& api,
+                                  LocationAPI* client,
+                                  size_t count,
+                                  uint32_t* ids,
+                                  GeofenceOption* options) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mCount(count),
+            mIds(ids),
+            mOptions(options) {}
+        inline virtual void proc() const  {
+            LocationError* errs = new LocationError[mCount];
+            if (nullptr == errs) {
+                LOC_LOGE("%s]: new failed to allocate errs", __func__);
+                return;
+            }
+            for (size_t i=0; i < mCount; ++i) {
+                if (NULL == mIds || NULL == mOptions) {
+                    errs[i] = LOCATION_ERROR_INVALID_PARAMETER;
+                } else {
+                    mApi.addToCallQueue(new LocApiResponse(*mAdapter.getContext(),
+                            [&mAdapter = mAdapter, mCount = mCount, mClient = mClient, mIds = mIds,
+                            &mApi = mApi, mOptions = mOptions, errs, i] (LocationError err ) {
+                        uint32_t hwId = 0;
+                        errs[i] = mAdapter.getHwIdFromClient(mClient, mIds[i], hwId);
+                        if (LOCATION_ERROR_SUCCESS == errs[i]) {
+                            mApi.modifyGeofence(hwId, mIds[i], mOptions[i],
+                                    new LocApiResponse(*mAdapter.getContext(),
+                                    [&mAdapter = mAdapter, mCount = mCount, mClient = mClient,
+                                    mIds = mIds, mOptions = mOptions, hwId, errs, i]
+                                    (LocationError err ) {
+                                if (LOCATION_ERROR_SUCCESS == err) {
+                                    errs[i] = err;
+
+                                    mAdapter.modifyGeofenceItem(hwId, mOptions[i]);
+                                }
+                                // Send aggregated response on last item and cleanup
+                                if (i == mCount-1) {
+                                    mAdapter.reportResponse(mClient, mCount, errs, mIds);
+                                    delete[] errs;
+                                    delete[] mIds;
+                                    delete[] mOptions;
+                                }
+                            }));
+                        } else {
+                            // Send aggregated response on last item and cleanup
+                            if (i == mCount-1) {
+                                mAdapter.reportResponse(mClient, mCount, errs, mIds);
+                                delete[] errs;
+                                delete[] mIds;
+                                delete[] mOptions;
+                            }
+                        }
+                    }));
+                }
+            }
+        }
+    };
+
+    if (0 == count) {
+        return;
+    }
+    uint32_t* idsCopy = new uint32_t[count];
+    if (nullptr == idsCopy) {
+        LOC_LOGE("%s]: new failed to allocate idsCopy", __func__);
+        return;
+    }
+    COPY_IF_NOT_NULL(idsCopy, ids, count);
+    GeofenceOption* optionsCopy;
+    if (options == NULL) {
+        optionsCopy = NULL;
+    } else {
+        optionsCopy = new GeofenceOption[count];
+        if (nullptr == optionsCopy) {
+            LOC_LOGE("%s]: new failed to allocate optionsCopy", __func__);
+            return;
+        }
+        COPY_IF_NOT_NULL(optionsCopy, options, count);
+    }
+
+    sendMsg(new MsgModifyGeofences(*this, *mLocApi, client, count, idsCopy, optionsCopy));
+}
+
+void
+GeofenceAdapter::saveGeofenceItem(LocationAPI* client, uint32_t clientId, uint32_t hwId,
+        const GeofenceOption& options, const GeofenceInfo& info)
+{
+    LOC_LOGD("%s]: hwId %u client %p clientId %u", __func__, hwId, client, clientId);
+    GeofenceKey key(client, clientId);
+    GeofenceObject object = {key,
+                             options.breachTypeMask,
+                             options.responsiveness,
+                             options.dwellTime,
+                             info.latitude,
+                             info.longitude,
+                             info.radius,
+                             false};
+    mGeofences[hwId] = object;
+    mGeofenceIds[key] = hwId;
+    dump();
+}
+
+void
+GeofenceAdapter::removeGeofenceItem(uint32_t hwId)
+{
+    GeofenceKey key;
+    LocationError err = getGeofenceKeyFromHwId(hwId, key);
+    if (LOCATION_ERROR_SUCCESS != err) {
+        LOC_LOGE("%s]: can not find the key for hwId %u", __func__, hwId);
+    } else {
+        auto it1 = mGeofenceIds.find(key);
+        if (it1 != mGeofenceIds.end()) {
+            mGeofenceIds.erase(it1);
+
+            auto it2 = mGeofences.find(hwId);
+            if (it2 != mGeofences.end()) {
+                mGeofences.erase(it2);
+                dump();
+            } else {
+                LOC_LOGE("%s]:geofence item to erase not found. hwId %u", __func__, hwId);
+            }
+        } else {
+            LOC_LOGE("%s]: geofence item to erase not found. hwId %u", __func__, hwId);
+        }
+    }
+}
+
+void
+GeofenceAdapter::pauseGeofenceItem(uint32_t hwId)
+{
+    auto it = mGeofences.find(hwId);
+    if (it != mGeofences.end()) {
+        it->second.paused = true;
+        dump();
+    } else {
+        LOC_LOGE("%s]: geofence item to pause not found. hwId %u", __func__, hwId);
+    }
+}
+
+void
+GeofenceAdapter::resumeGeofenceItem(uint32_t hwId)
+{
+    auto it = mGeofences.find(hwId);
+    if (it != mGeofences.end()) {
+        it->second.paused = false;
+        dump();
+    } else {
+        LOC_LOGE("%s]: geofence item to resume not found. hwId %u", __func__, hwId);
+    }
+}
+
+void
+GeofenceAdapter::modifyGeofenceItem(uint32_t hwId, const GeofenceOption& options)
+{
+    auto it = mGeofences.find(hwId);
+    if (it != mGeofences.end()) {
+        it->second.breachMask = options.breachTypeMask;
+        it->second.responsiveness = options.responsiveness;
+        it->second.dwellTime = options.dwellTime;
+        dump();
+    } else {
+        LOC_LOGE("%s]: geofence item to modify not found. hwId %u", __func__, hwId);
+    }
+}
+
+
+void
+GeofenceAdapter::geofenceBreachEvent(size_t count, uint32_t* hwIds, Location& location,
+        GeofenceBreachType breachType, uint64_t timestamp)
+{
+
+    IF_LOC_LOGD {
+        std::string idsString = "[";
+        if (NULL != hwIds) {
+            for (size_t i=0; i < count; ++i) {
+                idsString += std::to_string(hwIds[i]) + " ";
+            }
+        }
+        idsString += "]";
+        LOC_LOGD("%s]: breachType %u count %zu ids %s",
+                 __func__, breachType, count, idsString.c_str());
+    }
+
+    if (0 == count || NULL == hwIds)
+        return;
+
+    struct MsgGeofenceBreach : public LocMsg {
+        GeofenceAdapter& mAdapter;
+        size_t mCount;
+        uint32_t* mHwIds;
+        Location mLocation;
+        GeofenceBreachType mBreachType;
+        uint64_t mTimestamp;
+        inline MsgGeofenceBreach(GeofenceAdapter& adapter,
+                                 size_t count,
+                                 uint32_t* hwIds,
+                                 Location& location,
+                                 GeofenceBreachType breachType,
+                                 uint64_t timestamp) :
+            LocMsg(),
+            mAdapter(adapter),
+            mCount(count),
+            mHwIds(new uint32_t[count]),
+            mLocation(location),
+            mBreachType(breachType),
+            mTimestamp(timestamp)
+        {
+            if (nullptr == mHwIds) {
+                LOC_LOGE("%s]: new failed to allocate mHwIds", __func__);
+                return;
+            }
+            COPY_IF_NOT_NULL(mHwIds, hwIds, mCount);
+        }
+        inline virtual ~MsgGeofenceBreach() {
+            delete[] mHwIds;
+        }
+        inline virtual void proc() const {
+            mAdapter.geofenceBreach(mCount, mHwIds, mLocation, mBreachType, mTimestamp);
+        }
+    };
+
+    sendMsg(new MsgGeofenceBreach(*this, count, hwIds, location, breachType, timestamp));
+
+}
+
+void
+GeofenceAdapter::geofenceBreach(size_t count, uint32_t* hwIds, const Location& location,
+        GeofenceBreachType breachType, uint64_t timestamp)
+{
+
+    for (auto it = mClientData.begin(); it != mClientData.end(); ++it) {
+        uint32_t* clientIds = new uint32_t[count];
+        if (nullptr == clientIds) {
+            return;
+        }
+        uint32_t index = 0;
+        for (size_t i=0; i < count; ++i) {
+            GeofenceKey key;
+            LocationError err = getGeofenceKeyFromHwId(hwIds[i], key);
+            if (LOCATION_ERROR_SUCCESS == err) {
+                if (key.client == it->first) {
+                    clientIds[index++] = key.id;
+                }
+            }
+        }
+        if (index > 0 && it->second.geofenceBreachCb != nullptr) {
+            GeofenceBreachNotification notify = {sizeof(GeofenceBreachNotification),
+                                                 index,
+                                                 clientIds,
+                                                 location,
+                                                 breachType,
+                                                 timestamp};
+
+            it->second.geofenceBreachCb(notify);
+        }
+        delete[] clientIds;
+    }
+}
+
+void
+GeofenceAdapter::geofenceStatusEvent(GeofenceStatusAvailable available)
+{
+    LOC_LOGD("%s]: available %u ", __func__, available);
+
+    struct MsgGeofenceStatus : public LocMsg {
+        GeofenceAdapter& mAdapter;
+        GeofenceStatusAvailable mAvailable;
+        inline MsgGeofenceStatus(GeofenceAdapter& adapter,
+                                 GeofenceStatusAvailable available) :
+            LocMsg(),
+            mAdapter(adapter),
+            mAvailable(available) {}
+        inline virtual void proc() const {
+            mAdapter.geofenceStatus(mAvailable);
+        }
+    };
+
+    sendMsg(new MsgGeofenceStatus(*this, available));
+}
+
+void
+GeofenceAdapter::geofenceStatus(GeofenceStatusAvailable available)
+{
+    for (auto it = mClientData.begin(); it != mClientData.end(); ++it) {
+        if (it->second.geofenceStatusCb != nullptr) {
+            GeofenceStatusNotification notify = {sizeof(GeofenceStatusNotification),
+                                                 available,
+                                                 LOCATION_TECHNOLOGY_TYPE_GNSS};
+            it->second.geofenceStatusCb(notify);
+        }
+    }
+}
+
+void
+GeofenceAdapter::dump()
+{
+    IF_LOC_LOGV {
+        LOC_LOGV(
+            "HAL | hwId  | mask | respon | latitude | longitude | radius | paused |  Id  | client");
+        for (auto it = mGeofences.begin(); it != mGeofences.end(); ++it) {
+            uint32_t hwId = it->first;
+            GeofenceObject object = it->second;
+            LOC_LOGV("    | %5u | %4u | %6u | %8.2f | %9.2f | %6.2f | %6u | %04x | %p ",
+                    hwId, object.breachMask, object.responsiveness,
+                    object.latitude, object.longitude, object.radius,
+                    object.paused, object.key.id, object.key.client);
+        }
+    }
+}
+
diff --git a/gps/geofence/GeofenceAdapter.h b/gps/geofence/GeofenceAdapter.h
new file mode 100644
index 0000000..38f4823
--- /dev/null
+++ b/gps/geofence/GeofenceAdapter.h
@@ -0,0 +1,136 @@
+/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef GEOFENCE_ADAPTER_H
+#define GEOFENCE_ADAPTER_H
+
+#include <LocAdapterBase.h>
+#include <LocContext.h>
+#include <LocationAPI.h>
+#include <map>
+
+using namespace loc_core;
+
+#define COPY_IF_NOT_NULL(dest, src, len) do { \
+    if (NULL!=dest && NULL!=src) { \
+        for (size_t i=0; i<len; ++i) { \
+            dest[i] = src[i]; \
+        } \
+    } \
+} while (0)
+
+typedef struct GeofenceKey {
+    LocationAPI* client;
+    uint32_t id;
+    inline GeofenceKey() :
+        client(NULL), id(0) {}
+    inline GeofenceKey(LocationAPI* _client, uint32_t _id) :
+        client(_client), id(_id) {}
+} GeofenceKey;
+inline bool operator <(GeofenceKey const& left, GeofenceKey const& right) {
+    return left.id < right.id || (left.id == right.id && left.client < right.client);
+}
+inline bool operator ==(GeofenceKey const& left, GeofenceKey const& right) {
+    return left.id == right.id && left.client == right.client;
+}
+inline bool operator !=(GeofenceKey const& left, GeofenceKey const& right) {
+    return left.id != right.id || left.client != right.client;
+}
+typedef struct {
+    GeofenceKey key;
+    GeofenceBreachTypeMask breachMask;
+    uint32_t responsiveness;
+    uint32_t dwellTime;
+    double latitude;
+    double longitude;
+    double radius;
+    bool paused;
+} GeofenceObject;
+typedef std::map<uint32_t, GeofenceObject> GeofencesMap; //map of hwId to GeofenceObject
+typedef std::map<GeofenceKey, uint32_t> GeofenceIdMap; //map of GeofenceKey to hwId
+
+class GeofenceAdapter : public LocAdapterBase {
+
+    /* ==== GEOFENCES ====================================================================== */
+    GeofencesMap mGeofences; //map hwId to GeofenceObject
+    GeofenceIdMap mGeofenceIds; //map of GeofenceKey to hwId
+
+protected:
+
+    /* ==== CLIENT ========================================================================= */
+    virtual void updateClientsEventMask();
+    virtual void stopClientSessions(LocationAPI* client);
+
+public:
+
+    GeofenceAdapter();
+    virtual ~GeofenceAdapter() {}
+
+    /* ==== SSR ============================================================================ */
+    /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+    virtual void handleEngineUpEvent();
+    /* ======== UTILITIES ================================================================== */
+    void restartGeofences();
+
+    /* ==== GEOFENCES ====================================================================== */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    uint32_t* addGeofencesCommand(LocationAPI* client, size_t count,
+                                  GeofenceOption* options, GeofenceInfo* info);
+    void removeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids);
+    void pauseGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids);
+    void resumeGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids);
+    void modifyGeofencesCommand(LocationAPI* client, size_t count, uint32_t* ids,
+                                GeofenceOption* options);
+    /* ======== RESPONSES ================================================================== */
+    void reportResponse(LocationAPI* client, size_t count, LocationError* errs, uint32_t* ids);
+    /* ======== UTILITIES ================================================================== */
+    void saveGeofenceItem(LocationAPI* client,
+                          uint32_t clientId,
+                          uint32_t hwId,
+                          const GeofenceOption& options,
+                          const GeofenceInfo& info);
+    void removeGeofenceItem(uint32_t hwId);
+    void pauseGeofenceItem(uint32_t hwId);
+    void resumeGeofenceItem(uint32_t hwId);
+    void modifyGeofenceItem(uint32_t hwId, const GeofenceOption& options);
+    LocationError getHwIdFromClient(LocationAPI* client, uint32_t clientId, uint32_t& hwId);
+    LocationError getGeofenceKeyFromHwId(uint32_t hwId, GeofenceKey& key);
+    void dump();
+
+    /* ==== REPORTS ======================================================================== */
+    /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+    void geofenceBreachEvent(size_t count, uint32_t* hwIds, Location& location,
+                             GeofenceBreachType breachType, uint64_t timestamp);
+    void geofenceStatusEvent(GeofenceStatusAvailable available);
+    /* ======== UTILITIES ================================================================== */
+    void geofenceBreach(size_t count, uint32_t* hwIds, const Location& location,
+                        GeofenceBreachType breachType, uint64_t timestamp);
+    void geofenceStatus(GeofenceStatusAvailable available);
+};
+
+#endif /* GEOFENCE_ADAPTER_H */
diff --git a/gps/geofence/Makefile.am b/gps/geofence/Makefile.am
new file mode 100644
index 0000000..61883ff
--- /dev/null
+++ b/gps/geofence/Makefile.am
@@ -0,0 +1,50 @@
+AM_CFLAGS = -Wundef \
+        -Wno-trigraphs \
+        -g -O0 \
+        -fno-inline \
+        -fno-short-enums \
+        -fpic \
+        ${GPSUTILS_CFLAGS} \
+        ${LOCCORE_CFLAGS} \
+        $(LOCPLA_CFLAGS) \
+        -D__func__=__PRETTY_FUNCTION__ \
+        -std=c++1y
+
+AM_CPPFLAGS = $(AM_CFLAGS)
+
+ACLOCAL_AMFLAGS = -I m4
+
+requiredlibs = \
+        ${LOCCORE_LIBS} \
+        $(GPSUTILS_LIBS) \
+        -llog
+
+h_sources = \
+        GeofenceAdapter.h
+
+c_sources = \
+    GeofenceAdapter.cpp \
+    location_geofence.cpp
+
+libgeofencing_la_SOURCES = $(c_sources)
+if USE_GLIB
+libgeofencing_la_CFLAGS  = -DUSE_GLIB @GLIB_CFLAGS@ $(AM_CFLAGS)
+libgeofencing_la_CPPFLAGS  = -DUSE_GLIB @GLIB_CFLAGS@ $(AM_CFLAGS) $(AM_CPPFLAGS)
+libgeofencing_la_LDFLAGS = -lstdc++ -Wl,-z,defs @GLIB_LIBS@ $(requiredlibs) -shared -version-info 1:0:0
+libgeofencing_la_LIBDADD = $(requiredlibs) -lstdc++ @GLIB_LIBS@
+else
+libgeofencing_la_CFLAGS  = $(AM_CFLAGS)
+libgeofencing_la_CPPFLAGS  = $(AM_CFLAGS) $(AM_CPPFLAGS)
+libgeofencing_la_LDFLAGS = -lstdc++ -Wl,-z,defs $(requiredlibs) -shared -version-info 1:0:0
+libgeofencing_la_LIBDADD = $(requiredlibs) -lstdc++
+endif
+
+library_include_HEADERS = $(h_sources)
+
+library_includedir = $(pkgincludedir)
+
+lib_LTLIBRARIES = libgeofencing.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = location-geofence.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/gps/geofence/configure.ac b/gps/geofence/configure.ac
new file mode 100644
index 0000000..74eae7a
--- /dev/null
+++ b/gps/geofence/configure.ac
@@ -0,0 +1,72 @@
+AC_PREREQ(2.61)
+AC_INIT([location-geofence], 1.0.0)
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+AC_CONFIG_SRCDIR([Makefile.am])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Check for programs
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Check for libraries
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+PKG_CHECK_MODULES([LOCCORE], [loc-core])
+AC_SUBST([LOCCORE_CFLAGS])
+AC_SUBST([LOCCORE_LIBS])
+
+AS_CASE([$host],
+        [arm*], [ARM=yes],
+        [ARM=no]
+)
+
+AC_ARG_WITH([locpla_includes],
+      AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+         [specify the path to locpla-includes in loc-pla_git.bb]),
+      [locpla_incdir=$withval],
+      with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+   AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_ARG_WITH([glib],
+      AC_HELP_STRING([--with-glib],
+         [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+        AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+        PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GThread >= 2.16 is required))
+        PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GLib >= 2.16 is required))
+        GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+        GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+        AC_SUBST(GLIB_CFLAGS)
+        AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_SUBST([CFLAGS])
+AC_SUBST([CPPFLAGS])
+AC_SUBST([LIBS])
+
+AC_CONFIG_FILES([ \
+        Makefile \
+        location-geofence.pc
+        ])
+
+AC_OUTPUT
diff --git a/gps/geofence/location-geofence.pc.in b/gps/geofence/location-geofence.pc.in
new file mode 100644
index 0000000..6a0781f
--- /dev/null
+++ b/gps/geofence/location-geofence.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: location-geofence
+Description: QTI GPS Geofence
+Version: @VERSION
+Libs: -L${libdir} -lgeofencing
+Cflags: -I${includedir}/location-geofence
diff --git a/gps/geofence/location_geofence.cpp b/gps/geofence/location_geofence.cpp
new file mode 100644
index 0000000..66729f4
--- /dev/null
+++ b/gps/geofence/location_geofence.cpp
@@ -0,0 +1,145 @@
+/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include "GeofenceAdapter.h"
+#include "location_interface.h"
+
+static GeofenceAdapter* gGeofenceAdapter = NULL;
+
+static void initialize();
+static void deinitialize();
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks);
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+static void requestCapabilities(LocationAPI* client);
+
+static uint32_t* addGeofences(LocationAPI* client, size_t count, GeofenceOption*, GeofenceInfo*);
+static void removeGeofences(LocationAPI* client, size_t count, uint32_t* ids);
+static void modifyGeofences(LocationAPI* client, size_t count, uint32_t* ids,
+                               GeofenceOption* options);
+static void pauseGeofences(LocationAPI* client, size_t count, uint32_t* ids);
+static void resumeGeofences(LocationAPI* client, size_t count, uint32_t* ids);
+
+static const GeofenceInterface gGeofenceInterface = {
+    sizeof(GeofenceInterface),
+    initialize,
+    deinitialize,
+    addClient,
+    removeClient,
+    requestCapabilities,
+    addGeofences,
+    removeGeofences,
+    modifyGeofences,
+    pauseGeofences,
+    resumeGeofences
+};
+
+#ifndef DEBUG_X86
+extern "C" const GeofenceInterface* getGeofenceInterface()
+#else
+const GeofenceInterface* getGeofenceInterface()
+#endif // DEBUG_X86
+{
+   return &gGeofenceInterface;
+}
+
+static void initialize()
+{
+    if (NULL == gGeofenceAdapter) {
+        gGeofenceAdapter = new GeofenceAdapter();
+    }
+}
+
+static void deinitialize()
+{
+    if (NULL != gGeofenceAdapter) {
+        delete gGeofenceAdapter;
+        gGeofenceAdapter = NULL;
+    }
+}
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+    if (NULL != gGeofenceAdapter) {
+        gGeofenceAdapter->addClientCommand(client, callbacks);
+    }
+}
+
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb)
+{
+    if (NULL != gGeofenceAdapter) {
+        gGeofenceAdapter->removeClientCommand(client, rmClientCb);
+    }
+}
+
+static void requestCapabilities(LocationAPI* client)
+{
+    if (NULL != gGeofenceAdapter) {
+        gGeofenceAdapter->requestCapabilitiesCommand(client);
+    }
+}
+
+static uint32_t* addGeofences(LocationAPI* client, size_t count,
+                              GeofenceOption* options, GeofenceInfo* info)
+{
+    if (NULL != gGeofenceAdapter) {
+        return gGeofenceAdapter->addGeofencesCommand(client, count, options, info);
+    } else {
+        return NULL;
+    }
+}
+
+static void removeGeofences(LocationAPI* client, size_t count, uint32_t* ids)
+{
+    if (NULL != gGeofenceAdapter) {
+        return gGeofenceAdapter->removeGeofencesCommand(client, count, ids);
+    }
+}
+
+static void modifyGeofences(LocationAPI* client, size_t count, uint32_t* ids,
+                            GeofenceOption* options)
+{
+    if (NULL != gGeofenceAdapter) {
+        return gGeofenceAdapter->modifyGeofencesCommand(client, count, ids, options);
+    }
+}
+
+static void pauseGeofences(LocationAPI* client, size_t count, uint32_t* ids)
+{
+    if (NULL != gGeofenceAdapter) {
+        return gGeofenceAdapter->pauseGeofencesCommand(client, count, ids);
+    }
+}
+
+static void resumeGeofences(LocationAPI* client, size_t count, uint32_t* ids)
+{
+    if (NULL != gGeofenceAdapter) {
+        return gGeofenceAdapter->resumeGeofencesCommand(client, count, ids);
+    }
+}
+
diff --git a/gps/gnss/Agps.cpp b/gps/gnss/Agps.cpp
new file mode 100644
index 0000000..0b95f99
--- /dev/null
+++ b/gps/gnss/Agps.cpp
@@ -0,0 +1,675 @@
+/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_Agps"
+
+#include <Agps.h>
+#include <loc_pla.h>
+#include <ContextBase.h>
+#include <loc_timer.h>
+#include <inttypes.h>
+
+/* --------------------------------------------------------------------
+ *   AGPS State Machine Methods
+ * -------------------------------------------------------------------*/
+void AgpsStateMachine::processAgpsEvent(AgpsEvent event){
+
+    LOC_LOGD("processAgpsEvent(): SM %p, Event %d, State %d",
+               this, event, mState);
+
+    switch (event) {
+
+        case AGPS_EVENT_SUBSCRIBE:
+            processAgpsEventSubscribe();
+            break;
+
+        case AGPS_EVENT_UNSUBSCRIBE:
+            processAgpsEventUnsubscribe();
+            break;
+
+        case AGPS_EVENT_GRANTED:
+            processAgpsEventGranted();
+            break;
+
+        case AGPS_EVENT_RELEASED:
+            processAgpsEventReleased();
+            break;
+
+        case AGPS_EVENT_DENIED:
+            processAgpsEventDenied();
+            break;
+
+        default:
+            LOC_LOGE("Invalid Loc Agps Event");
+    }
+}
+
+void AgpsStateMachine::processAgpsEventSubscribe(){
+
+    switch (mState) {
+
+        case AGPS_STATE_RELEASED:
+            /* Add subscriber to list
+             * No notifications until we get RSRC_GRANTED */
+            addSubscriber(mCurrentSubscriber);
+            requestOrReleaseDataConn(true);
+            transitionState(AGPS_STATE_PENDING);
+            break;
+
+        case AGPS_STATE_PENDING:
+            /* Already requested for data connection,
+             * do nothing until we get RSRC_GRANTED event;
+             * Just add this subscriber to the list, for notifications */
+            addSubscriber(mCurrentSubscriber);
+            break;
+
+        case AGPS_STATE_ACQUIRED:
+            /* We already have the data connection setup,
+             * Notify current subscriber with GRANTED event,
+             * And add it to the subscriber list for further notifications. */
+            notifyEventToSubscriber(AGPS_EVENT_GRANTED, mCurrentSubscriber, false);
+            addSubscriber(mCurrentSubscriber);
+            break;
+
+        case AGPS_STATE_RELEASING:
+            addSubscriber(mCurrentSubscriber);
+            break;
+
+        default:
+            LOC_LOGE("Invalid state: %d", mState);
+    }
+}
+
+void AgpsStateMachine::processAgpsEventUnsubscribe(){
+
+    switch (mState) {
+
+        case AGPS_STATE_RELEASED:
+            notifyEventToSubscriber(
+                    AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, false);
+            break;
+
+        case AGPS_STATE_PENDING:
+        case AGPS_STATE_ACQUIRED:
+            /* If the subscriber wishes to wait for connection close,
+             * before being removed from list, move to inactive state
+             * and notify */
+            if (mCurrentSubscriber->mWaitForCloseComplete) {
+                mCurrentSubscriber->mIsInactive = true;
+            }
+            else {
+                /* Notify only current subscriber and then delete it from
+                 * subscriberList */
+                notifyEventToSubscriber(
+                        AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, true);
+            }
+
+            /* If no subscribers in list, release data connection */
+            if (mSubscriberList.empty()) {
+                transitionState(AGPS_STATE_RELEASED);
+                requestOrReleaseDataConn(false);
+            }
+            /* Some subscribers in list, but all inactive;
+             * Release data connection */
+            else if(!anyActiveSubscribers()) {
+                transitionState(AGPS_STATE_RELEASING);
+                requestOrReleaseDataConn(false);
+            }
+            break;
+
+        case AGPS_STATE_RELEASING:
+            /* If the subscriber wishes to wait for connection close,
+             * before being removed from list, move to inactive state
+             * and notify */
+            if (mCurrentSubscriber->mWaitForCloseComplete) {
+                mCurrentSubscriber->mIsInactive = true;
+            }
+            else {
+                /* Notify only current subscriber and then delete it from
+                 * subscriberList */
+                notifyEventToSubscriber(
+                        AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, true);
+            }
+
+            /* If no subscribers in list, just move the state.
+             * Request for releasing data connection should already have been
+             * sent */
+            if (mSubscriberList.empty()) {
+                transitionState(AGPS_STATE_RELEASED);
+            }
+            break;
+
+        default:
+            LOC_LOGE("Invalid state: %d", mState);
+    }
+}
+
+void AgpsStateMachine::processAgpsEventGranted(){
+
+    switch (mState) {
+
+        case AGPS_STATE_RELEASED:
+        case AGPS_STATE_ACQUIRED:
+        case AGPS_STATE_RELEASING:
+            LOC_LOGE("Unexpected event GRANTED in state %d", mState);
+            break;
+
+        case AGPS_STATE_PENDING:
+            // Move to acquired state
+            transitionState(AGPS_STATE_ACQUIRED);
+            notifyAllSubscribers(
+                    AGPS_EVENT_GRANTED, false,
+                    AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS);
+            break;
+
+        default:
+            LOC_LOGE("Invalid state: %d", mState);
+    }
+}
+
+void AgpsStateMachine::processAgpsEventReleased(){
+
+    switch (mState) {
+
+        case AGPS_STATE_RELEASED:
+            /* Subscriber list should be empty if we are in released state */
+            if (!mSubscriberList.empty()) {
+                LOC_LOGE("Unexpected event RELEASED in RELEASED state");
+            }
+            break;
+
+        case AGPS_STATE_ACQUIRED:
+            /* Force release received */
+            LOC_LOGW("Force RELEASED event in ACQUIRED state");
+            transitionState(AGPS_STATE_RELEASED);
+            notifyAllSubscribers(
+                    AGPS_EVENT_RELEASED, true,
+                    AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS);
+            break;
+
+        case AGPS_STATE_RELEASING:
+            /* Notify all inactive subscribers about the event */
+            notifyAllSubscribers(
+                    AGPS_EVENT_RELEASED, true,
+                    AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS);
+
+            /* If we have active subscribers now, they must be waiting for
+             * data conn setup */
+            if (anyActiveSubscribers()) {
+                transitionState(AGPS_STATE_PENDING);
+                requestOrReleaseDataConn(true);
+            }
+            /* No active subscribers, move to released state */
+            else {
+                transitionState(AGPS_STATE_RELEASED);
+            }
+            break;
+
+        case AGPS_STATE_PENDING:
+            /* NOOP */
+            break;
+
+        default:
+            LOC_LOGE("Invalid state: %d", mState);
+    }
+}
+
+void AgpsStateMachine::processAgpsEventDenied(){
+
+    switch (mState) {
+
+        case AGPS_STATE_RELEASED:
+            LOC_LOGE("Unexpected event DENIED in state %d", mState);
+            break;
+
+        case AGPS_STATE_ACQUIRED:
+            /* NOOP */
+            break;
+
+        case AGPS_STATE_RELEASING:
+            /* Notify all inactive subscribers about the event */
+            notifyAllSubscribers(
+                    AGPS_EVENT_RELEASED, true,
+                    AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS);
+
+            /* If we have active subscribers now, they must be waiting for
+             * data conn setup */
+            if (anyActiveSubscribers()) {
+                transitionState(AGPS_STATE_PENDING);
+                requestOrReleaseDataConn(true);
+            }
+            /* No active subscribers, move to released state */
+            else {
+                transitionState(AGPS_STATE_RELEASED);
+            }
+            break;
+
+        case AGPS_STATE_PENDING:
+            transitionState(AGPS_STATE_RELEASED);
+            notifyAllSubscribers(
+                    AGPS_EVENT_DENIED, true,
+                    AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS);
+            break;
+
+        default:
+            LOC_LOGE("Invalid state: %d", mState);
+    }
+}
+
+/* Request or Release data connection
+ * bool request :
+ *      true  = Request data connection
+ *      false = Release data connection */
+void AgpsStateMachine::requestOrReleaseDataConn(bool request){
+
+    AGnssExtStatusIpV4 nifRequest;
+    memset(&nifRequest, 0, sizeof(nifRequest));
+
+    nifRequest.type = mAgpsType;
+    nifRequest.apnTypeMask = mApnTypeMask;
+    if (request) {
+        LOC_LOGD("AGPS Data Conn Request mAgpsType=%d mApnTypeMask=0x%X",
+                 mAgpsType, mApnTypeMask);
+        nifRequest.status = LOC_GPS_REQUEST_AGPS_DATA_CONN;
+    }
+    else{
+        LOC_LOGD("AGPS Data Conn Release mAgpsType=%d mApnTypeMask=0x%X",
+                 mAgpsType, mApnTypeMask);
+        nifRequest.status = LOC_GPS_RELEASE_AGPS_DATA_CONN;
+    }
+
+    mFrameworkStatusV4Cb(nifRequest);
+}
+
+void AgpsStateMachine::notifyAllSubscribers(
+        AgpsEvent event, bool deleteSubscriberPostNotify,
+        AgpsNotificationType notificationType){
+
+    LOC_LOGD("notifyAllSubscribers(): "
+            "SM %p, Event %d Delete %d Notification Type %d",
+            this, event, deleteSubscriberPostNotify, notificationType);
+
+    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+    while ( it != mSubscriberList.end() ) {
+
+        AgpsSubscriber* subscriber = *it;
+
+        if (notificationType == AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS ||
+                (notificationType == AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS &&
+                        subscriber->mIsInactive) ||
+                (notificationType == AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS &&
+                        !subscriber->mIsInactive)) {
+
+            /* Deleting via this call would require another traversal
+             * through subscriber list, inefficient; hence pass in false*/
+            notifyEventToSubscriber(event, subscriber, false);
+
+            if (deleteSubscriberPostNotify) {
+                it = mSubscriberList.erase(it);
+                delete subscriber;
+            } else {
+                it++;
+            }
+        } else {
+            it++;
+        }
+    }
+}
+
+void AgpsStateMachine::notifyEventToSubscriber(
+        AgpsEvent event, AgpsSubscriber* subscriberToNotify,
+        bool deleteSubscriberPostNotify) {
+
+    LOC_LOGD("notifyEventToSubscriber(): "
+            "SM %p, Event %d Subscriber %p Delete %d",
+            this, event, subscriberToNotify, deleteSubscriberPostNotify);
+
+    switch (event) {
+
+        case AGPS_EVENT_GRANTED:
+            mAgpsManager->mAtlOpenStatusCb(
+                    subscriberToNotify->mConnHandle, 1, getAPN(), getAPNLen(),
+                    getBearer(), mAgpsType, mApnTypeMask);
+            break;
+
+        case AGPS_EVENT_DENIED:
+            mAgpsManager->mAtlOpenStatusCb(
+                    subscriberToNotify->mConnHandle, 0, getAPN(), getAPNLen(),
+                    getBearer(), mAgpsType, mApnTypeMask);
+            break;
+
+        case AGPS_EVENT_UNSUBSCRIBE:
+        case AGPS_EVENT_RELEASED:
+            mAgpsManager->mAtlCloseStatusCb(subscriberToNotify->mConnHandle, 1);
+            break;
+
+        default:
+            LOC_LOGE("Invalid event %d", event);
+    }
+
+    /* Search this subscriber in list and delete */
+    if (deleteSubscriberPostNotify) {
+        deleteSubscriber(subscriberToNotify);
+    }
+}
+
+void AgpsStateMachine::transitionState(AgpsState newState){
+
+    LOC_LOGD("transitionState(): SM %p, old %d, new %d",
+               this, mState, newState);
+
+    mState = newState;
+
+    // notify state transitions to all subscribers ?
+}
+
+void AgpsStateMachine::addSubscriber(AgpsSubscriber* subscriberToAdd){
+
+    LOC_LOGD("addSubscriber(): SM %p, Subscriber %p",
+               this, subscriberToAdd);
+
+    // Check if subscriber is already present in the current list
+    // If not, then add
+    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+    for (; it != mSubscriberList.end(); it++) {
+        AgpsSubscriber* subscriber = *it;
+        if (subscriber->equals(subscriberToAdd)) {
+            LOC_LOGE("Subscriber already in list");
+            return;
+        }
+    }
+
+    AgpsSubscriber* cloned = subscriberToAdd->clone();
+    LOC_LOGD("addSubscriber(): cloned subscriber: %p", cloned);
+    mSubscriberList.push_back(cloned);
+}
+
+void AgpsStateMachine::deleteSubscriber(AgpsSubscriber* subscriberToDelete){
+
+    LOC_LOGD("deleteSubscriber(): SM %p, Subscriber %p",
+               this, subscriberToDelete);
+
+    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+    while ( it != mSubscriberList.end() ) {
+
+        AgpsSubscriber* subscriber = *it;
+        if (subscriber && subscriber->equals(subscriberToDelete)) {
+
+            it = mSubscriberList.erase(it);
+            delete subscriber;
+        } else {
+            it++;
+        }
+    }
+}
+
+bool AgpsStateMachine::anyActiveSubscribers(){
+
+    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+    for (; it != mSubscriberList.end(); it++) {
+        AgpsSubscriber* subscriber = *it;
+        if (!subscriber->mIsInactive) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void AgpsStateMachine::setAPN(char* apn, unsigned int len){
+
+    if (NULL != mAPN) {
+        delete mAPN;
+        mAPN  = NULL;
+    }
+
+    if (NULL == apn || len > MAX_APN_LEN || strlen(apn) != len) {
+        LOC_LOGD("Invalid apn len (%d) or null apn", len);
+        mAPN = NULL;
+        mAPNLen = 0;
+    } else {
+        mAPN = new char[len+1];
+        if (NULL != mAPN) {
+            memcpy(mAPN, apn, len);
+            mAPN[len] = '\0';
+            mAPNLen = len;
+        }
+    }
+}
+
+AgpsSubscriber* AgpsStateMachine::getSubscriber(int connHandle){
+
+    /* Go over the subscriber list */
+    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+    for (; it != mSubscriberList.end(); it++) {
+        AgpsSubscriber* subscriber = *it;
+        if (subscriber->mConnHandle == connHandle) {
+            return subscriber;
+        }
+    }
+
+    /* Not found, return NULL */
+    return NULL;
+}
+
+AgpsSubscriber* AgpsStateMachine::getFirstSubscriber(bool isInactive){
+
+    /* Go over the subscriber list */
+    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+    for (; it != mSubscriberList.end(); it++) {
+        AgpsSubscriber* subscriber = *it;
+        if(subscriber->mIsInactive == isInactive) {
+            return subscriber;
+        }
+    }
+
+    /* Not found, return NULL */
+    return NULL;
+}
+
+void AgpsStateMachine::dropAllSubscribers(){
+
+    LOC_LOGD("dropAllSubscribers(): SM %p", this);
+
+    /* Go over the subscriber list */
+    std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin();
+    while ( it != mSubscriberList.end() ) {
+        AgpsSubscriber* subscriber = *it;
+        it = mSubscriberList.erase(it);
+        delete subscriber;
+    }
+}
+
+/* --------------------------------------------------------------------
+ *   Loc AGPS Manager Methods
+ * -------------------------------------------------------------------*/
+
+/* CREATE AGPS STATE MACHINES
+ * Must be invoked in Msg Handler context */
+void AgpsManager::createAgpsStateMachines(const AgpsCbInfo& cbInfo) {
+
+    LOC_LOGD("AgpsManager::createAgpsStateMachines");
+
+    bool agpsCapable =
+            ((loc_core::ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSA) ||
+                    (loc_core::ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSB));
+
+    if (NULL == mInternetNif && (cbInfo.atlType & AGPS_ATL_TYPE_WWAN)) {
+        mInternetNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_WWAN_ANY);
+        mInternetNif->registerFrameworkStatusCallback((AgnssStatusIpV4Cb)cbInfo.statusV4Cb);
+        LOC_LOGD("Internet NIF: %p", mInternetNif);
+    }
+    if (agpsCapable) {
+        if (NULL == mAgnssNif && (cbInfo.atlType & AGPS_ATL_TYPE_SUPL) &&
+                (cbInfo.atlType & AGPS_ATL_TYPE_SUPL_ES)) {
+            mAgnssNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_SUPL);
+            mAgnssNif->registerFrameworkStatusCallback((AgnssStatusIpV4Cb)cbInfo.statusV4Cb);
+            LOC_LOGD("AGNSS NIF: %p", mAgnssNif);
+        }
+    }
+}
+
+AgpsStateMachine* AgpsManager::getAgpsStateMachine(AGpsExtType agpsType) {
+
+    LOC_LOGD("AgpsManager::getAgpsStateMachine(): agpsType %d", agpsType);
+
+    switch (agpsType) {
+
+        case LOC_AGPS_TYPE_INVALID:
+        case LOC_AGPS_TYPE_SUPL:
+        case LOC_AGPS_TYPE_SUPL_ES:
+            if (mAgnssNif == NULL) {
+                LOC_LOGE("NULL AGNSS NIF !");
+            }
+            return mAgnssNif;
+        case LOC_AGPS_TYPE_WWAN_ANY:
+            if (mInternetNif == NULL) {
+                LOC_LOGE("NULL Internet NIF !");
+            }
+            return mInternetNif;
+        default:
+            return mInternetNif;
+    }
+
+    LOC_LOGE("No SM found !");
+    return NULL;
+}
+
+void AgpsManager::requestATL(int connHandle, AGpsExtType agpsType,
+                             LocApnTypeMask apnTypeMask){
+
+    LOC_LOGD("AgpsManager::requestATL(): connHandle %d, agpsType 0x%X apnTypeMask: 0x%X",
+               connHandle, agpsType, apnTypeMask);
+
+    if (0 == loc_core::ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL &&
+        LOC_AGPS_TYPE_SUPL_ES == agpsType) {
+        agpsType = LOC_AGPS_TYPE_SUPL;
+        apnTypeMask &= ~LOC_APN_TYPE_MASK_EMERGENCY;
+        apnTypeMask |= LOC_APN_TYPE_MASK_SUPL;
+        LOC_LOGD("Changed agpsType to non-emergency when USE_EMERGENCY... is 0"
+                 "and removed LOC_APN_TYPE_MASK_EMERGENCY from apnTypeMask"
+                 "agpsType 0x%X apnTypeMask : 0x%X",
+                 agpsType, apnTypeMask);
+    }
+    AgpsStateMachine* sm = getAgpsStateMachine(agpsType);
+
+    if (sm == NULL) {
+
+        LOC_LOGE("No AGPS State Machine for agpsType: %d apnTypeMask: 0x%X",
+                 agpsType, apnTypeMask);
+        mAtlOpenStatusCb(
+                connHandle, 0, NULL, 0, AGPS_APN_BEARER_INVALID, agpsType, apnTypeMask);
+        return;
+    }
+    sm->setType(agpsType);
+    sm->setApnTypeMask(apnTypeMask);
+
+    /* Invoke AGPS SM processing */
+    AgpsSubscriber subscriber(connHandle, true, false, apnTypeMask);
+    sm->setCurrentSubscriber(&subscriber);
+    /* Send subscriber event */
+    sm->processAgpsEvent(AGPS_EVENT_SUBSCRIBE);
+}
+
+void AgpsManager::releaseATL(int connHandle){
+
+    LOC_LOGD("AgpsManager::releaseATL(): connHandle %d", connHandle);
+
+    /* First find the subscriber with specified handle.
+     * We need to search in all state machines. */
+    AgpsStateMachine* sm = NULL;
+    AgpsSubscriber* subscriber = NULL;
+
+    if (mAgnssNif &&
+            (subscriber = mAgnssNif->getSubscriber(connHandle)) != NULL) {
+        sm = mAgnssNif;
+    }
+    else if (mInternetNif &&
+            (subscriber = mInternetNif->getSubscriber(connHandle)) != NULL) {
+        sm = mInternetNif;
+    }
+    if (sm == NULL) {
+        LOC_LOGE("Subscriber with connHandle %d not found in any SM",
+                    connHandle);
+        return;
+    }
+
+    /* Now send unsubscribe event */
+    sm->setCurrentSubscriber(subscriber);
+    sm->processAgpsEvent(AGPS_EVENT_UNSUBSCRIBE);
+}
+
+void AgpsManager::reportAtlOpenSuccess(
+        AGpsExtType agpsType, char* apnName, int apnLen,
+        AGpsBearerType bearerType){
+
+    LOC_LOGD("AgpsManager::reportAtlOpenSuccess(): "
+             "AgpsType %d, APN [%s], Len %d, BearerType %d",
+             agpsType, apnName, apnLen, bearerType);
+
+    /* Find the state machine instance */
+    AgpsStateMachine* sm = getAgpsStateMachine(agpsType);
+
+    /* Set bearer and apn info in state machine instance */
+    sm->setBearer(bearerType);
+    sm->setAPN(apnName, apnLen);
+
+    /* Send GRANTED event to state machine */
+    sm->processAgpsEvent(AGPS_EVENT_GRANTED);
+}
+
+void AgpsManager::reportAtlOpenFailed(AGpsExtType agpsType){
+
+    LOC_LOGD("AgpsManager::reportAtlOpenFailed(): AgpsType %d", agpsType);
+
+    /* Fetch SM and send DENIED event */
+    AgpsStateMachine* sm = getAgpsStateMachine(agpsType);
+    sm->processAgpsEvent(AGPS_EVENT_DENIED);
+}
+
+void AgpsManager::reportAtlClosed(AGpsExtType agpsType){
+
+    LOC_LOGD("AgpsManager::reportAtlClosed(): AgpsType %d", agpsType);
+
+    /* Fetch SM and send RELEASED event */
+    AgpsStateMachine* sm = getAgpsStateMachine(agpsType);
+    sm->processAgpsEvent(AGPS_EVENT_RELEASED);
+}
+
+void AgpsManager::handleModemSSR(){
+
+    LOC_LOGD("AgpsManager::handleModemSSR");
+
+    /* Drop subscribers from all state machines */
+    if (mAgnssNif) {
+        mAgnssNif->dropAllSubscribers();
+    }
+    if (mInternetNif) {
+        mInternetNif->dropAllSubscribers();
+    }
+}
diff --git a/gps/gnss/Agps.h b/gps/gnss/Agps.h
new file mode 100644
index 0000000..8a27cd9
--- /dev/null
+++ b/gps/gnss/Agps.h
@@ -0,0 +1,318 @@
+/* Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef AGPS_H
+#define AGPS_H
+
+#include <functional>
+#include <list>
+#include <MsgTask.h>
+#include <gps_extended_c.h>
+#include <loc_pla.h>
+#include <log_util.h>
+
+using namespace loc_util;
+
+/* ATL callback function pointers
+ * Passed in by Adapter to AgpsManager */
+typedef std::function<void(
+        int handle, int isSuccess, char* apn, uint32_t apnLen,
+        AGpsBearerType bearerType, AGpsExtType agpsType,
+        LocApnTypeMask mask)> AgpsAtlOpenStatusCb;
+
+typedef std::function<void(int handle, int isSuccess)> AgpsAtlCloseStatusCb;
+
+/* Post message to adapter's message queue */
+typedef std::function<void(LocMsg* msg)>     SendMsgToAdapterMsgQueueFn;
+
+/* AGPS States */
+typedef enum {
+    AGPS_STATE_INVALID = 0,
+    AGPS_STATE_RELEASED,
+    AGPS_STATE_PENDING,
+    AGPS_STATE_ACQUIRED,
+    AGPS_STATE_RELEASING
+} AgpsState;
+
+typedef enum {
+    AGPS_EVENT_INVALID = 0,
+    AGPS_EVENT_SUBSCRIBE,
+    AGPS_EVENT_UNSUBSCRIBE,
+    AGPS_EVENT_GRANTED,
+    AGPS_EVENT_RELEASED,
+    AGPS_EVENT_DENIED
+} AgpsEvent;
+
+/* Notification Types sent to subscribers */
+typedef enum {
+    AGPS_NOTIFICATION_TYPE_INVALID = 0,
+
+    /* Meant for all subscribers, either active or inactive */
+    AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS,
+
+    /* Meant for only inactive subscribers */
+    AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS,
+
+    /* Meant for only active subscribers */
+    AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS
+} AgpsNotificationType;
+
+/* Classes in this header */
+class AgpsSubscriber;
+class AgpsManager;
+class AgpsStateMachine;
+
+/* SUBSCRIBER
+ * Each Subscriber instance corresponds to one AGPS request,
+ * received by the AGPS state machine */
+class AgpsSubscriber {
+
+public:
+    int mConnHandle;
+
+    /* Does this subscriber wait for data call close complete,
+     * before being notified ATL close ?
+     * While waiting for data call close, subscriber will be in
+     * inactive state. */
+    bool mWaitForCloseComplete;
+    bool mIsInactive;
+    LocApnTypeMask mApnTypeMask;
+
+    inline AgpsSubscriber(
+            int connHandle, bool waitForCloseComplete, bool isInactive,
+            LocApnTypeMask apnTypeMask) :
+            mConnHandle(connHandle),
+            mWaitForCloseComplete(waitForCloseComplete),
+            mIsInactive(isInactive),
+            mApnTypeMask(apnTypeMask) {}
+    inline virtual ~AgpsSubscriber() {}
+
+    inline virtual bool equals(const AgpsSubscriber *s) const
+    { return (mConnHandle == s->mConnHandle); }
+
+    inline virtual AgpsSubscriber* clone()
+    { return new AgpsSubscriber(
+            mConnHandle, mWaitForCloseComplete, mIsInactive, mApnTypeMask); }
+};
+
+/* AGPS STATE MACHINE */
+class AgpsStateMachine {
+protected:
+    /* AGPS Manager instance, from where this state machine is created */
+    AgpsManager* mAgpsManager;
+
+    /* List of all subscribers for this State Machine.
+     * Once a subscriber is notified for ATL open/close status,
+     * it is deleted */
+    std::list<AgpsSubscriber*> mSubscriberList;
+
+    /* Current subscriber, whose request this State Machine is
+     * currently processing */
+    AgpsSubscriber* mCurrentSubscriber;
+
+    /* Current state for this state machine */
+    AgpsState mState;
+
+    AgnssStatusIpV4Cb     mFrameworkStatusV4Cb;
+private:
+    /* AGPS Type for this state machine
+       LOC_AGPS_TYPE_ANY           0
+       LOC_AGPS_TYPE_SUPL          1
+       LOC_AGPS_TYPE_WWAN_ANY      3
+       LOC_AGPS_TYPE_SUPL_ES       5 */
+    AGpsExtType mAgpsType;
+    LocApnTypeMask mApnTypeMask;
+
+    /* APN and IP Type info for AGPS Call */
+    char* mAPN;
+    unsigned int mAPNLen;
+    AGpsBearerType mBearer;
+
+public:
+    /* CONSTRUCTOR */
+    AgpsStateMachine(AgpsManager* agpsManager, AGpsExtType agpsType):
+        mFrameworkStatusV4Cb(NULL),
+        mAgpsManager(agpsManager), mSubscriberList(),
+        mCurrentSubscriber(NULL), mState(AGPS_STATE_RELEASED),
+        mAgpsType(agpsType), mAPN(NULL), mAPNLen(0),
+        mBearer(AGPS_APN_BEARER_INVALID) {};
+
+    virtual ~AgpsStateMachine() { if(NULL != mAPN) delete[] mAPN; };
+
+    /* Getter/Setter methods */
+    void setAPN(char* apn, unsigned int len);
+    inline char* getAPN() const { return mAPN; }
+    inline uint32_t getAPNLen() const { return mAPNLen; }
+    inline void setBearer(AGpsBearerType bearer) { mBearer = bearer; }
+    inline LocApnTypeMask getApnTypeMask() const { return mApnTypeMask; }
+    inline void setApnTypeMask(LocApnTypeMask apnTypeMask)
+    { mApnTypeMask = apnTypeMask; }
+    inline AGpsBearerType getBearer() const { return mBearer; }
+    inline void setType(AGpsExtType type) { mAgpsType = type; }
+    inline AGpsExtType getType() const { return mAgpsType; }
+    inline void setCurrentSubscriber(AgpsSubscriber* subscriber)
+    { mCurrentSubscriber = subscriber; }
+
+    inline void registerFrameworkStatusCallback(AgnssStatusIpV4Cb frameworkStatusV4Cb) {
+        mFrameworkStatusV4Cb = frameworkStatusV4Cb;
+    }
+
+    /* Fetch subscriber with specified handle */
+    AgpsSubscriber* getSubscriber(int connHandle);
+
+    /* Fetch first active or inactive subscriber in list
+     * isInactive = true : fetch first inactive subscriber
+     * isInactive = false : fetch first active subscriber */
+    AgpsSubscriber* getFirstSubscriber(bool isInactive);
+
+    /* Process LOC AGPS Event being passed in
+     * onRsrcEvent */
+    virtual void processAgpsEvent(AgpsEvent event);
+
+    /* Drop all subscribers, in case of Modem SSR */
+    void dropAllSubscribers();
+
+protected:
+    /* Remove the specified subscriber from list if present.
+     * Also delete the subscriber instance. */
+    void deleteSubscriber(AgpsSubscriber* subscriber);
+
+private:
+    /* Send call setup request to framework
+     * sendRsrcRequest(LOC_GPS_REQUEST_AGPS_DATA_CONN)
+     * sendRsrcRequest(LOC_GPS_RELEASE_AGPS_DATA_CONN) */
+    void requestOrReleaseDataConn(bool request);
+
+    /* Individual event processing methods */
+    void processAgpsEventSubscribe();
+    void processAgpsEventUnsubscribe();
+    void processAgpsEventGranted();
+    void processAgpsEventReleased();
+    void processAgpsEventDenied();
+
+    /* Clone the passed in subscriber and add to the subscriber list
+     * if not already present */
+    void addSubscriber(AgpsSubscriber* subscriber);
+
+    /* Notify subscribers about AGPS events */
+    void notifyAllSubscribers(
+            AgpsEvent event, bool deleteSubscriberPostNotify,
+            AgpsNotificationType notificationType);
+    virtual void notifyEventToSubscriber(
+            AgpsEvent event, AgpsSubscriber* subscriber,
+            bool deleteSubscriberPostNotify);
+
+    /* Do we have any subscribers in active state */
+    bool anyActiveSubscribers();
+
+    /* Transition state */
+    void transitionState(AgpsState newState);
+};
+
+/* LOC AGPS MANAGER */
+class AgpsManager {
+
+    friend class AgpsStateMachine;
+public:
+    /* CONSTRUCTOR */
+    AgpsManager():
+        mAtlOpenStatusCb(), mAtlCloseStatusCb(),
+        mAgnssNif(NULL), mInternetNif(NULL)/*, mDsNif(NULL)*/ {}
+
+    /* Register callbacks */
+    inline void registerATLCallbacks(AgpsAtlOpenStatusCb  atlOpenStatusCb,
+            AgpsAtlCloseStatusCb                atlCloseStatusCb) {
+
+        mAtlOpenStatusCb = atlOpenStatusCb;
+        mAtlCloseStatusCb = atlCloseStatusCb;
+    }
+
+    /* Check if AGPS client is registered */
+    inline bool isRegistered() { return nullptr != mAgnssNif || nullptr != mInternetNif; }
+
+    /* Create all AGPS state machines */
+    void createAgpsStateMachines(const AgpsCbInfo& cbInfo);
+
+    /* Process incoming ATL requests */
+    void requestATL(int connHandle, AGpsExtType agpsType, LocApnTypeMask apnTypeMask);
+    void releaseATL(int connHandle);
+    /* Process incoming framework data call events */
+    void reportAtlOpenSuccess(AGpsExtType agpsType, char* apnName, int apnLen,
+            AGpsBearerType bearerType);
+    void reportAtlOpenFailed(AGpsExtType agpsType);
+    void reportAtlClosed(AGpsExtType agpsType);
+
+    /* Handle Modem SSR */
+    void handleModemSSR();
+
+protected:
+
+    AgpsAtlOpenStatusCb   mAtlOpenStatusCb;
+    AgpsAtlCloseStatusCb  mAtlCloseStatusCb;
+    AgpsStateMachine*   mAgnssNif;
+    AgpsStateMachine*   mInternetNif;
+private:
+    /* Fetch state machine for handling request ATL call */
+    AgpsStateMachine* getAgpsStateMachine(AGpsExtType agpsType);
+};
+
+/* Request SUPL/INTERNET/SUPL_ES ATL
+ * This LocMsg is defined in this header since it has to be used from more
+ * than one place, other Agps LocMsg are restricted to GnssAdapter and
+ * declared inline */
+struct AgpsMsgRequestATL: public LocMsg {
+
+    AgpsManager* mAgpsManager;
+    int mConnHandle;
+    AGpsExtType mAgpsType;
+    LocApnTypeMask mApnTypeMask;
+
+    inline AgpsMsgRequestATL(AgpsManager* agpsManager, int connHandle,
+            AGpsExtType agpsType, LocApnTypeMask apnTypeMask) :
+            LocMsg(), mAgpsManager(agpsManager), mConnHandle(connHandle),
+            mAgpsType(agpsType), mApnTypeMask(apnTypeMask){
+
+        LOC_LOGV("AgpsMsgRequestATL");
+    }
+
+    inline virtual void proc() const {
+
+        LOC_LOGV("AgpsMsgRequestATL::proc()");
+        mAgpsManager->requestATL(mConnHandle, mAgpsType, mApnTypeMask);
+    }
+};
+
+namespace AgpsUtils {
+
+AGpsBearerType ipTypeToBearerType(LocApnIpType ipType);
+LocApnIpType bearerTypeToIpType(AGpsBearerType bearerType);
+
+}
+
+#endif /* AGPS_H */
diff --git a/gps/gnss/Android.bp b/gps/gnss/Android.bp
new file mode 100644
index 0000000..736ea81
--- /dev/null
+++ b/gps/gnss/Android.bp
@@ -0,0 +1,35 @@
+
+
+cc_library_shared {
+
+    name: "libgnss",
+    vendor: true,
+
+
+
+    shared_libs: [
+        "libutils",
+        "libcutils",
+        "libdl",
+        "liblog",
+        "libloc_core",
+        "libgps.utils",
+    ],
+
+    srcs: [
+        "location_gnss.cpp",
+        "GnssAdapter.cpp",
+        "Agps.cpp",
+        "XtraSystemStatusObserver.cpp",
+        "NativeAgpsHandler.cpp",
+    ],
+
+    cflags: ["-fno-short-enums"] + GNSS_CFLAGS,
+    header_libs: [
+        "libgps.utils_headers",
+        "libloc_core_headers",
+        "libloc_pla_headers",
+        "liblocation_api_headers",
+    ],
+
+}
diff --git a/gps/gnss/GnssAdapter.cpp b/gps/gnss/GnssAdapter.cpp
new file mode 100644
index 0000000..f3ccd99
--- /dev/null
+++ b/gps/gnss/GnssAdapter.cpp
@@ -0,0 +1,6979 @@
+/* Copyright (c) 2017-2021 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_GnssAdapter"
+
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <math.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <GnssAdapter.h>
+#include <string>
+#include <sstream>
+#include <loc_log.h>
+#include <loc_nmea.h>
+#include <Agps.h>
+#include <SystemStatus.h>
+#include <vector>
+#include <loc_misc_utils.h>
+#include <gps_extended_c.h>
+
+#define RAD2DEG    (180.0 / M_PI)
+#define DEG2RAD    (M_PI / 180.0)
+#define PROCESS_NAME_ENGINE_SERVICE "engine-service"
+#define MIN_TRACKING_INTERVAL (100) // 100 msec
+
+#define BILLION_NSEC (1000000000ULL)
+#define NMEA_MIN_THRESHOLD_MSEC (99)
+#define NMEA_MAX_THRESHOLD_MSEC (975)
+
+#define DGNSS_RANGE_UPDATE_TIME_10MIN_IN_MILLI  600000
+
+using namespace loc_core;
+
+static int loadEngHubForExternalEngine = 0;
+static loc_param_s_type izatConfParamTable[] = {
+    {"LOAD_ENGHUB_FOR_EXTERNAL_ENGINE", &loadEngHubForExternalEngine, nullptr,'n'}
+};
+
+/* Method to fetch status cb from loc_net_iface library */
+typedef AgpsCbInfo& (*LocAgpsGetAgpsCbInfo)(LocAgpsOpenResultCb openResultCb,
+        LocAgpsCloseResultCb closeResultCb, void* userDataPtr);
+
+static void agpsOpenResultCb (bool isSuccess, AGpsExtType agpsType, const char* apn,
+        AGpsBearerType bearerType, void* userDataPtr);
+static void agpsCloseResultCb (bool isSuccess, AGpsExtType agpsType, void* userDataPtr);
+
+typedef const CdfwInterface* (*getCdfwInterface)();
+
+typedef void getPdnTypeFromWds(const std::string& apnName, std::function<void(int)> pdnCb);
+
+inline bool GnssReportLoggerUtil::isLogEnabled() {
+    return (mLogLatency != nullptr);
+}
+
+inline void GnssReportLoggerUtil::log(const GnssLatencyInfo& gnssLatencyMeasInfo) {
+    if (mLogLatency != nullptr) {
+        mLogLatency(gnssLatencyMeasInfo);
+    }
+}
+
+GnssAdapter::GnssAdapter() :
+    LocAdapterBase(0,
+                   LocContext::getLocContext(LocContext::mLocationHalName),
+                   true, nullptr, true),
+    mEngHubProxy(new EngineHubProxyBase()),
+    mQDgnssListenerHDL(nullptr),
+    mCdfwInterface(nullptr),
+    mDGnssNeedReport(false),
+    mDGnssDataUsage(false),
+    mLocPositionMode(),
+    mNHzNeeded(false),
+    mSPEAlreadyRunningAtHighestInterval(false),
+    mGnssSvIdUsedInPosition(),
+    mGnssSvIdUsedInPosAvail(false),
+    mControlCallbacks(),
+    mAfwControlId(0),
+    mNmeaMask(0),
+    mGnssSvIdConfig(),
+    mGnssSeconaryBandConfig(),
+    mGnssSvTypeConfig(),
+    mGnssSvTypeConfigCb(nullptr),
+    mLocConfigInfo{},
+    mNiData(),
+    mAgpsManager(),
+    mOdcpiRequestCb(nullptr),
+    mOdcpiRequestActive(false),
+    mOdcpiTimer(this),
+    mOdcpiRequest(),
+    mCallbackPriority(OdcpiPrioritytype::ODCPI_HANDLER_PRIORITY_LOW),
+    mSystemStatus(SystemStatus::getInstance(mMsgTask)),
+    mServerUrl(":"),
+    mXtraObserver(mSystemStatus->getOsObserver(), mMsgTask),
+    mBlockCPIInfo{},
+    mDreIntEnabled(false),
+    mLocSystemInfo{},
+    mNfwCb(NULL),
+    mPowerOn(false),
+    mAllowFlpNetworkFixes(0),
+    mGnssEnergyConsumedCb(nullptr),
+    mPowerStateCb(nullptr),
+    mIsE911Session(NULL),
+    mGnssMbSvIdUsedInPosition{},
+    mGnssMbSvIdUsedInPosAvail(false),
+    mSupportNfwControl(true),
+    mSystemPowerState(POWER_STATE_UNKNOWN),
+    mIsMeasCorrInterfaceOpen(false),
+    mIsAntennaInfoInterfaceOpened(false),
+    mLastDeleteAidingDataTime(0),
+    mDgnssState(0),
+    mSendNmeaConsent(false),
+    mDgnssLastNmeaBootTimeMilli(0),
+    mNativeAgpsHandler(mSystemStatus->getOsObserver(), *this)
+{
+    LOC_LOGD("%s]: Constructor %p", __func__, this);
+    mLocPositionMode.mode = LOC_POSITION_MODE_INVALID;
+
+    pthread_condattr_t condAttr;
+    pthread_condattr_init(&condAttr);
+    pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
+    pthread_cond_init(&mNiData.session.tCond, &condAttr);
+    pthread_cond_init(&mNiData.sessionEs.tCond, &condAttr);
+    pthread_condattr_destroy(&condAttr);
+
+    /* Set ATL open/close callbacks */
+    AgpsAtlOpenStatusCb atlOpenStatusCb =
+            [this](int handle, int isSuccess, char* apn, uint32_t apnLen,
+                    AGpsBearerType bearerType, AGpsExtType agpsType, LocApnTypeMask mask) {
+
+                mLocApi->atlOpenStatus(
+                        handle, isSuccess, apn, apnLen, bearerType, agpsType, mask);
+            };
+    AgpsAtlCloseStatusCb atlCloseStatusCb =
+            [this](int handle, int isSuccess) {
+
+                mLocApi->atlCloseStatus(handle, isSuccess);
+            };
+    mAgpsManager.registerATLCallbacks(atlOpenStatusCb, atlCloseStatusCb);
+
+    readConfigCommand();
+    initDefaultAgpsCommand();
+    initEngHubProxyCommand();
+
+    // at last step, let us inform adapater base that we are done
+    // with initialization, e.g.: ready to process handleEngineUpEvent
+    doneInit();
+}
+
+void
+GnssAdapter::setControlCallbacksCommand(LocationControlCallbacks& controlCallbacks)
+{
+    struct MsgSetControlCallbacks : public LocMsg {
+        GnssAdapter& mAdapter;
+        const LocationControlCallbacks mControlCallbacks;
+        inline MsgSetControlCallbacks(GnssAdapter& adapter,
+                                      LocationControlCallbacks& controlCallbacks) :
+            LocMsg(),
+            mAdapter(adapter),
+            mControlCallbacks(controlCallbacks) {}
+        inline virtual void proc() const {
+            mAdapter.setControlCallbacks(mControlCallbacks);
+        }
+    };
+
+    sendMsg(new MsgSetControlCallbacks(*this, controlCallbacks));
+}
+
+void
+GnssAdapter::convertOptions(LocPosMode& out, const TrackingOptions& trackingOptions)
+{
+    switch (trackingOptions.mode) {
+    case GNSS_SUPL_MODE_MSB:
+        out.mode = LOC_POSITION_MODE_MS_BASED;
+        break;
+    case GNSS_SUPL_MODE_MSA:
+        out.mode = LOC_POSITION_MODE_MS_ASSISTED;
+        break;
+    default:
+        out.mode = LOC_POSITION_MODE_STANDALONE;
+        break;
+    }
+    out.share_position = true;
+    out.min_interval = trackingOptions.minInterval;
+    out.powerMode = trackingOptions.powerMode;
+    out.timeBetweenMeasurements = trackingOptions.tbm;
+}
+
+bool
+GnssAdapter::checkAndSetSPEToRunforNHz(TrackingOptions & out) {
+
+    // first check if NHz meas is needed at all, if not, just return false
+    // if a NHz capable engine is subscribed for NHz measurement or NHz positions,
+    // always run the SPE only session at 100ms TBF.
+    // If SPE session is already set to highest interval, no need to start it again.
+
+    bool isSPERunningAtHighestInterval = false;
+
+    if (!mNHzNeeded) {
+        LOC_LOGd("No nHz session needed.");
+    } else if (mSPEAlreadyRunningAtHighestInterval) {
+        LOC_LOGd("SPE is already running at highest interval.");
+        isSPERunningAtHighestInterval = true;
+    } else if (out.minInterval > MIN_TRACKING_INTERVAL) {
+        out.minInterval = MIN_TRACKING_INTERVAL;
+        LOC_LOGd("nHz session is needed, starting SPE only session at 100ms TBF.");
+        mSPEAlreadyRunningAtHighestInterval = true;
+    }
+
+    return isSPERunningAtHighestInterval;
+}
+
+
+void
+GnssAdapter::convertLocation(Location& out, const UlpLocation& ulpLocation,
+                             const GpsLocationExtended& locationExtended)
+{
+    memset(&out, 0, sizeof(Location));
+    out.size = sizeof(Location);
+    if (LOC_GPS_LOCATION_HAS_LAT_LONG & ulpLocation.gpsLocation.flags) {
+        out.flags |= LOCATION_HAS_LAT_LONG_BIT;
+        out.latitude = ulpLocation.gpsLocation.latitude;
+        out.longitude = ulpLocation.gpsLocation.longitude;
+    }
+    if (LOC_GPS_LOCATION_HAS_ALTITUDE & ulpLocation.gpsLocation.flags) {
+        out.flags |= LOCATION_HAS_ALTITUDE_BIT;
+        out.altitude = ulpLocation.gpsLocation.altitude;
+    }
+    if (LOC_GPS_LOCATION_HAS_SPEED & ulpLocation.gpsLocation.flags) {
+        out.flags |= LOCATION_HAS_SPEED_BIT;
+        out.speed = ulpLocation.gpsLocation.speed;
+    }
+    if (LOC_GPS_LOCATION_HAS_BEARING & ulpLocation.gpsLocation.flags) {
+        out.flags |= LOCATION_HAS_BEARING_BIT;
+        out.bearing = ulpLocation.gpsLocation.bearing;
+    }
+    if (LOC_GPS_LOCATION_HAS_ACCURACY & ulpLocation.gpsLocation.flags) {
+        out.flags |= LOCATION_HAS_ACCURACY_BIT;
+        out.accuracy = ulpLocation.gpsLocation.accuracy;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_VERT_UNC & locationExtended.flags) {
+        out.flags |= LOCATION_HAS_VERTICAL_ACCURACY_BIT;
+        out.verticalAccuracy = locationExtended.vert_unc;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_SPEED_UNC & locationExtended.flags) {
+        out.flags |= LOCATION_HAS_SPEED_ACCURACY_BIT;
+        out.speedAccuracy = locationExtended.speed_unc;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_BEARING_UNC & locationExtended.flags) {
+        out.flags |= LOCATION_HAS_BEARING_ACCURACY_BIT;
+        out.bearingAccuracy = locationExtended.bearing_unc;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_CONFORMITY_INDEX & locationExtended.flags) {
+        out.flags |= LOCATION_HAS_CONFORMITY_INDEX_BIT;
+        out.conformityIndex = locationExtended.conformityIndex;
+    }
+    out.timestamp = ulpLocation.gpsLocation.timestamp;
+    if (LOC_POS_TECH_MASK_SATELLITE & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_GNSS_BIT;
+    }
+    if (LOC_POS_TECH_MASK_CELLID & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_CELL_BIT;
+    }
+    if (LOC_POS_TECH_MASK_WIFI & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_WIFI_BIT;
+    }
+    if (LOC_POS_TECH_MASK_SENSORS & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_SENSORS_BIT;
+    }
+    if (LOC_POS_TECH_MASK_REFERENCE_LOCATION & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_REFERENCE_LOCATION_BIT;
+    }
+    if (LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_INJECTED_COARSE_POSITION_BIT;
+    }
+    if (LOC_POS_TECH_MASK_AFLT & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_AFLT_BIT;
+    }
+    if (LOC_POS_TECH_MASK_HYBRID & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_HYBRID_BIT;
+    }
+    if (LOC_POS_TECH_MASK_PPE & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_PPE_BIT;
+    }
+    if (LOC_POS_TECH_MASK_VEH & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_VEH_BIT;
+    }
+    if (LOC_POS_TECH_MASK_VIS & locationExtended.tech_mask) {
+        out.techMask |= LOCATION_TECHNOLOGY_VIS_BIT;
+    }
+    if (LOC_NAV_MASK_DGNSS_CORRECTION & locationExtended.navSolutionMask) {
+        out.techMask |= LOCATION_TECHNOLOGY_DGNSS_BIT;
+    }
+
+    if (LOC_GPS_LOCATION_HAS_SPOOF_MASK & ulpLocation.gpsLocation.flags) {
+        out.flags |= LOCATION_HAS_SPOOF_MASK;
+        out.spoofMask = ulpLocation.gpsLocation.spoof_mask;
+    }
+    if (LOC_GPS_LOCATION_HAS_ELAPSED_REAL_TIME & ulpLocation.gpsLocation.flags) {
+        out.flags |= LOCATION_HAS_ELAPSED_REAL_TIME;
+        out.elapsedRealTime = ulpLocation.gpsLocation.elapsedRealTime;
+        out.elapsedRealTimeUnc = ulpLocation.gpsLocation.elapsedRealTimeUnc;
+    }
+}
+
+/* This is utility routine that computes number of SV used
+   in the fix from the svUsedIdsMask.
+ */
+#define MAX_SV_CNT_SUPPORTED_IN_ONE_CONSTELLATION 64
+uint16_t GnssAdapter::getNumSvUsed(uint64_t svUsedIdsMask,
+                                   int totalSvCntInThisConstellation)
+{
+    if (totalSvCntInThisConstellation > MAX_SV_CNT_SUPPORTED_IN_ONE_CONSTELLATION) {
+        LOC_LOGe ("error: total SV count in this constellation %d exceeded limit of %d",
+                  totalSvCntInThisConstellation, MAX_SV_CNT_SUPPORTED_IN_ONE_CONSTELLATION);
+        return 0;
+    }
+
+    uint16_t numSvUsed = 0;
+    uint64_t mask = 0x1;
+    for (int i = 0; i < totalSvCntInThisConstellation; i++) {
+        if (svUsedIdsMask & mask) {
+            numSvUsed++;
+        }
+        mask <<= 1;
+    }
+
+    return numSvUsed;
+}
+
+void
+GnssAdapter::convertLocationInfo(GnssLocationInfoNotification& out,
+                                 const GpsLocationExtended& locationExtended,
+                                 enum loc_sess_status status)
+{
+    out.size = sizeof(GnssLocationInfoNotification);
+    if (GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_ALTITUDE_MEAN_SEA_LEVEL_BIT;
+        out.altitudeMeanSeaLevel = locationExtended.altitudeMeanSeaLevel;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_EXT_DOP & locationExtended.flags) {
+        out.flags |= (GNSS_LOCATION_INFO_DOP_BIT|GNSS_LOCATION_INFO_EXT_DOP_BIT);
+        out.pdop = locationExtended.extDOP.PDOP;
+        out.hdop = locationExtended.extDOP.HDOP;
+        out.vdop = locationExtended.extDOP.VDOP;
+        out.gdop = locationExtended.extDOP.GDOP;
+        out.tdop = locationExtended.extDOP.TDOP;
+    } else if (GPS_LOCATION_EXTENDED_HAS_DOP & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_DOP_BIT;
+        out.pdop = locationExtended.pdop;
+        out.hdop = locationExtended.hdop;
+        out.vdop = locationExtended.vdop;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_MAG_DEV & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_MAGNETIC_DEVIATION_BIT;
+        out.magneticDeviation = locationExtended.magneticDeviation;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_HOR_RELIABILITY & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_HOR_RELIABILITY_BIT;
+        switch (locationExtended.horizontal_reliability) {
+            case LOC_RELIABILITY_VERY_LOW:
+                out.horReliability = LOCATION_RELIABILITY_VERY_LOW;
+                break;
+            case LOC_RELIABILITY_LOW:
+                out.horReliability = LOCATION_RELIABILITY_LOW;
+                break;
+            case LOC_RELIABILITY_MEDIUM:
+                out.horReliability = LOCATION_RELIABILITY_MEDIUM;
+                break;
+            case LOC_RELIABILITY_HIGH:
+                out.horReliability = LOCATION_RELIABILITY_HIGH;
+                break;
+            default:
+                out.horReliability = LOCATION_RELIABILITY_NOT_SET;
+                break;
+        }
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_VERT_RELIABILITY & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_VER_RELIABILITY_BIT;
+        switch (locationExtended.vertical_reliability) {
+            case LOC_RELIABILITY_VERY_LOW:
+                out.verReliability = LOCATION_RELIABILITY_VERY_LOW;
+                break;
+            case LOC_RELIABILITY_LOW:
+                out.verReliability = LOCATION_RELIABILITY_LOW;
+                break;
+            case LOC_RELIABILITY_MEDIUM:
+                out.verReliability = LOCATION_RELIABILITY_MEDIUM;
+                break;
+            case LOC_RELIABILITY_HIGH:
+                out.verReliability = LOCATION_RELIABILITY_HIGH;
+                break;
+            default:
+                out.verReliability = LOCATION_RELIABILITY_NOT_SET;
+                break;
+        }
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MAJOR & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MAJOR_BIT;
+        out.horUncEllipseSemiMajor = locationExtended.horUncEllipseSemiMajor;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MINOR & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MINOR_BIT;
+        out.horUncEllipseSemiMinor = locationExtended.horUncEllipseSemiMinor;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_AZIMUTH & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_AZIMUTH_BIT;
+        out.horUncEllipseOrientAzimuth = locationExtended.horUncEllipseOrientAzimuth;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_NORTH_STD_DEV & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_NORTH_STD_DEV_BIT;
+        out.northStdDeviation = locationExtended.northStdDeviation;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_EAST_STD_DEV & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_EAST_STD_DEV_BIT;
+        out.eastStdDeviation = locationExtended.eastStdDeviation;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_NORTH_VEL & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_NORTH_VEL_BIT;
+        out.northVelocity = locationExtended.northVelocity;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_NORTH_VEL_UNC & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_NORTH_VEL_UNC_BIT;
+        out.northVelocityStdDeviation = locationExtended.northVelocityStdDeviation;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_EAST_VEL & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_EAST_VEL_BIT;
+        out.eastVelocity = locationExtended.eastVelocity;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_EAST_VEL_UNC & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_EAST_VEL_UNC_BIT;
+        out.eastVelocityStdDeviation = locationExtended.eastVelocityStdDeviation;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_UP_VEL & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_UP_VEL_BIT;
+        out.upVelocity = locationExtended.upVelocity;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_UP_VEL_UNC & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_UP_VEL_UNC_BIT;
+        out.upVelocityStdDeviation = locationExtended.upVelocityStdDeviation;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_GNSS_SV_USED_DATA_BIT;
+        out.svUsedInPosition.gpsSvUsedIdsMask =
+                locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask;
+        out.svUsedInPosition.gloSvUsedIdsMask =
+                locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask;
+        out.svUsedInPosition.galSvUsedIdsMask =
+                locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask;
+        out.svUsedInPosition.bdsSvUsedIdsMask =
+                locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask;
+        out.svUsedInPosition.qzssSvUsedIdsMask =
+                locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask;
+        out.svUsedInPosition.navicSvUsedIdsMask =
+                locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask;
+
+        out.flags |= GNSS_LOCATION_INFO_NUM_SV_USED_IN_POSITION_BIT;
+        out.numSvUsedInPosition = getNumSvUsed(out.svUsedInPosition.gpsSvUsedIdsMask,
+                                               GPS_SV_PRN_MAX - GPS_SV_PRN_MIN + 1);
+        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.gloSvUsedIdsMask,
+                                                GLO_SV_PRN_MAX - GLO_SV_PRN_MIN + 1);
+        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.qzssSvUsedIdsMask,
+                                                QZSS_SV_PRN_MAX - QZSS_SV_PRN_MIN + 1);
+        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.bdsSvUsedIdsMask,
+                                                BDS_SV_PRN_MAX - BDS_SV_PRN_MIN + 1);
+        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.galSvUsedIdsMask,
+                                                GAL_SV_PRN_MAX - GAL_SV_PRN_MIN + 1);
+        out.numSvUsedInPosition += getNumSvUsed(out.svUsedInPosition.navicSvUsedIdsMask,
+                                                NAVIC_SV_PRN_MAX - NAVIC_SV_PRN_MIN + 1);
+
+        out.numOfMeasReceived = locationExtended.numOfMeasReceived;
+        for (int idx =0; idx < locationExtended.numOfMeasReceived; idx++) {
+            out.measUsageInfo[idx].gnssSignalType =
+                    locationExtended.measUsageInfo[idx].gnssSignalType;
+            out.measUsageInfo[idx].gnssSvId =
+                    locationExtended.measUsageInfo[idx].gnssSvId;
+            out.measUsageInfo[idx].gnssConstellation =
+                    locationExtended.measUsageInfo[idx].gnssConstellation;
+        }
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_NAV_SOLUTION_MASK_BIT;
+        out.navSolutionMask = locationExtended.navSolutionMask;
+    }
+    if (GPS_LOCATION_EXTENDED_HAS_POS_DYNAMICS_DATA & locationExtended.flags) {
+        out.flags |= GPS_LOCATION_EXTENDED_HAS_POS_DYNAMICS_DATA;
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_LONG_ACCEL_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LONG_ACCEL_BIT;
+        }
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_LAT_ACCEL_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LAT_ACCEL_BIT;
+        }
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_VERT_ACCEL_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_VERT_ACCEL_BIT;
+        }
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_YAW_RATE_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_RATE_BIT;
+        }
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+            LOCATION_NAV_DATA_HAS_PITCH_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_BIT;
+        }
+
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_LONG_ACCEL_UNC_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LONG_ACCEL_UNC_BIT;
+        }
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_LAT_ACCEL_UNC_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_LAT_ACCEL_UNC_BIT;
+        }
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_VERT_ACCEL_UNC_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_VERT_ACCEL_UNC_BIT;
+        }
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_YAW_RATE_UNC_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_RATE_UNC_BIT;
+        }
+        if (locationExtended.bodyFrameData.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_PITCH_UNC_BIT) {
+            out.bodyFrameData.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_UNC_BIT;
+        }
+
+        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_PITCH_RATE_BIT) {
+            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_RATE_BIT;
+        }
+        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_PITCH_RATE_UNC_BIT) {
+            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_PITCH_RATE_UNC_BIT;
+        }
+        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_ROLL_BIT) {
+            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_BIT;
+        }
+        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_ROLL_UNC_BIT) {
+            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_UNC_BIT;
+        }
+        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_ROLL_RATE_BIT) {
+            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_RATE_BIT;
+        }
+        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_ROLL_RATE_UNC_BIT) {
+            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_ROLL_RATE_UNC_BIT;
+        }
+        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_YAW_BIT) {
+            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_BIT;
+        }
+        if (locationExtended.bodyFrameDataExt.bodyFrameDataMask &
+                LOCATION_NAV_DATA_HAS_YAW_UNC_BIT) {
+            out.bodyFrameDataExt.bodyFrameDataMask |= LOCATION_NAV_DATA_HAS_YAW_UNC_BIT;
+        }
+
+        out.bodyFrameData.longAccel = locationExtended.bodyFrameData.longAccel;
+        out.bodyFrameData.latAccel = locationExtended.bodyFrameData.latAccel;
+        out.bodyFrameData.vertAccel = locationExtended.bodyFrameData.vertAccel;
+        out.bodyFrameData.yawRate = locationExtended.bodyFrameData.yawRate;
+        out.bodyFrameData.pitch = locationExtended.bodyFrameData.pitch;
+        out.bodyFrameData.longAccelUnc = locationExtended.bodyFrameData.longAccelUnc;
+        out.bodyFrameData.latAccelUnc  = locationExtended.bodyFrameData.latAccelUnc;
+        out.bodyFrameData.vertAccelUnc = locationExtended.bodyFrameData.vertAccelUnc;
+        out.bodyFrameData.yawRateUnc   = locationExtended.bodyFrameData.yawRateUnc;
+        out.bodyFrameData.pitchUnc     = locationExtended.bodyFrameData.pitchUnc;
+
+        out.bodyFrameDataExt.pitchRate    = locationExtended.bodyFrameDataExt.pitchRate;
+        out.bodyFrameDataExt.pitchRateUnc = locationExtended.bodyFrameDataExt.pitchRateUnc;
+        out.bodyFrameDataExt.roll         = locationExtended.bodyFrameDataExt.roll;
+        out.bodyFrameDataExt.rollUnc      = locationExtended.bodyFrameDataExt.rollUnc;
+        out.bodyFrameDataExt.rollRate     = locationExtended.bodyFrameDataExt.rollRate;
+        out.bodyFrameDataExt.rollRateUnc  = locationExtended.bodyFrameDataExt.rollRateUnc;
+        out.bodyFrameDataExt.yaw          = locationExtended.bodyFrameDataExt.yaw;
+        out.bodyFrameDataExt.yawUnc       = locationExtended.bodyFrameDataExt.yawUnc;
+    }
+
+    // Validity of this structure is established from the timeSrc of the GnssSystemTime structure.
+    out.gnssSystemTime = locationExtended.gnssSystemTime;
+
+    if (GPS_LOCATION_EXTENDED_HAS_LEAP_SECONDS & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_LEAP_SECONDS_BIT;
+        out.leapSeconds = locationExtended.leapSeconds;
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_TIME_UNC & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_TIME_UNC_BIT;
+        out.timeUncMs = locationExtended.timeUncMs;
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_CALIBRATION_CONFIDENCE & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_CALIBRATION_CONFIDENCE_BIT;
+        out.calibrationConfidence = locationExtended.calibrationConfidence;
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_CALIBRATION_STATUS & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_CALIBRATION_STATUS_BIT;
+        out.calibrationStatus = locationExtended.calibrationStatus;
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT;
+        out.locOutputEngType = locationExtended.locOutputEngType;
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_MASK & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_OUTPUT_ENG_MASK_BIT;
+        out.locOutputEngMask = locationExtended.locOutputEngMask;
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_CONFORMITY_INDEX & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_CONFORMITY_INDEX_BIT;
+        out.conformityIndex = locationExtended.conformityIndex;
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_LLA_VRP_BASED & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_LLA_VRP_BASED_BIT;
+        out.llaVRPBased = locationExtended.llaVRPBased;
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_ENU_VELOCITY_LLA_VRP_BASED & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_ENU_VELOCITY_VRP_BASED_BIT;
+        // copy over east, north and up vrp based velocity
+        out.enuVelocityVRPBased[0] = locationExtended.enuVelocityVRPBased[0];
+        out.enuVelocityVRPBased[1] = locationExtended.enuVelocityVRPBased[1];
+        out.enuVelocityVRPBased[2] = locationExtended.enuVelocityVRPBased[2];
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_DR_SOLUTION_STATUS_MASK & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_DR_SOLUTION_STATUS_MASK_BIT;
+        out.drSolutionStatusMask = locationExtended.drSolutionStatusMask;
+    }
+
+    if (GPS_LOCATION_EXTENDED_HAS_ALTITUDE_ASSUMED & locationExtended.flags) {
+        out.flags |= GNSS_LOCATION_INFO_ALTITUDE_ASSUMED_BIT;
+        out.altitudeAssumed = locationExtended.altitudeAssumed;
+    }
+
+    out.flags |= GNSS_LOCATION_INFO_SESSION_STATUS_BIT;
+    out.sessionStatus = status;
+}
+
+inline uint32_t
+GnssAdapter::convertSuplVersion(const GnssConfigSuplVersion suplVersion)
+{
+    switch (suplVersion) {
+        case GNSS_CONFIG_SUPL_VERSION_2_0_4:
+            return 0x00020004;
+        case GNSS_CONFIG_SUPL_VERSION_2_0_0:
+            return 0x00020000;
+        case GNSS_CONFIG_SUPL_VERSION_2_0_2:
+            return 0x00020002;
+        case GNSS_CONFIG_SUPL_VERSION_1_0_0:
+        default:
+            return 0x00010000;
+    }
+}
+
+uint32_t
+GnssAdapter::convertLppeCp(const GnssConfigLppeControlPlaneMask lppeControlPlaneMask)
+{
+    uint32_t mask = 0;
+    if (GNSS_CONFIG_LPPE_CONTROL_PLANE_DBH_BIT & lppeControlPlaneMask) {
+        mask |= (1<<0);
+    }
+    if (GNSS_CONFIG_LPPE_CONTROL_PLANE_WLAN_AP_MEASUREMENTS_BIT & lppeControlPlaneMask) {
+        mask |= (1<<1);
+    }
+    if (GNSS_CONFIG_LPPE_CONTROL_PLANE_SRN_AP_MEASUREMENTS_BIT & lppeControlPlaneMask) {
+        mask |= (1<<2);
+    }
+    if (GNSS_CONFIG_LPPE_CONTROL_PLANE_SENSOR_BARO_MEASUREMENTS_BIT & lppeControlPlaneMask) {
+        mask |= (1<<3);
+    }
+    return mask;
+}
+
+uint32_t
+GnssAdapter::convertLppeUp(const GnssConfigLppeUserPlaneMask lppeUserPlaneMask)
+{
+    uint32_t mask = 0;
+    if (GNSS_CONFIG_LPPE_USER_PLANE_DBH_BIT & lppeUserPlaneMask) {
+        mask |= (1<<0);
+    }
+    if (GNSS_CONFIG_LPPE_USER_PLANE_WLAN_AP_MEASUREMENTS_BIT & lppeUserPlaneMask) {
+        mask |= (1<<1);
+    }
+    if (GNSS_CONFIG_LPPE_USER_PLANE_SRN_AP_MEASUREMENTS_BIT & lppeUserPlaneMask) {
+        mask |= (1<<2);
+    }
+    if (GNSS_CONFIG_LPPE_USER_PLANE_SENSOR_BARO_MEASUREMENTS_BIT & lppeUserPlaneMask) {
+        mask |= (1<<3);
+    }
+    return mask;
+}
+
+uint32_t
+GnssAdapter::convertAGloProt(const GnssConfigAGlonassPositionProtocolMask aGloPositionProtocolMask)
+{
+    uint32_t mask = 0;
+    if (GNSS_CONFIG_RRC_CONTROL_PLANE_BIT & aGloPositionProtocolMask) {
+        mask |= (1<<0);
+    }
+    if (GNSS_CONFIG_RRLP_USER_PLANE_BIT & aGloPositionProtocolMask) {
+        mask |= (1<<1);
+    }
+    if (GNSS_CONFIG_LLP_USER_PLANE_BIT & aGloPositionProtocolMask) {
+        mask |= (1<<2);
+    }
+    if (GNSS_CONFIG_LLP_CONTROL_PLANE_BIT & aGloPositionProtocolMask) {
+        mask |= (1<<3);
+    }
+    return mask;
+}
+
+uint32_t
+GnssAdapter::convertEP4ES(const GnssConfigEmergencyPdnForEmergencySupl emergencyPdnForEmergencySupl)
+{
+    switch (emergencyPdnForEmergencySupl) {
+       case GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES:
+           return 1;
+       case GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO:
+       default:
+           return 0;
+    }
+}
+
+uint32_t
+GnssAdapter::convertSuplEs(const GnssConfigSuplEmergencyServices suplEmergencyServices)
+{
+    switch (suplEmergencyServices) {
+       case GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_YES:
+           return 1;
+       case GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO:
+       default:
+           return 0;
+    }
+}
+
+uint32_t
+GnssAdapter::convertSuplMode(const GnssConfigSuplModeMask suplModeMask)
+{
+    uint32_t mask = 0;
+    if (GNSS_CONFIG_SUPL_MODE_MSB_BIT & suplModeMask) {
+        mask |= (1<<0);
+    }
+    if (GNSS_CONFIG_SUPL_MODE_MSA_BIT & suplModeMask) {
+        mask |= (1<<1);
+    }
+    return mask;
+}
+
+void
+GnssAdapter::readConfigCommand()
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    struct MsgReadConfig : public LocMsg {
+        GnssAdapter* mAdapter;
+        ContextBase& mContext;
+        inline MsgReadConfig(GnssAdapter* adapter,
+                             ContextBase& context) :
+            LocMsg(),
+            mAdapter(adapter),
+            mContext(context) {}
+        inline virtual void proc() const {
+            static bool confReadDone = false;
+            if (!confReadDone) {
+                confReadDone = true;
+                // reads config into mContext->mGps_conf
+                mContext.readConfig();
+
+                uint32_t allowFlpNetworkFixes = 0;
+                static const loc_param_s_type flp_conf_param_table[] =
+                {
+                    {"ALLOW_NETWORK_FIXES", &allowFlpNetworkFixes, NULL, 'n'},
+                };
+                UTIL_READ_CONF(LOC_PATH_FLP_CONF, flp_conf_param_table);
+                LOC_LOGd("allowFlpNetworkFixes %u", allowFlpNetworkFixes);
+                mAdapter->setAllowFlpNetworkFixes(allowFlpNetworkFixes);
+            }
+        }
+    };
+
+    if (mContext != NULL) {
+        sendMsg(new MsgReadConfig(this, *mContext));
+    }
+}
+
+void
+GnssAdapter::setSuplHostServer(const char* server, int port, LocServerType type)
+{
+    if (ContextBase::mGps_conf.AGPS_CONFIG_INJECT) {
+        char serverUrl[MAX_URL_LEN] = {};
+        int32_t length = -1;
+        const char noHost[] = "NONE";
+
+        if ((NULL == server) || (server[0] == 0) ||
+                (strncasecmp(noHost, server, sizeof(noHost)) == 0)) {
+            serverUrl[0] = '\0';
+            length = 0;
+        } else if (port > 0) {
+            length = snprintf(serverUrl, sizeof(serverUrl), "%s:%u", server, port);
+        }
+        if (LOC_AGPS_SUPL_SERVER != type && LOC_AGPS_MO_SUPL_SERVER != type) {
+            LOC_LOGe("Invalid type=%d", type);
+        } else if (length >= 0) {
+            if (LOC_AGPS_SUPL_SERVER == type) {
+                getServerUrl().assign(serverUrl);
+                strlcpy(ContextBase::mGps_conf.SUPL_HOST,
+                        (nullptr == server) ? serverUrl : server,
+                        LOC_MAX_PARAM_STRING);
+                ContextBase::mGps_conf.SUPL_PORT = port;
+            } else {
+                if (strncasecmp(getMoServerUrl().c_str(), serverUrl, sizeof(serverUrl)) != 0) {
+                    getMoServerUrl().assign(serverUrl);
+                }
+            }
+        }
+    }
+}
+
+void
+GnssAdapter::setConfig()
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    // set nmea mask type
+    uint32_t mask = 0;
+    if (NMEA_PROVIDER_MP == ContextBase::mGps_conf.NMEA_PROVIDER) {
+        mask |= LOC_NMEA_ALL_GENERAL_SUPPORTED_MASK;
+        if (ContextBase::mGps_conf.NMEA_TAG_BLOCK_GROUPING_ENABLED) {
+            mask |= LOC_NMEA_MASK_TAGBLOCK_V02;
+        }
+    }
+    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) {
+        mask |= LOC_NMEA_MASK_DEBUG_V02;
+    }
+    if (mNmeaMask != mask) {
+        mNmeaMask = mask;
+        if (mNmeaMask) {
+            for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+                if ((it->second.gnssNmeaCb != nullptr)) {
+                    updateEvtMask(LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT,
+                                  LOC_REGISTRATION_MASK_ENABLED);
+                    break;
+                }
+            }
+        }
+    }
+
+    std::string oldMoServerUrl = getMoServerUrl();
+    setSuplHostServer(ContextBase::mGps_conf.SUPL_HOST,
+                      ContextBase::mGps_conf.SUPL_PORT,
+                      LOC_AGPS_SUPL_SERVER);
+    setSuplHostServer(ContextBase::mGps_conf.MO_SUPL_HOST,
+                      ContextBase::mGps_conf.MO_SUPL_PORT,
+                      LOC_AGPS_MO_SUPL_SERVER);
+
+    std::string moServerUrl = getMoServerUrl();
+    std::string serverUrl = getServerUrl();
+    // inject the configurations into modem
+    loc_gps_cfg_s gpsConf = ContextBase::mGps_conf;
+    loc_sap_cfg_s_type sapConf = ContextBase::mSap_conf;
+
+    //cache the injected configuration with GnssConfigRequested struct
+    GnssConfig gnssConfigRequested = {};
+    gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT |
+            GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+    /* Here we process an SSR. We need to set the GPS_LOCK to the proper values, as follows:
+    1. Q behavior. This is identified by mSupportNfwControl being 1. In this case
+    ContextBase::mGps_conf.GPS_LOCK is a "state", meaning it should reflect the
+    NV value. Therefore we will set the NV to ContextBase::mGps_conf.GPS_LOCK
+    2. P behavior. This is identified by mSupportNfwControl being 0. In this case
+    ContextBase::mGps_conf.GPS_LOCK is a "configuration", meaning it should hold
+    the "mask" for NI. There are two subcases:
+    a. Location enabled in GUI (1 == getAfwControlId()). We need to set
+    the NV to GNSS_CONFIG_GPS_LOCK_NONE (both MO and NI enabled)
+    b. Location disabled in GUI (0 == getAfwControlId()). We need to set
+    the NV to ContextBase::mGps_conf.GPS_LOCK (the "mask", which is SIM-card
+    specific)
+    */
+    if (mSupportNfwControl || (0 == getAfwControlId())) {
+        gnssConfigRequested.gpsLock = gpsConf.GPS_LOCK;
+    } else {
+        gnssConfigRequested.gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+    }
+    gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT |
+            GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT |
+            GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT |
+            GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT;
+    gnssConfigRequested.suplVersion = mLocApi->convertSuplVersion(gpsConf.SUPL_VER);
+    gnssConfigRequested.lppProfileMask = gpsConf.LPP_PROFILE;
+    gnssConfigRequested.aGlonassPositionProtocolMask = gpsConf.A_GLONASS_POS_PROTOCOL_SELECT;
+    if (gpsConf.LPPE_CP_TECHNOLOGY) {
+        gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT;
+        gnssConfigRequested.lppeControlPlaneMask =
+                mLocApi->convertLppeCp(gpsConf.LPPE_CP_TECHNOLOGY);
+    }
+
+    if (gpsConf.LPPE_UP_TECHNOLOGY) {
+        gnssConfigRequested.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT;
+        gnssConfigRequested.lppeUserPlaneMask =
+                mLocApi->convertLppeUp(gpsConf.LPPE_UP_TECHNOLOGY);
+    }
+    gnssConfigRequested.blacklistedSvIds.assign(mBlacklistedSvIds.begin(),
+                                                mBlacklistedSvIds.end());
+    mLocApi->sendMsg(new LocApiMsg(
+            [this, gpsConf, sapConf, oldMoServerUrl, moServerUrl,
+            serverUrl, gnssConfigRequested] () mutable {
+        gnssUpdateConfig(oldMoServerUrl, moServerUrl, serverUrl,
+                gnssConfigRequested, gnssConfigRequested);
+
+        // set nmea mask type
+        uint32_t mask = 0;
+        if (NMEA_PROVIDER_MP == gpsConf.NMEA_PROVIDER) {
+            mask |= LOC_NMEA_ALL_GENERAL_SUPPORTED_MASK;
+            if (gpsConf.NMEA_TAG_BLOCK_GROUPING_ENABLED) {
+                mask |= LOC_NMEA_MASK_TAGBLOCK_V02;
+            }
+        }
+        if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) {
+            mask |= LOC_NMEA_MASK_DEBUG_V02;
+        }
+
+        if (mask != 0) {
+            mLocApi->setNMEATypesSync(mask);
+        }
+
+        // load tunc configuration from config file on first boot-up,
+        // e.g.: adapter.mLocConfigInfo.tuncConfigInfo.isValid is false
+        if (mLocConfigInfo.tuncConfigInfo.isValid == false) {
+            mLocConfigInfo.tuncConfigInfo.isValid = true;
+            mLocConfigInfo.tuncConfigInfo.enable =
+                    (gpsConf.CONSTRAINED_TIME_UNCERTAINTY_ENABLED == 1);
+            mLocConfigInfo.tuncConfigInfo.tuncThresholdMs =
+                   (float)gpsConf.CONSTRAINED_TIME_UNCERTAINTY_THRESHOLD;
+            mLocConfigInfo.tuncConfigInfo.energyBudget =
+                   gpsConf.CONSTRAINED_TIME_UNCERTAINTY_ENERGY_BUDGET;
+        }
+
+        mLocApi->setConstrainedTuncMode(
+                mLocConfigInfo.tuncConfigInfo.enable,
+                mLocConfigInfo.tuncConfigInfo.tuncThresholdMs,
+                mLocConfigInfo.tuncConfigInfo.energyBudget);
+
+        // load pace configuration from config file on first boot-up,
+        // e.g.: adapter.mLocConfigInfo.paceConfigInfo.isValid is false
+        if (mLocConfigInfo.paceConfigInfo.isValid == false) {
+            mLocConfigInfo.paceConfigInfo.isValid = true;
+            mLocConfigInfo.paceConfigInfo.enable =
+                    (gpsConf.POSITION_ASSISTED_CLOCK_ESTIMATOR_ENABLED==1);
+        }
+        mLocApi->setPositionAssistedClockEstimatorMode(
+                mLocConfigInfo.paceConfigInfo.enable);
+
+        // we do not support control robust location from gps.conf
+        if (mLocConfigInfo.robustLocationConfigInfo.isValid == true) {
+            mLocApi->configRobustLocation(
+                    mLocConfigInfo.robustLocationConfigInfo.enable,
+                    mLocConfigInfo.robustLocationConfigInfo.enableFor911);
+        }
+
+        if (sapConf.GYRO_BIAS_RANDOM_WALK_VALID ||
+            sapConf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID ||
+            sapConf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID ||
+            sapConf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID ||
+            sapConf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID ) {
+            mLocApi->setSensorPropertiesSync(
+                sapConf.GYRO_BIAS_RANDOM_WALK_VALID,
+                sapConf.GYRO_BIAS_RANDOM_WALK,
+                sapConf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY_VALID,
+                sapConf.ACCEL_RANDOM_WALK_SPECTRAL_DENSITY,
+                sapConf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY_VALID,
+                sapConf.ANGLE_RANDOM_WALK_SPECTRAL_DENSITY,
+                sapConf.RATE_RANDOM_WALK_SPECTRAL_DENSITY_VALID,
+                sapConf.RATE_RANDOM_WALK_SPECTRAL_DENSITY,
+                sapConf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY_VALID,
+                sapConf.VELOCITY_RANDOM_WALK_SPECTRAL_DENSITY);
+        }
+        mLocApi->setSensorPerfControlConfigSync(
+                sapConf.SENSOR_CONTROL_MODE,
+                sapConf.SENSOR_ACCEL_SAMPLES_PER_BATCH,
+                sapConf.SENSOR_ACCEL_BATCHES_PER_SEC,
+                sapConf.SENSOR_GYRO_SAMPLES_PER_BATCH,
+                sapConf.SENSOR_GYRO_BATCHES_PER_SEC,
+                sapConf.SENSOR_ACCEL_SAMPLES_PER_BATCH_HIGH,
+                sapConf.SENSOR_ACCEL_BATCHES_PER_SEC_HIGH,
+                sapConf.SENSOR_GYRO_SAMPLES_PER_BATCH_HIGH,
+                sapConf.SENSOR_GYRO_BATCHES_PER_SEC_HIGH,
+                sapConf.SENSOR_ALGORITHM_CONFIG_MASK);
+    } ));
+    // deal with Measurement Corrections
+    if (true == mIsMeasCorrInterfaceOpen) {
+        initMeasCorr(true);
+    }
+}
+
+std::vector<LocationError> GnssAdapter::gnssUpdateConfig(const std::string& oldMoServerUrl,
+        const std::string& moServerUrl, const std::string& serverUrl,
+        GnssConfig& gnssConfigRequested, GnssConfig& gnssConfigNeedEngineUpdate, size_t count) {
+    loc_gps_cfg_s gpsConf = ContextBase::mGps_conf;
+    size_t index = 0;
+    LocationError err = LOCATION_ERROR_SUCCESS;
+    std::vector<LocationError> errsList = {err};
+    if (count > 0) {
+        errsList.insert(errsList.begin(), count, LOCATION_ERROR_SUCCESS);
+    }
+
+    int serverUrlLen = serverUrl.length();
+    int moServerUrlLen = moServerUrl.length();
+
+    if (!ContextBase::mGps_conf.AGPS_CONFIG_INJECT) {
+        LOC_LOGd("AGPS_CONFIG_INJECT is 0. Not setting flags for AGPS configurations");
+        gnssConfigRequested.flags &= ~(GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT |
+                GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT |
+                GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT |
+                GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT);
+    }
+
+    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+        if (gnssConfigNeedEngineUpdate.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+            err = mLocApi->setGpsLockSync(gnssConfigRequested.gpsLock);
+            if (index < count) {
+                errsList[index] = err;
+            }
+        }
+        index++;
+    }
+
+    if (gnssConfigRequested.flags &
+            GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+        if (gnssConfigNeedEngineUpdate.flags &
+                GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+            if (gnssConfigNeedEngineUpdate.assistanceServer.type ==
+                    GNSS_ASSISTANCE_TYPE_SUPL) {
+                err = mLocApi->setServerSync(
+                        serverUrl.c_str(), serverUrlLen, LOC_AGPS_SUPL_SERVER);
+                if (index < count) {
+                    errsList[index] = err;
+                }
+                if (0 != oldMoServerUrl.compare(moServerUrl)) {
+                    LocationError locErr =
+                        mLocApi->setServerSync(moServerUrl.c_str(),
+                                moServerUrlLen,
+                                LOC_AGPS_MO_SUPL_SERVER);
+                    if (locErr != LOCATION_ERROR_SUCCESS) {
+                        LOC_LOGe("Error while setting MO SUPL_HOST server:%s",
+                                moServerUrl.c_str());
+                    }
+                }
+            } else if (gnssConfigNeedEngineUpdate.assistanceServer.type ==
+                    GNSS_ASSISTANCE_TYPE_C2K) {
+                struct in_addr addr;
+                struct hostent* hp;
+                bool resolveAddrSuccess = true;
+
+                hp = gethostbyname(
+                        gnssConfigNeedEngineUpdate.assistanceServer.hostName);
+                if (hp != NULL) { /* DNS OK */
+                    memcpy(&addr, hp->h_addr_list[0], hp->h_length);
+                } else {
+                    /* Try IP representation */
+                    if (inet_aton(
+                                gnssConfigNeedEngineUpdate.assistanceServer.hostName,
+                                &addr) == 0) {
+                        /* IP not valid */
+                        LOC_LOGE("%s]: hostname '%s' cannot be resolved ",
+                                __func__,
+                                gnssConfigNeedEngineUpdate.assistanceServer.hostName);
+                        if (index < count) {
+                            errsList[index] = LOCATION_ERROR_INVALID_PARAMETER;
+                        }
+                    } else {
+                        resolveAddrSuccess = false;
+                    }
+                }
+
+                if (resolveAddrSuccess) {
+                    unsigned int ip = htonl(addr.s_addr);
+                    err = mLocApi->setServerSync(ip,
+                            gnssConfigNeedEngineUpdate.assistanceServer.port,
+                            LOC_AGPS_CDMA_PDE_SERVER);
+                    if (index < count) {
+                        errsList[index] = err;
+                    }
+                }
+            }
+        }
+        index++;
+    }
+
+    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+        if (gnssConfigNeedEngineUpdate.flags &
+                GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+            err = mLocApi->setSUPLVersionSync(gnssConfigRequested.suplVersion);
+            if (index < count) {
+                errsList[index] = err;
+            }
+        }
+        index++;
+    }
+
+    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+        if (gnssConfigNeedEngineUpdate.flags &
+                GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+            err = mLocApi->setLPPConfigSync(gnssConfigRequested.lppProfileMask);
+            if (index < count) {
+                errsList[index] = err;
+            }
+        }
+        index++;
+    }
+
+    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+        if (gnssConfigNeedEngineUpdate.flags &
+                GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+            err = mLocApi->setLPPeProtocolCpSync(
+                    gnssConfigRequested.lppeControlPlaneMask);
+            if (index < count) {
+                errsList[index] = err;
+            }
+        }
+        index++;
+    }
+
+    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+        if (gnssConfigNeedEngineUpdate.flags &
+                GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+            err = mLocApi->setLPPeProtocolUpSync(
+                    gnssConfigRequested.lppeUserPlaneMask);
+            if (index < count) {
+                errsList[index] = err;
+            }
+        }
+        index++;
+    }
+
+    if (gnssConfigRequested.flags &
+            GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+        if (gnssConfigNeedEngineUpdate.flags &
+                GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+            err = mLocApi->setAGLONASSProtocolSync(
+                    gnssConfigRequested.aGlonassPositionProtocolMask);
+            if (index < count) {
+                errsList[index] = err;
+            }
+        }
+        index++;
+    }
+    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) {
+        // Check if feature is supported
+        if (!ContextBase::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
+            mBlacklistedSvIds.assign(gnssConfigRequested.blacklistedSvIds.begin(),
+                    gnssConfigRequested.blacklistedSvIds.end());
+            err = gnssSvIdConfigUpdateSync(gnssConfigRequested.blacklistedSvIds);
+            if (LOCATION_ERROR_SUCCESS != err) {
+                LOC_LOGe("Failed to send config to modem, err %d", err);
+            }
+        }
+        if (index < count) {
+            errsList[index] = err;
+        }
+        index++;
+    }
+    if (gnssConfigRequested.flags &
+            GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) {
+        if (gnssConfigNeedEngineUpdate.flags &
+                GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) {
+            err = mLocApi->setEmergencyExtensionWindowSync(
+                    gnssConfigRequested.emergencyExtensionSeconds);
+            if (index < count) {
+                errsList[index] = err;
+            }
+        }
+        index++;
+    }
+
+    if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT) {
+        GnssConfig gnssConfig = {};
+        gnssConfig.flags = GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT;
+        gnssConfig.minSvElevation = gnssConfigRequested.minSvElevation;
+        err = mLocApi->setParameterSync(gnssConfig);
+        if (index < count) {
+            errsList[index] = err;
+        }
+        index++;
+    }
+
+    return errsList;
+}
+
+uint32_t*
+GnssAdapter::gnssUpdateConfigCommand(const GnssConfig& config)
+{
+    // count the number of bits set
+    GnssConfigFlagsMask flagsCopy = config.flags;
+    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 (ids == nullptr) {
+            LOC_LOGE("%s] new allocation failed, fatal error.", __func__);
+            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("%s]: ids %s flags 0x%X", __func__, idsString.c_str(), config.flags);
+
+    struct MsgGnssUpdateConfig : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        GnssConfig mConfig;
+        size_t mCount;
+        uint32_t* mIds;
+        inline MsgGnssUpdateConfig(GnssAdapter& adapter,
+                                   LocApiBase& api,
+                                   GnssConfig config,
+                                   uint32_t* ids,
+                                   size_t count) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mConfig(config),
+            mCount(count),
+            mIds(nullptr) {
+                if (mCount > 0) {
+                    mIds = new uint32_t[count];
+                    if (mIds) {
+                        for (uint32_t index = 0; index < count; index++) {
+                            mIds[index] = ids[index];
+                        }
+                    } else {
+                        LOC_LOGe("memory allocation for mIds failed");
+                    }
+                }
+        }
+
+        inline MsgGnssUpdateConfig(const MsgGnssUpdateConfig& obj) :
+                MsgGnssUpdateConfig(obj.mAdapter, obj.mApi, obj.mConfig,
+                        obj.mIds, obj.mCount) {}
+
+        inline virtual ~MsgGnssUpdateConfig()
+        {
+            if (nullptr != mIds) delete[] mIds;
+        }
+
+        inline virtual void proc() const {
+            if (!mAdapter.isEngineCapabilitiesKnown()) {
+                mAdapter.mPendingMsgs.push_back(new MsgGnssUpdateConfig(*this));
+                return;
+            }
+            GnssAdapter& adapter = mAdapter;
+            size_t countOfConfigs = mCount;
+            GnssConfig gnssConfigRequested = mConfig;
+            GnssConfig gnssConfigNeedEngineUpdate = mConfig;
+
+            std::vector<uint32_t> sessionIds;
+            sessionIds.assign(mIds, mIds + mCount);
+            std::vector<LocationError> errs(mCount, LOCATION_ERROR_SUCCESS);
+            int index = 0;
+            bool needSuspendResume = false;
+
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) {
+                GnssConfigGpsLock newGpsLock = gnssConfigRequested.gpsLock;
+
+                newGpsLock |= GNSS_CONFIG_GPS_LOCK_MO;
+                ContextBase::mGps_conf.GPS_LOCK = newGpsLock;
+                /* If we get here it means that the changes in the framework to request for
+                   'P' behavior were made, and therefore we need to "behave" as in 'P'
+                However, we need to determine if enableCommand function has already been
+                called, since it could get called before this function.*/
+                if (0 != mAdapter.getAfwControlId()) {
+                    /* enableCommand function has already been called since getAfwControlId
+                    returns non zero. Now there are two possible cases:
+                    1. This is the first time this function is called
+                       (mSupportNfwControl is true). We need to behave as in 'P', but
+                       for the first time, meaning MO was enabled, but NI was not, so
+                       we need to unlock NI
+                    2. This is not the first time this function is called, meaning we
+                       are already behaving as in 'P'. No need to update the configuration
+                       in this case (return to 'P' code) */
+                    if (mAdapter.mSupportNfwControl) {
+                        // case 1 above
+                        newGpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+                    } else {
+                        // case 2 above
+                        gnssConfigNeedEngineUpdate.flags &= ~(GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT);
+                    }
+                }
+                gnssConfigRequested.gpsLock = newGpsLock;
+                mAdapter.mSupportNfwControl = false;
+                index++;
+            }
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) {
+                uint32_t newSuplVersion =
+                        mAdapter.convertSuplVersion(gnssConfigRequested.suplVersion);
+                ContextBase::mGps_conf.SUPL_VER = newSuplVersion;
+                index++;
+            }
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) {
+                if (GNSS_ASSISTANCE_TYPE_SUPL == mConfig.assistanceServer.type) {
+                    mAdapter.setSuplHostServer(mConfig.assistanceServer.hostName,
+                                                     mConfig.assistanceServer.port,
+                                                     LOC_AGPS_SUPL_SERVER);
+                } else {
+                    LOC_LOGE("%s]: Not a valid gnss assistance type %u",
+                            __func__, mConfig.assistanceServer.type);
+                    errs.at(index) = LOCATION_ERROR_INVALID_PARAMETER;
+                    gnssConfigNeedEngineUpdate.flags &=
+                            ~(GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT);
+                }
+                index++;
+            }
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) {
+                uint32_t newLppProfileMask = gnssConfigRequested.lppProfileMask;
+                ContextBase::mGps_conf.LPP_PROFILE = newLppProfileMask;
+                index++;
+            }
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) {
+                uint32_t newLppeControlPlaneMask =
+                        mAdapter.convertLppeCp(gnssConfigRequested.lppeControlPlaneMask);
+                ContextBase::mGps_conf.LPPE_CP_TECHNOLOGY = newLppeControlPlaneMask;
+                index++;
+            }
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) {
+                uint32_t newLppeUserPlaneMask =
+                        mAdapter.convertLppeUp(gnssConfigRequested.lppeUserPlaneMask);
+                ContextBase::mGps_conf.LPPE_UP_TECHNOLOGY = newLppeUserPlaneMask;
+                index++;
+            }
+            if (gnssConfigRequested.flags &
+                    GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) {
+                uint32_t newAGloProtMask =
+                        mAdapter.convertAGloProt(gnssConfigRequested.aGlonassPositionProtocolMask);
+                ContextBase::mGps_conf.A_GLONASS_POS_PROTOCOL_SELECT = newAGloProtMask;
+                index++;
+            }
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) {
+                uint32_t newEP4ES = mAdapter.convertEP4ES(
+                        gnssConfigRequested.emergencyPdnForEmergencySupl);
+                if (newEP4ES != ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL) {
+                    ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL = newEP4ES;
+                }
+                index++;
+            }
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) {
+                uint32_t newSuplEs = mAdapter.convertSuplEs(
+                        gnssConfigRequested.suplEmergencyServices);
+                if (newSuplEs != ContextBase::mGps_conf.SUPL_ES) {
+                    ContextBase::mGps_conf.SUPL_ES = newSuplEs;
+                }
+                index++;
+            }
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) {
+                uint32_t newSuplMode = mAdapter.convertSuplMode(gnssConfigRequested.suplModeMask);
+                ContextBase::mGps_conf.SUPL_MODE = newSuplMode;
+                mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+                index++;
+            }
+
+            if (gnssConfigRequested.flags & GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT) {
+                needSuspendResume = true;
+                index++;
+            }
+
+            if (needSuspendResume == true) {
+                mAdapter.suspendSessions();
+            }
+            LocApiCollectiveResponse *configCollectiveResponse = new LocApiCollectiveResponse(
+                    *adapter.getContext(),
+                    [&adapter, sessionIds, countOfConfigs] (std::vector<LocationError> errs) {
+
+                    std::vector<uint32_t> ids(sessionIds);
+                    adapter.reportResponse(countOfConfigs, errs.data(), ids.data());
+            });
+
+            std::string moServerUrl = adapter.getMoServerUrl();
+            std::string serverUrl = adapter.getServerUrl();
+            mApi.sendMsg(new LocApiMsg(
+                    [&adapter, gnssConfigRequested, gnssConfigNeedEngineUpdate,
+                    moServerUrl, serverUrl, countOfConfigs, configCollectiveResponse,
+                    errs] () mutable {
+                std::vector<LocationError> errsList = adapter.gnssUpdateConfig("",
+                        moServerUrl, serverUrl,
+                        gnssConfigRequested, gnssConfigNeedEngineUpdate, countOfConfigs);
+
+                configCollectiveResponse->returnToSender(errsList);
+            }));
+
+            if (needSuspendResume == true) {
+                mAdapter.restartSessions();
+            }
+        }
+    };
+
+    if (NULL != ids) {
+        sendMsg(new MsgGnssUpdateConfig(*this, *mLocApi, config, ids, count));
+    } else {
+        LOC_LOGE("%s]: No GNSS config items to update", __func__);
+    }
+
+    return ids;
+}
+
+void
+GnssAdapter::gnssSvIdConfigUpdate(const std::vector<GnssSvIdSource>& blacklistedSvIds)
+{
+    // Clear the existing config
+    memset(&mGnssSvIdConfig, 0, sizeof(GnssSvIdConfig));
+
+    // Convert the sv id lists to masks
+    bool convertSuccess = convertToGnssSvIdConfig(blacklistedSvIds, mGnssSvIdConfig);
+
+    // Now send to Modem if conversion successful
+    if (convertSuccess) {
+        gnssSvIdConfigUpdate();
+    } else {
+        LOC_LOGe("convertToGnssSvIdConfig failed");
+    }
+}
+
+void
+GnssAdapter::gnssSvIdConfigUpdate()
+{
+    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64,
+            mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+            mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask,
+            mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask);
+    // Now set required blacklisted SVs
+    mLocApi->setBlacklistSv(mGnssSvIdConfig);
+}
+
+LocationError
+GnssAdapter::gnssSvIdConfigUpdateSync(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 gnssSvIdConfigUpdateSync();
+}
+
+LocationError
+GnssAdapter::gnssSvIdConfigUpdateSync()
+{
+    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64,
+            mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+            mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask,
+            mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask);
+
+    // Now set required blacklisted SVs
+    return mLocApi->setBlacklistSvSync(mGnssSvIdConfig);
+}
+
+void
+GnssAdapter::gnssSecondaryBandConfigUpdate(LocApiResponse* locApiResponse)
+{
+    LOC_LOGd("secondary band config, size %d, enabled constellation 0x%" PRIx64 ","
+             "disabled constellation 0x%" PRIx64 "", mGnssSeconaryBandConfig.size,
+             mGnssSeconaryBandConfig.enabledSvTypesMask,
+             mGnssSeconaryBandConfig.blacklistedSvTypesMask);
+    if (mGnssSeconaryBandConfig.size == sizeof(mGnssSeconaryBandConfig)) {
+        // Now set required secondary band config
+        mLocApi->configConstellationMultiBand(mGnssSeconaryBandConfig, locApiResponse);
+    }
+}
+
+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),
+            mCount(count),
+            mIds(nullptr) {
+                if (mCount > 0) {
+                    mIds = new uint32_t[count];
+                    if (mIds) {
+                        for (uint32_t index = 0; index < count; index++) {
+                            mIds[index] = ids[index];
+                        }
+                    } else {
+                        LOC_LOGe("memory allocation for mIds failed");
+                    }
+                }
+        }
+
+        inline MsgGnssGetConfig(const MsgGnssGetConfig& obj) :
+                MsgGnssGetConfig(obj.mAdapter, obj.mApi, obj.mConfigMask,
+                        obj.mIds, obj.mCount) {}
+
+        inline virtual ~MsgGnssGetConfig()
+        {
+            if (nullptr != mIds) delete[] mIds;
+        }
+        inline virtual void proc() const {
+            if (!mAdapter.isEngineCapabilitiesKnown()) {
+                mAdapter.mPendingMsgs.push_back(new MsgGnssGetConfig(*this));
+                return;
+            }
+            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 (!ContextBase::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
+                    mApi.getBlacklistSv();
+                    err = LOCATION_ERROR_SUCCESS;
+                }
+                if (index < mCount) {
+                    errs[index++] = err;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT) {
+                err = LOCATION_ERROR_NOT_SUPPORTED;
+                if (index < mCount) {
+                    errs[index++] = LOCATION_ERROR_NOT_SUPPORTED;
+                }
+            }
+            if (mConfigMask & GNSS_CONFIG_FLAGS_ROBUST_LOCATION_BIT) {
+                uint32_t sessionId = *(mIds+index);
+                LocApiResponse* locApiResponse =
+                        new LocApiResponse(*mAdapter.getContext(),
+                                           [this, sessionId] (LocationError err) {
+                                           mAdapter.reportResponse(err, sessionId);});
+                if (!locApiResponse) {
+                    LOC_LOGe("memory alloc failed");
+                    mAdapter.reportResponse(LOCATION_ERROR_GENERAL_FAILURE, sessionId);
+                } else {
+                   mApi.getRobustLocationConfig(sessionId, locApiResponse);
+                }
+            }
+
+            if (mConfigMask & GNSS_CONFIG_FLAGS_MIN_GPS_WEEK_BIT) {
+                uint32_t sessionId = *(mIds+index);
+                LocApiResponse* locApiResponse =
+                        new LocApiResponse(*mAdapter.getContext(),
+                                           [this, sessionId] (LocationError err) {
+                                           mAdapter.reportResponse(err, sessionId);});
+                if (!locApiResponse) {
+                    LOC_LOGe("memory alloc failed");
+                    mAdapter.reportResponse(LOCATION_ERROR_GENERAL_FAILURE, sessionId);
+                } else {
+                   mApi.getMinGpsWeek(sessionId, locApiResponse);
+                }
+            }
+
+            if (mConfigMask & GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT) {
+                uint32_t sessionId = *(mIds+index);
+                LocApiResponse* locApiResponse =
+                        new LocApiResponse(*mAdapter.getContext(),
+                                           [this, sessionId] (LocationError err) {
+                                           mAdapter.reportResponse(err, sessionId);});
+                if (!locApiResponse) {
+                    LOC_LOGe("memory alloc failed");
+                    mAdapter.reportResponse(LOCATION_ERROR_GENERAL_FAILURE, sessionId);
+                } else {
+                    mApi.getParameter(sessionId, GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT,
+                                      locApiResponse);
+                }
+            }
+
+            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;
+}
+
+bool
+GnssAdapter::convertToGnssSvIdConfig(
+        const std::vector<GnssSvIdSource>& blacklistedSvIds, GnssSvIdConfig& config)
+{
+    bool retVal = false;
+    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;
+        config.sbasBlacklistSvMask = 0;
+        config.navicBlacklistSvMask = 0;
+        retVal = true;
+    } else {
+        // Parse the vector and convert SV IDs to mask values
+        for (GnssSvIdSource source : blacklistedSvIds) {
+            uint64_t* svMaskPtr = NULL;
+            GnssSvId initialSvId = 0;
+            uint16_t svIndexOffset = 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;
+            case GNSS_SV_TYPE_SBAS:
+                // SBAS does not support enable/disable whole constellation
+                // so do not set up svTypeMask for SBAS
+                svMaskPtr = &config.sbasBlacklistSvMask;
+                // SBAS currently has two ranges, [120, 158] and [183, 191]
+                if (0 == source.svId) {
+                    LOC_LOGd("blacklist all SBAS SV");
+                } else if (source.svId >= GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID) {
+                    // handle SV id in range [183, 191]
+                    initialSvId = GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID;
+                    svIndexOffset = GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH;
+                } else if ((source.svId >= GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID) &&
+                           (source.svId < (GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID +
+                                           GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH))){
+                        // handle SV id in range of [120, 158]
+                        initialSvId = GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID;
+                    } else {
+                        LOC_LOGe("invalid SBAS sv id %d", source.svId);
+                        svMaskPtr = nullptr;
+                    }
+                    break;
+            case GNSS_SV_TYPE_NAVIC:
+                 svMaskPtr = &config.navicBlacklistSvMask;
+                 initialSvId = GNSS_SV_CONFIG_NAVIC_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 {
+                    uint32_t shiftCnt = source.svId + svIndexOffset - initialSvId;
+                    *svMaskPtr |= (1ULL << shiftCnt);
+                }
+            }
+        }
+
+        // Return true if any one source is valid
+        if (0 != config.gloBlacklistSvMask ||
+                0 != config.bdsBlacklistSvMask ||
+                0 != config.galBlacklistSvMask ||
+                0 != config.qzssBlacklistSvMask ||
+                0 != config.sbasBlacklistSvMask ||
+                0 != config.navicBlacklistSvMask) {
+            retVal = true;
+        }
+    }
+
+    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64,
+             config.bdsBlacklistSvMask, config.gloBlacklistSvMask,
+             config.qzssBlacklistSvMask, config.galBlacklistSvMask,
+            config.sbasBlacklistSvMask, config.navicBlacklistSvMask);
+
+    return retVal;
+}
+
+void GnssAdapter::convertFromGnssSvIdConfig(
+        const GnssSvIdConfig& svConfig, std::vector<GnssSvIdSource>& blacklistedSvIds)
+{
+    // Convert blacklisted SV mask values to vectors
+    if (svConfig.bdsBlacklistSvMask) {
+        convertGnssSvIdMaskToList(
+                svConfig.bdsBlacklistSvMask, blacklistedSvIds,
+                GNSS_SV_CONFIG_BDS_INITIAL_SV_ID, GNSS_SV_TYPE_BEIDOU);
+    }
+    if (svConfig.galBlacklistSvMask) {
+        convertGnssSvIdMaskToList(
+                svConfig.galBlacklistSvMask, blacklistedSvIds,
+                GNSS_SV_CONFIG_GAL_INITIAL_SV_ID, GNSS_SV_TYPE_GALILEO);
+    }
+    if (svConfig.gloBlacklistSvMask) {
+        convertGnssSvIdMaskToList(
+                svConfig.gloBlacklistSvMask, blacklistedSvIds,
+                GNSS_SV_CONFIG_GLO_INITIAL_SV_ID, GNSS_SV_TYPE_GLONASS);
+    }
+    if (svConfig.qzssBlacklistSvMask) {
+        convertGnssSvIdMaskToList(
+                svConfig.qzssBlacklistSvMask, blacklistedSvIds,
+                GNSS_SV_CONFIG_QZSS_INITIAL_SV_ID, GNSS_SV_TYPE_QZSS);
+    }
+    if (svConfig.sbasBlacklistSvMask) {
+        // SBAS - SV 120 to 158, maps to 0 to 38
+        //        SV 183 to 191, maps to 39 to 47
+        uint64_t sbasBlacklistSvMask = svConfig.sbasBlacklistSvMask;
+        // operate on 120 and 158 first
+        sbasBlacklistSvMask <<= (64 - GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH);
+        sbasBlacklistSvMask >>= (64 - GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH);
+        convertGnssSvIdMaskToList(
+                sbasBlacklistSvMask, blacklistedSvIds,
+                GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID, GNSS_SV_TYPE_SBAS);
+        // operate on the second range
+        sbasBlacklistSvMask = svConfig.sbasBlacklistSvMask;
+        sbasBlacklistSvMask >>= GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH;
+        convertGnssSvIdMaskToList(
+                sbasBlacklistSvMask, blacklistedSvIds,
+                GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID, GNSS_SV_TYPE_SBAS);
+    }
+    if (svConfig.navicBlacklistSvMask) {
+        convertGnssSvIdMaskToList(
+                svConfig.navicBlacklistSvMask, blacklistedSvIds,
+                GNSS_SV_CONFIG_NAVIC_INITIAL_SV_ID, GNSS_SV_TYPE_NAVIC);
+    }
+}
+
+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) {
+        LOC_LOGd("blacklist all SVs in constellation %d", source.constellation);
+        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;
+            // SBAS has two ranges:
+            // SBAS - SV 120 to 158, maps to 0 to 38
+            //        SV 183 to 191, maps to 39 to 47
+            // #define GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID     120
+            // #define GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH 39
+            // #define GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID    183
+            if (svType == GNSS_SV_TYPE_SBAS) {
+                if (bitNumber >= GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH) {
+                    source.svId = bitNumber - GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH +
+                                  GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID;
+                }
+            }
+            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.blacklistedSvIds);
+        if (config.blacklistedSvIds.size() > 0) {
+            config.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT;
+        }
+        LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64 ", "
+                 "qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", navic 0x%" PRIx64,
+                 svIdConfig.bdsBlacklistSvMask, svIdConfig.gloBlacklistSvMask,
+                 svIdConfig.qzssBlacklistSvMask, svIdConfig.galBlacklistSvMask,
+                 svIdConfig.sbasBlacklistSvMask,  svIdConfig.navicBlacklistSvMask);
+        // use 0 session id to indicate that receiver does not yet care about session id
+        mControlCallbacks.gnssConfigCb(0, 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 {
+            if (!mAdapter->isEngineCapabilitiesKnown()) {
+                mAdapter->mPendingMsgs.push_back(new MsgGnssUpdateSvTypeConfig(*this));
+                return;
+            }
+            // Check if feature is supported
+            if (!ContextBase::isFeatureSupported(
+                    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+                LOC_LOGe("Feature not supported.");
+            } else {
+                // Send update request to modem
+                mAdapter->gnssSvTypeConfigUpdate(mConfig);
+            }
+        }
+    };
+
+    sendMsg(new MsgGnssUpdateSvTypeConfig(this, mLocApi, config));
+}
+
+void
+GnssAdapter::gnssSvTypeConfigUpdate(const GnssSvTypeConfig& config)
+{
+    // Gather bits removed from enabled mask
+    GnssSvTypesMask enabledRemoved = mGnssSvTypeConfig.enabledSvTypesMask &
+            (mGnssSvTypeConfig.enabledSvTypesMask ^ config.enabledSvTypesMask);
+    // Send reset if any constellation is removed from the enabled list
+    bool sendReset = (enabledRemoved != 0);
+    // Save new config and update
+    gnssSetSvTypeConfig(config);
+    gnssSvTypeConfigUpdate(sendReset);
+}
+
+void
+GnssAdapter::gnssSvTypeConfigUpdate(bool sendReset)
+{
+    LOC_LOGd("size %" PRIu32" constellations blacklisted 0x%" PRIx64 ", enabled 0x%" PRIx64
+             ", sendReset %d",
+             mGnssSvTypeConfig.size, mGnssSvTypeConfig.blacklistedSvTypesMask,
+             mGnssSvTypeConfig.enabledSvTypesMask, sendReset);
+
+    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", Navic 0x%" PRIx64,
+            mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+            mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask,
+            mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask);
+
+    LOC_LOGd("blacklist bds 0x%" PRIx64 ", glo 0x%" PRIx64
+            ", qzss 0x%" PRIx64 ", gal 0x%" PRIx64 ", sbas 0x%" PRIx64 ", Navic 0x%" PRIx64,
+            mGnssSvIdConfig.bdsBlacklistSvMask, mGnssSvIdConfig.gloBlacklistSvMask,
+            mGnssSvIdConfig.qzssBlacklistSvMask, mGnssSvIdConfig.galBlacklistSvMask,
+            mGnssSvIdConfig.sbasBlacklistSvMask, mGnssSvIdConfig.navicBlacklistSvMask);
+
+    if (mGnssSvTypeConfig.size == sizeof(mGnssSvTypeConfig)) {
+
+        if (sendReset) {
+            mLocApi->resetConstellationControl();
+        }
+
+        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;
+            }
+            if (mGnssSvTypeConfig.blacklistedSvTypesMask & GNSS_SV_TYPES_MASK_NAVIC_BIT) {
+                blacklistConfig.navicBlacklistSvMask = GNSS_SV_CONFIG_ALL_BITS_ENABLED_MASK;
+            }
+        }
+
+        // Send blacklist info
+        mLocApi->setBlacklistSv(blacklistConfig);
+
+        // Send only enabled constellation config
+        if (mGnssSvTypeConfig.enabledSvTypesMask) {
+            GnssSvTypeConfig svTypeConfig = {sizeof(GnssSvTypeConfig), 0, 0};
+            svTypeConfig.enabledSvTypesMask = mGnssSvTypeConfig.enabledSvTypesMask;
+            mLocApi->setConstellationControl(svTypeConfig);
+        }
+    }
+}
+
+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 (!mAdapter->isEngineCapabilitiesKnown()) {
+                mAdapter->mPendingMsgs.push_back(new MsgGnssGetSvTypeConfig(*this));
+                return;
+            }
+            if (!ContextBase::isFeatureSupported(
+                    LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+                LOC_LOGe("Feature not supported.");
+            } else {
+                // Save the callback
+                mAdapter->gnssSetSvTypeConfigCallback(mCallback);
+                // Send GET request to modem
+                mApi->getConstellationControl();
+            }
+        }
+    };
+
+    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 (!mAdapter->isEngineCapabilitiesKnown()) {
+                mAdapter->mPendingMsgs.push_back(new MsgGnssResetSvTypeConfig(*this));
+                return;
+            }
+            if (!ContextBase::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
+                mAdapter->gnssSvIdConfigUpdate();
+                // Send reset request to modem
+                mApi->resetConstellationControl();
+            }
+        }
+    };
+
+    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);
+    }
+}
+
+void GnssAdapter::deleteAidingData(const GnssAidingData &data, uint32_t sessionId) {
+    struct timespec bootDeleteAidingDataTime;
+    int64_t bootDeleteTimeMs;
+    if (clock_gettime(CLOCK_BOOTTIME, &bootDeleteAidingDataTime) == 0) {
+        bootDeleteTimeMs = bootDeleteAidingDataTime.tv_sec * 1000000;
+        int64_t diffTimeBFirSecDelete = bootDeleteTimeMs - mLastDeleteAidingDataTime;
+        if (diffTimeBFirSecDelete > DELETE_AIDING_DATA_EXPECTED_TIME_MS) {
+            mLocApi->deleteAidingData(data, new LocApiResponse(*getContext(),
+                    [this, sessionId] (LocationError err) {
+                        reportResponse(err, sessionId);
+                    }));
+            mLastDeleteAidingDataTime = bootDeleteTimeMs;
+       }
+   }
+}
+
+uint32_t
+GnssAdapter::gnssDeleteAidingDataCommand(GnssAidingData& data)
+{
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGD("%s]: id %u", __func__, sessionId);
+
+    struct MsgDeleteAidingData : public LocMsg {
+        GnssAdapter& mAdapter;
+        uint32_t mSessionId;
+        GnssAidingData mData;
+        inline MsgDeleteAidingData(GnssAdapter& adapter,
+                                   uint32_t sessionId,
+                                   GnssAidingData& data) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mData(data) {}
+        inline virtual void proc() const {
+            if ((mData.posEngineMask & STANDARD_POSITIONING_ENGINE) != 0) {
+                mAdapter.deleteAidingData(mData, mSessionId);
+                SystemStatus* s = mAdapter.getSystemStatus();
+                if ((nullptr != s) && (mData.deleteAll)) {
+                    s->setDefaultGnssEngineStates();
+                }
+            }
+
+            bool retVal = mAdapter.mEngHubProxy->gnssDeleteAidingData(mData);
+            // When SPE engine is invoked, responseCb will be invoked
+            // from QMI Loc API call.
+            // When SPE engine is not invoked, we also need to deliver responseCb
+            if ((mData.posEngineMask & STANDARD_POSITIONING_ENGINE) == 0) {
+                LocationError err = LOCATION_ERROR_NOT_SUPPORTED;
+                if (retVal == true) {
+                    err = LOCATION_ERROR_SUCCESS;
+                }
+                mAdapter.reportResponse(err, mSessionId);
+            }
+        }
+    };
+
+    sendMsg(new MsgDeleteAidingData(*this, sessionId, data));
+    return sessionId;
+}
+
+void
+GnssAdapter::gnssUpdateXtraThrottleCommand(const bool enabled)
+{
+    LOC_LOGD("%s] enabled:%d", __func__, enabled);
+
+    struct UpdateXtraThrottleMsg : public LocMsg {
+        GnssAdapter& mAdapter;
+        const bool mEnabled;
+        inline UpdateXtraThrottleMsg(GnssAdapter& adapter, const bool enabled) :
+            LocMsg(),
+            mAdapter(adapter),
+            mEnabled(enabled) {}
+        inline virtual void proc() const {
+                mAdapter.mXtraObserver.updateXtraThrottle(mEnabled);
+        }
+    };
+
+    sendMsg(new UpdateXtraThrottleMsg(*this, enabled));
+}
+
+void
+GnssAdapter::injectLocationCommand(double latitude, double longitude, float accuracy)
+{
+    LOC_LOGD("%s]: latitude %8.4f longitude %8.4f accuracy %8.4f",
+             __func__, latitude, longitude, accuracy);
+
+    struct MsgInjectLocation : public LocMsg {
+        LocApiBase& mApi;
+        ContextBase& mContext;
+        BlockCPIInfo& mBlockCPI;
+        double mLatitude;
+        double mLongitude;
+        float mAccuracy;
+        bool mOnDemandCpi;
+        inline MsgInjectLocation(LocApiBase& api,
+                                 ContextBase& context,
+                                 BlockCPIInfo& blockCPIInfo,
+                                 double latitude,
+                                 double longitude,
+                                 float accuracy,
+                                 bool onDemandCpi) :
+            LocMsg(),
+            mApi(api),
+            mContext(context),
+            mBlockCPI(blockCPIInfo),
+            mLatitude(latitude),
+            mLongitude(longitude),
+            mAccuracy(accuracy),
+            mOnDemandCpi(onDemandCpi) {}
+        inline virtual void proc() const {
+            if ((uptimeMillis() <= mBlockCPI.blockedTillTsMs) &&
+                (fabs(mLatitude-mBlockCPI.latitude) <= mBlockCPI.latLonDiffThreshold) &&
+                (fabs(mLongitude-mBlockCPI.longitude) <= mBlockCPI.latLonDiffThreshold)) {
+
+                LOC_LOGD("%s]: positon injection blocked: lat: %f, lon: %f, accuracy: %f",
+                         __func__, mLatitude, mLongitude, mAccuracy);
+
+            } else {
+                mApi.injectPosition(mLatitude, mLongitude, mAccuracy, mOnDemandCpi);
+            }
+        }
+    };
+
+    sendMsg(new MsgInjectLocation(*mLocApi, *mContext, mBlockCPIInfo,
+                                  latitude, longitude, accuracy, mOdcpiRequestActive));
+}
+
+void
+GnssAdapter::injectLocationExtCommand(const GnssLocationInfoNotification &locationInfo)
+{
+    LOC_LOGd("latitude %8.4f longitude %8.4f accuracy %8.4f, tech mask 0x%x",
+             locationInfo.location.latitude, locationInfo.location.longitude,
+             locationInfo.location.accuracy, locationInfo.location.techMask);
+
+    struct MsgInjectLocationExt : public LocMsg {
+        LocApiBase& mApi;
+        ContextBase& mContext;
+        GnssLocationInfoNotification mLocationInfo;
+        inline MsgInjectLocationExt(LocApiBase& api,
+                                    ContextBase& context,
+                                    GnssLocationInfoNotification locationInfo) :
+            LocMsg(),
+            mApi(api),
+            mContext(context),
+            mLocationInfo(locationInfo) {}
+        inline virtual void proc() const {
+            // false to indicate for none-ODCPI
+            mApi.injectPosition(mLocationInfo, false);
+        }
+    };
+
+    sendMsg(new MsgInjectLocationExt(*mLocApi, *mContext, locationInfo));
+}
+
+void
+GnssAdapter::injectTimeCommand(int64_t time, int64_t timeReference, int32_t uncertainty)
+{
+    LOC_LOGD("%s]: time %lld timeReference %lld uncertainty %d",
+             __func__, (long long)time, (long long)timeReference, uncertainty);
+
+    struct MsgInjectTime : public LocMsg {
+        LocApiBase& mApi;
+        ContextBase& mContext;
+        int64_t mTime;
+        int64_t mTimeReference;
+        int32_t mUncertainty;
+        inline MsgInjectTime(LocApiBase& api,
+                             ContextBase& context,
+                             int64_t time,
+                             int64_t timeReference,
+                             int32_t uncertainty) :
+            LocMsg(),
+            mApi(api),
+            mContext(context),
+            mTime(time),
+            mTimeReference(timeReference),
+            mUncertainty(uncertainty) {}
+        inline virtual void proc() const {
+            mApi.setTime(mTime, mTimeReference, mUncertainty);
+        }
+    };
+
+    sendMsg(new MsgInjectTime(*mLocApi, *mContext, time, timeReference, uncertainty));
+}
+
+// This command is to called to block the position to be injected to the modem.
+// This can happen for network position that comes from modem.
+void
+GnssAdapter::blockCPICommand(double latitude, double longitude,
+                             float accuracy, int blockDurationMsec,
+                             double latLonDiffThreshold)
+{
+    struct MsgBlockCPI : public LocMsg {
+        BlockCPIInfo& mDstCPIInfo;
+        BlockCPIInfo mSrcCPIInfo;
+
+        inline MsgBlockCPI(BlockCPIInfo& dstCPIInfo,
+                           BlockCPIInfo& srcCPIInfo) :
+            mDstCPIInfo(dstCPIInfo),
+            mSrcCPIInfo(srcCPIInfo) {}
+        inline virtual void proc() const {
+            // in the same hal thread, save the cpi to be blocked
+            // the global variable
+            mDstCPIInfo = mSrcCPIInfo;
+        }
+    };
+
+    // construct the new block CPI info and queue on the same thread
+    // for processing
+    BlockCPIInfo blockCPIInfo;
+    blockCPIInfo.latitude = latitude;
+    blockCPIInfo.longitude = longitude;
+    blockCPIInfo.accuracy = accuracy;
+    blockCPIInfo.blockedTillTsMs = uptimeMillis() + blockDurationMsec;
+    blockCPIInfo.latLonDiffThreshold = latLonDiffThreshold;
+
+    LOC_LOGD("%s]: block CPI lat: %f, lon: %f ", __func__, latitude, longitude);
+    // send a message to record down the coarse position
+    // to be blocked from injection in the master copy (mBlockCPIInfo)
+    sendMsg(new MsgBlockCPI(mBlockCPIInfo, blockCPIInfo));
+}
+
+void
+GnssAdapter::updateSystemPowerState(PowerStateType systemPowerState) {
+    if (POWER_STATE_UNKNOWN != systemPowerState) {
+        mSystemPowerState = systemPowerState;
+        mLocApi->updateSystemPowerState(mSystemPowerState);
+    }
+}
+
+void
+GnssAdapter::updateSystemPowerStateCommand(PowerStateType systemPowerState) {
+    LOC_LOGd("power event %d", systemPowerState);
+
+    struct MsgUpdatePowerState : public LocMsg {
+        GnssAdapter& mAdapter;
+        PowerStateType mSystemPowerState;
+
+        inline MsgUpdatePowerState(GnssAdapter& adapter,
+                                   PowerStateType systemPowerState) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSystemPowerState(systemPowerState) {}
+        inline virtual void proc() const {
+            mAdapter.updateSystemPowerState(mSystemPowerState);
+        }
+    };
+
+    sendMsg(new MsgUpdatePowerState(*this, systemPowerState));
+}
+
+void
+GnssAdapter::addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+    LOC_LOGD("%s]: client %p", __func__, client);
+
+    struct MsgAddClient : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocationAPI* mClient;
+        const LocationCallbacks mCallbacks;
+        inline MsgAddClient(GnssAdapter& adapter,
+                            LocationAPI* client,
+                            const LocationCallbacks& callbacks) :
+            LocMsg(),
+            mAdapter(adapter),
+            mClient(client),
+            mCallbacks(callbacks) {}
+        inline virtual void proc() const {
+            // check whether we need to notify client of cached location system info
+            mAdapter.notifyClientOfCachedLocationSystemInfo(mClient, mCallbacks);
+            mAdapter.saveClient(mClient, mCallbacks);
+        }
+    };
+
+    sendMsg(new MsgAddClient(*this, client, callbacks));
+}
+
+void
+GnssAdapter::stopClientSessions(LocationAPI* client)
+{
+    LOC_LOGD("%s]: client %p", __func__, client);
+
+    /* Time-based Tracking */
+    std::vector<LocationSessionKey> vTimeBasedTrackingClient;
+    for (auto it : mTimeBasedTrackingSessions) {
+        if (client == it.first.client) {
+            vTimeBasedTrackingClient.emplace_back(it.first.client, it.first.id);
+        }
+    }
+    for (auto key : vTimeBasedTrackingClient) {
+        stopTimeBasedTrackingMultiplex(key.client, key.id);
+        eraseTrackingSession(key.client, key.id);
+    }
+
+    /* Distance-based Tracking */
+    for (auto it = mDistanceBasedTrackingSessions.begin();
+              it != mDistanceBasedTrackingSessions.end(); /* no increment here*/) {
+        if (client == it->first.client) {
+            mLocApi->stopDistanceBasedTracking(it->first.id, new LocApiResponse(*getContext(),
+                          [this, client, id=it->first.id] (LocationError err) {
+                    if (LOCATION_ERROR_SUCCESS == err) {
+                        eraseTrackingSession(client, id);
+                    }
+                }
+            ));
+        }
+        ++it; // increment only when not erasing an iterator
+    }
+
+}
+
+void
+GnssAdapter::updateClientsEventMask()
+{
+    // need to register for leap second info
+    // for proper nmea generation
+    LOC_API_ADAPTER_EVENT_MASK_T mask = LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO |
+            LOC_API_ADAPTER_BIT_EVENT_REPORT_INFO;
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        if (it->second.trackingCb != nullptr ||
+            it->second.gnssLocationInfoCb != nullptr ||
+            it->second.engineLocationsInfoCb != nullptr) {
+            mask |= LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT;
+        }
+        if (it->second.gnssSvCb != nullptr) {
+            mask |= LOC_API_ADAPTER_BIT_SATELLITE_REPORT;
+        }
+        if ((it->second.gnssNmeaCb != nullptr) && (mNmeaMask)) {
+            mask |= LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT;
+        }
+        if (it->second.gnssMeasurementsCb != nullptr) {
+            mask |= LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT;
+        }
+        if (it->second.gnssDataCb != nullptr) {
+            mask |= LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT;
+            mask |= LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT;
+            updateNmeaMask(mNmeaMask | LOC_NMEA_MASK_DEBUG_V02);
+        }
+    }
+
+    /*
+    ** For Automotive use cases we need to enable MEASUREMENT, POLY and EPHEMERIS
+    ** when QDR is enabled (e.g.: either enabled via conf file or
+    ** engine hub is loaded successfully).
+    ** Note: this need to be called from msg queue thread.
+    */
+    if((1 == ContextBase::mGps_conf.EXTERNAL_DR_ENABLED) ||
+       (true == initEngHubProxy())) {
+        mask |= LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT;
+        mask |= LOC_API_ADAPTER_BIT_GNSS_SV_POLYNOMIAL_REPORT;
+        mask |= LOC_API_ADAPTER_BIT_PARSED_UNPROPAGATED_POSITION_REPORT;
+        mask |= LOC_API_ADAPTER_BIT_GNSS_SV_EPHEMERIS_REPORT;
+
+        // Nhz measurement bit is set based on callback from loc eng hub
+        // for Nhz engines.
+        mask |= checkMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT);
+
+        LOC_LOGd("Auto usecase, Enable MEAS/POLY/EPHEMERIS - mask 0x%" PRIx64 "",
+                mask);
+    }
+
+    if (mAgpsManager.isRegistered()) {
+        mask |= LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST;
+    }
+    // Add ODCPI handling
+    if (nullptr != mOdcpiRequestCb) {
+        mask |= LOC_API_ADAPTER_BIT_REQUEST_WIFI;
+    }
+
+    // need to register for leap second info
+    // for proper nmea generation
+    mask |= LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO;
+
+    // always register for NI NOTIFY VERIFY to handle internally in HAL
+    mask |= LOC_API_ADAPTER_BIT_NI_NOTIFY_VERIFY_REQUEST;
+
+    // Enable the latency report
+    if (mask & LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT) {
+        if (mLogger.isLogEnabled()) {
+            mask |= LOC_API_ADAPTER_BIT_LATENCY_INFORMATION;
+        }
+    }
+
+    updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
+}
+
+void
+GnssAdapter::handleEngineUpEvent()
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    struct MsgHandleEngineUpEvent : public LocMsg {
+        GnssAdapter& mAdapter;
+        inline MsgHandleEngineUpEvent(GnssAdapter& adapter) :
+            LocMsg(),
+            mAdapter(adapter) {}
+        virtual void proc() const {
+            mAdapter.setEngineCapabilitiesKnown(true);
+            mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+            // must be called only after capabilities are known
+            mAdapter.setConfig();
+            mAdapter.gnssSvIdConfigUpdate();
+            mAdapter.gnssSvTypeConfigUpdate();
+            mAdapter.updateSystemPowerState(mAdapter.getSystemPowerState());
+            mAdapter.gnssSecondaryBandConfigUpdate();
+            // start CDFW service
+            mAdapter.initCDFWService();
+            // restart sessions
+            mAdapter.restartSessions(true);
+            for (auto msg: mAdapter.mPendingMsgs) {
+                mAdapter.sendMsg(msg);
+            }
+            mAdapter.mPendingMsgs.clear();
+        }
+    };
+
+    readConfigCommand();
+    sendMsg(new MsgHandleEngineUpEvent(*this));
+}
+
+void
+GnssAdapter::restartSessions(bool modemSSR)
+{
+    LOC_LOGi(":enter");
+
+    if (modemSSR) {
+        // odcpi session is no longer active after restart
+        mOdcpiRequestActive = false;
+    }
+
+    // SPE will be restarted now, so set this variable to false.
+    mSPEAlreadyRunningAtHighestInterval = false;
+
+    if (false == mTimeBasedTrackingSessions.empty()) {
+        // inform engine hub that GNSS session is about to start
+        mEngHubProxy->gnssSetFixMode(mLocPositionMode);
+        mEngHubProxy->gnssStartFix();
+        checkUpdateDgnssNtrip(false);
+    }
+
+    checkAndRestartSPESession();
+}
+
+void GnssAdapter::checkAndRestartSPESession()
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    // SPE will be restarted now, so set this variable to false.
+    mSPEAlreadyRunningAtHighestInterval = false;
+
+    checkAndRestartTimeBasedSession();
+
+    for (auto it = mDistanceBasedTrackingSessions.begin();
+        it != mDistanceBasedTrackingSessions.end(); ++it) {
+        mLocApi->startDistanceBasedTracking(it->first.id, it->second,
+                                            new LocApiResponse(*getContext(),
+                                            [] (LocationError /*err*/) {}));
+    }
+}
+
+// suspend all on-going sessions
+void
+GnssAdapter::suspendSessions()
+{
+    LOC_LOGi(":enter");
+
+    if (!mTimeBasedTrackingSessions.empty()) {
+        // inform engine hub that GNSS session has stopped
+        mEngHubProxy->gnssStopFix();
+        mLocApi->stopFix(nullptr);
+        if (isDgnssNmeaRequired()) {
+            mDgnssState &= ~DGNSS_STATE_NO_NMEA_PENDING;
+        }
+        stopDgnssNtrip();
+        mSPEAlreadyRunningAtHighestInterval = false;
+    }
+}
+
+void GnssAdapter::checkAndRestartTimeBasedSession()
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    if (!mTimeBasedTrackingSessions.empty()) {
+        // get the LocationOptions that has the smallest interval, which should be the active one
+        TrackingOptions smallestIntervalOptions; // size is zero until set for the first time
+        TrackingOptions highestPowerTrackingOptions;
+        memset(&smallestIntervalOptions, 0, sizeof(smallestIntervalOptions));
+        memset(&highestPowerTrackingOptions, 0, sizeof(highestPowerTrackingOptions));
+        for (auto it = mTimeBasedTrackingSessions.begin();
+                it != mTimeBasedTrackingSessions.end(); ++it) {
+            // size of zero means we havent set it yet
+            if (0 == smallestIntervalOptions.size ||
+                it->second.minInterval < smallestIntervalOptions.minInterval) {
+                 smallestIntervalOptions = it->second;
+            }
+            GnssPowerMode powerMode = it->second.powerMode;
+            // Size of zero means we havent set it yet
+            if (0 == highestPowerTrackingOptions.size ||
+                (GNSS_POWER_MODE_INVALID != powerMode &&
+                        powerMode < highestPowerTrackingOptions.powerMode)) {
+                 highestPowerTrackingOptions = it->second;
+            }
+        }
+
+        highestPowerTrackingOptions.setLocationOptions(smallestIntervalOptions);
+        // want to run SPE session at a fixed min interval in some automotive scenarios
+        if(!checkAndSetSPEToRunforNHz(highestPowerTrackingOptions)) {
+            mLocApi->startTimeBasedTracking(highestPowerTrackingOptions, nullptr);
+        }
+    }
+}
+
+LocationCapabilitiesMask
+GnssAdapter::getCapabilities()
+{
+    LocationCapabilitiesMask mask = 0;
+    uint32_t carrierCapabilities = ContextBase::getCarrierCapabilities();
+    // time based tracking always supported
+    mask |= LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT;
+    // geofence always supported
+    mask |= LOCATION_CAPABILITIES_GEOFENCE_BIT;
+    if (carrierCapabilities & LOC_GPS_CAPABILITY_MSB) {
+        mask |= LOCATION_CAPABILITIES_GNSS_MSB_BIT;
+    }
+    if (LOC_GPS_CAPABILITY_MSA & carrierCapabilities) {
+        mask |= LOCATION_CAPABILITIES_GNSS_MSA_BIT;
+    }
+    if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING)) {
+        mask |= LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT |
+                LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT;
+    }
+    if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) {
+        mask |= LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT;
+    }
+    if (ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_OUTDOOR_TRIP_BATCHING)) {
+        mask |= LOCATION_CAPABILITIES_OUTDOOR_TRIP_BATCHING_BIT;
+    }
+    if (ContextBase::gnssConstellationConfig()) {
+        mask |= LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT;
+    }
+    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_DEBUG_NMEA_V02)) {
+        mask |= LOCATION_CAPABILITIES_DEBUG_NMEA_BIT;
+    }
+    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_CONSTELLATION_ENABLEMENT_V02)) {
+        mask |= LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT;
+    }
+    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_AGPM_V02)) {
+        mask |= LOCATION_CAPABILITIES_AGPM_BIT;
+    }
+    //Get QWES feature status mask
+    mask |= ContextBase::getQwesFeatureStatus();
+    return mask;
+}
+
+void
+GnssAdapter::notifyClientOfCachedLocationSystemInfo(
+        LocationAPI* client, const LocationCallbacks& callbacks) {
+
+    if (mLocSystemInfo.systemInfoMask) {
+        // client need to be notified if client has not yet previously registered
+        // for the info but now register for it.
+        bool notifyClientOfSystemInfo = false;
+        // check whether we need to notify client of cached location system info
+        //
+        // client need to be notified if client has not yet previously registered
+        // for the info but now register for it.
+        if (callbacks.locationSystemInfoCb) {
+            notifyClientOfSystemInfo = true;
+            auto it = mClientData.find(client);
+            if (it != mClientData.end()) {
+                LocationCallbacks oldCallbacks = it->second;
+                if (oldCallbacks.locationSystemInfoCb) {
+                    notifyClientOfSystemInfo = false;
+                }
+            }
+        }
+
+        if (notifyClientOfSystemInfo) {
+            callbacks.locationSystemInfoCb(mLocSystemInfo);
+        }
+    }
+}
+
+bool
+GnssAdapter::isTimeBasedTrackingSession(LocationAPI* client, uint32_t sessionId)
+{
+    LocationSessionKey key(client, sessionId);
+    return (mTimeBasedTrackingSessions.find(key) != mTimeBasedTrackingSessions.end());
+}
+
+bool
+GnssAdapter::isDistanceBasedTrackingSession(LocationAPI* client, uint32_t sessionId)
+{
+    LocationSessionKey key(client, sessionId);
+    return (mDistanceBasedTrackingSessions.find(key) != mDistanceBasedTrackingSessions.end());
+}
+
+bool
+GnssAdapter::hasCallbacksToStartTracking(LocationAPI* client)
+{
+    bool allowed = false;
+    auto it = mClientData.find(client);
+    if (it != mClientData.end()) {
+        if (it->second.trackingCb || it->second.gnssLocationInfoCb ||
+                it->second.engineLocationsInfoCb || it->second.gnssMeasurementsCb ||
+                it->second.gnssDataCb || it->second.gnssSvCb || it->second.gnssNmeaCb) {
+            allowed = true;
+        } else {
+            LOC_LOGi("missing right callback to start tracking")
+        }
+    } else {
+        LOC_LOGi("client %p not found", client)
+    }
+    return allowed;
+}
+
+bool
+GnssAdapter::isTrackingSession(LocationAPI* client, uint32_t sessionId)
+{
+    LocationSessionKey key(client, sessionId);
+    return (mTimeBasedTrackingSessions.find(key) != mTimeBasedTrackingSessions.end());
+}
+
+void
+GnssAdapter::reportPowerStateIfChanged()
+{
+    bool newPowerOn = !mTimeBasedTrackingSessions.empty() ||
+                      !mDistanceBasedTrackingSessions.empty();
+    if (newPowerOn != mPowerOn) {
+        mPowerOn = newPowerOn;
+        if (mPowerStateCb != nullptr) {
+            mPowerStateCb(mPowerOn);
+        }
+    }
+}
+
+void
+GnssAdapter::getPowerStateChangesCommand(std::function<void(bool)> powerStateCb)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    struct MsgReportLocation : public LocMsg {
+        GnssAdapter& mAdapter;
+        std::function<void(bool)> mPowerStateCb;
+        inline MsgReportLocation(GnssAdapter& adapter,
+                                 std::function<void(bool)> powerStateCb) :
+            LocMsg(),
+            mAdapter(adapter),
+            mPowerStateCb(powerStateCb) {}
+        inline virtual void proc() const {
+            mAdapter.savePowerStateCallback(mPowerStateCb);
+            mPowerStateCb(mAdapter.getPowerState());
+        }
+    };
+
+    sendMsg(new MsgReportLocation(*this, powerStateCb));
+}
+
+void
+GnssAdapter::saveTrackingSession(LocationAPI* client, uint32_t sessionId,
+                                const TrackingOptions& options)
+{
+    LocationSessionKey key(client, sessionId);
+    if ((options.minDistance > 0) &&
+            ContextBase::isMessageSupported(LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) {
+        mDistanceBasedTrackingSessions[key] = options;
+    } else {
+        mTimeBasedTrackingSessions[key] = options;
+    }
+    reportPowerStateIfChanged();
+}
+
+void
+GnssAdapter::eraseTrackingSession(LocationAPI* client, uint32_t sessionId)
+{
+    LocationSessionKey key(client, sessionId);
+    auto it = mTimeBasedTrackingSessions.find(key);
+    if (it != mTimeBasedTrackingSessions.end()) {
+        mTimeBasedTrackingSessions.erase(it);
+    } else {
+        auto itr = mDistanceBasedTrackingSessions.find(key);
+        if (itr != mDistanceBasedTrackingSessions.end()) {
+            mDistanceBasedTrackingSessions.erase(itr);
+        }
+    }
+    reportPowerStateIfChanged();
+}
+
+bool GnssAdapter::setLocPositionMode(const LocPosMode& mode) {
+    if (!mLocPositionMode.equals(mode)) {
+        mLocPositionMode = mode;
+        return true;
+    } else {
+        return false;
+    }
+}
+
+void
+GnssAdapter::reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId)
+{
+    LOC_LOGD("%s]: client %p id %u err %u", __func__, client, sessionId, err);
+
+    auto it = mClientData.find(client);
+    if (it != mClientData.end() && it->second.responseCb != nullptr) {
+        it->second.responseCb(err, sessionId);
+    } else {
+        LOC_LOGW("%s]: client %p id %u not found in data", __func__, client, sessionId);
+    }
+}
+
+void
+GnssAdapter::reportResponse(LocationError err, uint32_t sessionId)
+{
+    LOC_LOGD("%s]: id %u err %u", __func__, sessionId, err);
+
+    if (mControlCallbacks.size > 0 && mControlCallbacks.responseCb != nullptr) {
+        mControlCallbacks.responseCb(err, sessionId);
+    } else {
+        LOC_LOGW("%s]: control client response callback not found", __func__);
+    }
+}
+
+void
+GnssAdapter::reportResponse(size_t count, LocationError* errs, uint32_t* ids)
+{
+    IF_LOC_LOGD {
+        std::string idsString = "[";
+        std::string errsString = "[";
+        if (NULL != ids && NULL != errs) {
+            for (size_t i=0; i < count; ++i) {
+                idsString += std::to_string(ids[i]) + " ";
+                errsString += std::to_string(errs[i]) + " ";
+            }
+        }
+        idsString += "]";
+        errsString += "]";
+
+        LOC_LOGD("%s]: ids %s errs %s",
+                 __func__, idsString.c_str(), errsString.c_str());
+    }
+
+    if (mControlCallbacks.size > 0 && mControlCallbacks.collectiveResponseCb != nullptr) {
+        mControlCallbacks.collectiveResponseCb(count, errs, ids);
+    } else {
+        LOC_LOGW("%s]: control client callback not found", __func__);
+    }
+}
+
+uint32_t
+GnssAdapter::startTrackingCommand(LocationAPI* client, TrackingOptions& options)
+{
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGD("%s]: client %p id %u minInterval %u minDistance %u mode %u powermode %u tbm %u",
+             __func__, client, sessionId, options.minInterval, options.minDistance, options.mode,
+             options.powerMode, options.tbm);
+
+    struct MsgStartTracking : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        uint32_t mSessionId;
+        mutable TrackingOptions mOptions;
+        inline MsgStartTracking(GnssAdapter& adapter,
+                               LocApiBase& api,
+                               LocationAPI* client,
+                               uint32_t sessionId,
+                               TrackingOptions options) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mSessionId(sessionId),
+            mOptions(options) {}
+        inline virtual void proc() const {
+            // distance based tracking will need to know engine capabilities before it can start
+            if (!mAdapter.isEngineCapabilitiesKnown() && mOptions.minDistance > 0) {
+                mAdapter.mPendingMsgs.push_back(new MsgStartTracking(*this));
+                return;
+            }
+            LocationError err = LOCATION_ERROR_SUCCESS;
+            if (!mAdapter.hasCallbacksToStartTracking(mClient)) {
+                err = LOCATION_ERROR_CALLBACK_MISSING;
+            } else if (0 == mOptions.size) {
+                err = LOCATION_ERROR_INVALID_PARAMETER;
+            } else {
+                if (mOptions.minInterval < MIN_TRACKING_INTERVAL) {
+                    mOptions.minInterval = MIN_TRACKING_INTERVAL;
+                }
+                if (mOptions.minDistance > 0 &&
+                        ContextBase::isMessageSupported(
+                        LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING)) {
+                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+                    mApi.startDistanceBasedTracking(mSessionId, mOptions,
+                            new LocApiResponse(*mAdapter.getContext(),
+                            [&mAdapter = mAdapter, mSessionId = mSessionId, mClient = mClient]
+                            (LocationError err) {
+                        if (LOCATION_ERROR_SUCCESS != err) {
+                            mAdapter.eraseTrackingSession(mClient, mSessionId);
+                        }
+                        mAdapter.reportResponse(mClient, err, mSessionId);
+                    }));
+                } else {
+                    if (GNSS_POWER_MODE_M4 == mOptions.powerMode &&
+                            mOptions.tbm > TRACKING_TBM_THRESHOLD_MILLIS) {
+                        LOC_LOGd("TBM (%d) > %d Falling back to M2 power mode",
+                                mOptions.tbm, TRACKING_TBM_THRESHOLD_MILLIS);
+                        mOptions.powerMode = GNSS_POWER_MODE_M2;
+                    }
+                    // Api doesn't support multiple clients for time based tracking, so mutiplex
+                    bool reportToClientWithNoWait =
+                            mAdapter.startTimeBasedTrackingMultiplex(mClient, mSessionId, mOptions);
+                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+
+                    if (reportToClientWithNoWait) {
+                        mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId);
+                    }
+                }
+            }
+        }
+    };
+
+    sendMsg(new MsgStartTracking(*this, *mLocApi, client, sessionId, options));
+    return sessionId;
+
+}
+
+bool
+GnssAdapter::startTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t sessionId,
+                                             const TrackingOptions& options)
+{
+    bool reportToClientWithNoWait = true;
+
+    if (mTimeBasedTrackingSessions.empty()) {
+        /*Reset previous NMEA reported time stamp */
+        mPrevNmeaRptTimeNsec = 0;
+        startTimeBasedTracking(client, sessionId, options);
+        // need to wait for QMI callback
+        reportToClientWithNoWait = false;
+    } else {
+        // find the smallest interval and powerMode
+        TrackingOptions multiplexedOptions = {}; // size is 0 until set for the first time
+        GnssPowerMode multiplexedPowerMode = GNSS_POWER_MODE_INVALID;
+        memset(&multiplexedOptions, 0, sizeof(multiplexedOptions));
+        for (auto it = mTimeBasedTrackingSessions.begin(); it != mTimeBasedTrackingSessions.end(); ++it) {
+            // if not set or there is a new smallest interval, then set the new interval
+            if (0 == multiplexedOptions.size ||
+                it->second.minInterval < multiplexedOptions.minInterval) {
+                multiplexedOptions = it->second;
+            }
+            // if session is not the one we are updating and either powerMode
+            // is not set or there is a new smallest powerMode, then set the new powerMode
+            if (GNSS_POWER_MODE_INVALID == multiplexedPowerMode ||
+                it->second.powerMode < multiplexedPowerMode) {
+                multiplexedPowerMode = it->second.powerMode;
+            }
+        }
+        bool updateOptions = false;
+        // if session we are starting has smaller interval then next smallest
+        if (options.minInterval < multiplexedOptions.minInterval) {
+            multiplexedOptions.minInterval = options.minInterval;
+            updateOptions = true;
+        }
+
+        // if session we are starting has smaller powerMode then next smallest
+        if (options.powerMode < multiplexedPowerMode) {
+            multiplexedOptions.powerMode = options.powerMode;
+            updateOptions = true;
+        }
+        if (updateOptions) {
+            // restart time based tracking with the newly updated options
+
+            startTimeBasedTracking(client, sessionId, multiplexedOptions);
+            // need to wait for QMI callback
+            reportToClientWithNoWait = false;
+        }
+        // else part: no QMI call is made, need to report back to client right away
+    }
+
+    return reportToClientWithNoWait;
+}
+
+void
+GnssAdapter::startTimeBasedTracking(LocationAPI* client, uint32_t sessionId,
+        const TrackingOptions& trackingOptions)
+{
+    LOC_LOGd("minInterval %u minDistance %u mode %u powermode %u tbm %u",
+            trackingOptions.minInterval, trackingOptions.minDistance,
+            trackingOptions.mode, trackingOptions.powerMode, trackingOptions.tbm);
+    LocPosMode locPosMode = {};
+    convertOptions(locPosMode, trackingOptions);
+    // save position mode parameters
+    setLocPositionMode(locPosMode);
+    // inform engine hub that GNSS session is about to start
+    mEngHubProxy->gnssSetFixMode(mLocPositionMode);
+    mEngHubProxy->gnssStartFix();
+
+    // want to run SPE session at a fixed min interval in some automotive scenarios
+    // use a local copy of TrackingOptions as the TBF may get modified in the
+    // checkAndSetSPEToRunforNHz function
+    TrackingOptions tempOptions(trackingOptions);
+    if (!checkAndSetSPEToRunforNHz(tempOptions)) {
+        mLocApi->startTimeBasedTracking(tempOptions, new LocApiResponse(*getContext(),
+                          [this, client, sessionId] (LocationError err) {
+                if (LOCATION_ERROR_SUCCESS != err) {
+                    eraseTrackingSession(client, sessionId);
+                } else {
+                    checkUpdateDgnssNtrip(false);
+                }
+
+                reportResponse(client, err, sessionId);
+            }
+        ));
+    } else {
+        reportResponse(client, LOCATION_ERROR_SUCCESS, sessionId);
+    }
+
+}
+
+void
+GnssAdapter::updateTracking(LocationAPI* client, uint32_t sessionId,
+        const TrackingOptions& updatedOptions, const TrackingOptions& oldOptions)
+{
+    LocPosMode locPosMode = {};
+    convertOptions(locPosMode, updatedOptions);
+    // save position mode parameters
+    setLocPositionMode(locPosMode);
+
+    // inform engine hub that GNSS session is about to start
+    mEngHubProxy->gnssSetFixMode(mLocPositionMode);
+    mEngHubProxy->gnssStartFix();
+
+    // want to run SPE session at a fixed min interval in some automotive scenarios
+    // use a local copy of TrackingOptions as the TBF may get modified in the
+    // checkAndSetSPEToRunforNHz function
+    TrackingOptions tempOptions(updatedOptions);
+    if(!checkAndSetSPEToRunforNHz(tempOptions)) {
+        mLocApi->startTimeBasedTracking(tempOptions, new LocApiResponse(*getContext(),
+                          [this, client, sessionId, oldOptions] (LocationError err) {
+                if (LOCATION_ERROR_SUCCESS != err) {
+                    // restore the old LocationOptions
+                    saveTrackingSession(client, sessionId, oldOptions);
+                }
+                reportResponse(client, err, sessionId);
+            }
+        ));
+    } else {
+        reportResponse(client, LOCATION_ERROR_SUCCESS, sessionId);
+    }
+}
+
+void
+GnssAdapter::updateTrackingOptionsCommand(LocationAPI* client, uint32_t id,
+                                          TrackingOptions& options)
+{
+    LOC_LOGD("%s]: client %p id %u minInterval %u mode %u",
+             __func__, client, id, options.minInterval, options.mode);
+
+    struct MsgUpdateTracking : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        uint32_t mSessionId;
+        mutable TrackingOptions mOptions;
+        inline MsgUpdateTracking(GnssAdapter& adapter,
+                                LocApiBase& api,
+                                LocationAPI* client,
+                                uint32_t sessionId,
+                                TrackingOptions options) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mSessionId(sessionId),
+            mOptions(options) {}
+        inline virtual void proc() const {
+            // distance based tracking will need to know engine capabilities before it can start
+            if (!mAdapter.isEngineCapabilitiesKnown() && mOptions.minDistance > 0) {
+                mAdapter.mPendingMsgs.push_back(new MsgUpdateTracking(*this));
+                return;
+            }
+            LocationError err = LOCATION_ERROR_SUCCESS;
+            bool isTimeBased = mAdapter.isTimeBasedTrackingSession(mClient, mSessionId);
+            bool isDistanceBased = mAdapter.isDistanceBasedTrackingSession(mClient, mSessionId);
+            if (!isTimeBased && !isDistanceBased) {
+                err = LOCATION_ERROR_ID_UNKNOWN;
+            } else if (0 == mOptions.size) {
+                err = LOCATION_ERROR_INVALID_PARAMETER;
+            }
+            if (LOCATION_ERROR_SUCCESS != err) {
+                mAdapter.reportResponse(mClient, err, mSessionId);
+            } else {
+                if (GNSS_POWER_MODE_M4 == mOptions.powerMode &&
+                        mOptions.tbm > TRACKING_TBM_THRESHOLD_MILLIS) {
+                    LOC_LOGd("TBM (%d) > %d Falling back to M2 power mode",
+                            mOptions.tbm, TRACKING_TBM_THRESHOLD_MILLIS);
+                    mOptions.powerMode = GNSS_POWER_MODE_M2;
+                }
+                if (mOptions.minInterval < MIN_TRACKING_INTERVAL) {
+                    mOptions.minInterval = MIN_TRACKING_INTERVAL;
+                }
+                // Now update session as required
+                if (isTimeBased && mOptions.minDistance > 0) {
+                    // switch from time based to distance based
+                    // Api doesn't support multiple clients for time based tracking, so mutiplex
+                    bool reportToClientWithNoWait =
+                        mAdapter.stopTimeBasedTrackingMultiplex(mClient, mSessionId);
+                    // erases the time based Session
+                    mAdapter.eraseTrackingSession(mClient, mSessionId);
+                    if (reportToClientWithNoWait) {
+                        mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId);
+                    }
+                    // saves as distance based Session
+                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+                    mApi.startDistanceBasedTracking(mSessionId, mOptions,
+                            new LocApiResponse(*mAdapter.getContext(),
+                                        [] (LocationError /*err*/) {}));
+                } else if (isDistanceBased && mOptions.minDistance == 0) {
+                    // switch from distance based to time based
+                    mAdapter.eraseTrackingSession(mClient, mSessionId);
+                    mApi.stopDistanceBasedTracking(mSessionId, new LocApiResponse(
+                            *mAdapter.getContext(),
+                            [&mAdapter = mAdapter, mSessionId = mSessionId, mOptions = mOptions,
+                            mClient = mClient] (LocationError /*err*/) {
+                        // Api doesn't support multiple clients for time based tracking,
+                        // so mutiplex
+                        bool reportToClientWithNoWait =
+                                mAdapter.startTimeBasedTrackingMultiplex(mClient, mSessionId,
+                                                                         mOptions);
+                        mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+
+                        if (reportToClientWithNoWait) {
+                            mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId);
+                        }
+                    }));
+                } else if (isTimeBased) {
+                    // update time based tracking
+                    // Api doesn't support multiple clients for time based tracking, so mutiplex
+                    bool reportToClientWithNoWait =
+                            mAdapter.updateTrackingMultiplex(mClient, mSessionId, mOptions);
+                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+
+                    if (reportToClientWithNoWait) {
+                        mAdapter.reportResponse(mClient, err, mSessionId);
+                    }
+                } else if (isDistanceBased) {
+                    // restart distance based tracking
+                    mApi.stopDistanceBasedTracking(mSessionId, new LocApiResponse(
+                            *mAdapter.getContext(),
+                            [&mAdapter = mAdapter, mSessionId = mSessionId, mOptions = mOptions,
+                            mClient = mClient, &mApi = mApi] (LocationError err) {
+                        if (LOCATION_ERROR_SUCCESS == err) {
+                            mApi.startDistanceBasedTracking(mSessionId, mOptions,
+                                    new LocApiResponse(*mAdapter.getContext(),
+                                    [&mAdapter, mClient, mSessionId, mOptions]
+                                    (LocationError err) {
+                                if (LOCATION_ERROR_SUCCESS == err) {
+                                    mAdapter.saveTrackingSession(mClient, mSessionId, mOptions);
+                                }
+                                mAdapter.reportResponse(mClient, err, mSessionId);
+                            }));
+                        }
+                    }));
+                }
+            }
+        }
+    };
+
+    sendMsg(new MsgUpdateTracking(*this, *mLocApi, client, id, options));
+}
+
+bool
+GnssAdapter::updateTrackingMultiplex(LocationAPI* client, uint32_t id,
+                                     const TrackingOptions& trackingOptions)
+{
+    bool reportToClientWithNoWait = true;
+
+    LocationSessionKey key(client, id);
+    // get the session we are updating
+    auto it = mTimeBasedTrackingSessions.find(key);
+
+    // cache the clients existing LocationOptions
+    TrackingOptions oldOptions = it->second;
+
+    // if session we are updating exists and the minInterval or powerMode has changed
+    if (it != mTimeBasedTrackingSessions.end() &&
+       (it->second.minInterval != trackingOptions.minInterval ||
+        it->second.powerMode != trackingOptions.powerMode)) {
+        // find the smallest interval and powerMode, other than the session we are updating
+        TrackingOptions multiplexedOptions = {}; // size is 0 until set for the first time
+        GnssPowerMode multiplexedPowerMode = GNSS_POWER_MODE_INVALID;
+        memset(&multiplexedOptions, 0, sizeof(multiplexedOptions));
+        for (auto it2 = mTimeBasedTrackingSessions.begin();
+             it2 != mTimeBasedTrackingSessions.end(); ++it2) {
+            // if session is not the one we are updating and either interval
+            // is not set or there is a new smallest interval, then set the new interval
+            if (it2->first != key && (0 == multiplexedOptions.size ||
+                it2->second.minInterval < multiplexedOptions.minInterval)) {
+                 multiplexedOptions = it2->second;
+            }
+            // if session is not the one we are updating and either powerMode
+            // is not set or there is a new smallest powerMode, then set the new powerMode
+            if (it2->first != key && (GNSS_POWER_MODE_INVALID == multiplexedPowerMode ||
+                it2->second.powerMode < multiplexedPowerMode)) {
+                multiplexedPowerMode = it2->second.powerMode;
+            }
+            // else part: no QMI call is made, need to report back to client right away
+        }
+        bool updateOptions = false;
+        // if session we are updating has smaller interval then next smallest
+        if (trackingOptions.minInterval < multiplexedOptions.minInterval) {
+            multiplexedOptions.minInterval = trackingOptions.minInterval;
+            updateOptions = true;
+        }
+        // if session we are updating has smaller powerMode then next smallest
+        if (trackingOptions.powerMode < multiplexedPowerMode) {
+            multiplexedOptions.powerMode = trackingOptions.powerMode;
+            updateOptions = true;
+        }
+        // if only one session exists, then tracking should be updated with it
+        if (1 == mTimeBasedTrackingSessions.size()) {
+            multiplexedOptions = trackingOptions;
+            updateOptions = true;
+        }
+        if (updateOptions) {
+            // restart time based tracking with the newly updated options
+            updateTracking(client, id, multiplexedOptions, oldOptions);
+            // need to wait for QMI callback
+            reportToClientWithNoWait = false;
+        }
+    }
+
+    return reportToClientWithNoWait;
+}
+
+void
+GnssAdapter::stopTrackingCommand(LocationAPI* client, uint32_t id)
+{
+    LOC_LOGD("%s]: client %p id %u", __func__, client, id);
+
+    struct MsgStopTracking : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        LocationAPI* mClient;
+        uint32_t mSessionId;
+        inline MsgStopTracking(GnssAdapter& adapter,
+                               LocApiBase& api,
+                               LocationAPI* client,
+                               uint32_t sessionId) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mClient(client),
+            mSessionId(sessionId) {}
+        inline virtual void proc() const {
+            bool isTimeBased = mAdapter.isTimeBasedTrackingSession(mClient, mSessionId);
+            bool isDistanceBased = mAdapter.isDistanceBasedTrackingSession(mClient, mSessionId);
+            if (isTimeBased || isDistanceBased) {
+                if (isTimeBased) {
+                    // Api doesn't support multiple clients for time based tracking, so mutiplex
+                    bool reportToClientWithNoWait =
+                        mAdapter.stopTimeBasedTrackingMultiplex(mClient, mSessionId);
+                    mAdapter.eraseTrackingSession(mClient, mSessionId);
+
+                    if (reportToClientWithNoWait) {
+                        mAdapter.reportResponse(mClient, LOCATION_ERROR_SUCCESS, mSessionId);
+                    }
+                } else if (isDistanceBased) {
+                    mApi.stopDistanceBasedTracking(mSessionId, new LocApiResponse(
+                            *mAdapter.getContext(),
+                            [&mAdapter = mAdapter, mSessionId = mSessionId, mClient = mClient]
+                            (LocationError err) {
+                        if (LOCATION_ERROR_SUCCESS == err) {
+                            mAdapter.eraseTrackingSession(mClient, mSessionId);
+                        }
+                        mAdapter.reportResponse(mClient, err, mSessionId);
+                    }));
+                }
+            } else {
+                mAdapter.reportResponse(mClient, LOCATION_ERROR_ID_UNKNOWN, mSessionId);
+            }
+
+        }
+    };
+
+    sendMsg(new MsgStopTracking(*this, *mLocApi, client, id));
+}
+
+bool
+GnssAdapter::stopTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t id)
+{
+    bool reportToClientWithNoWait = true;
+
+    if (1 == mTimeBasedTrackingSessions.size()) {
+        stopTracking(client, id);
+        // need to wait for QMI callback
+        reportToClientWithNoWait = false;
+    } else {
+        LocationSessionKey key(client, id);
+
+        // get the session we are stopping
+        auto it = mTimeBasedTrackingSessions.find(key);
+        if (it != mTimeBasedTrackingSessions.end()) {
+            // find the smallest interval and powerMode, other than the session we are stopping
+            TrackingOptions multiplexedOptions = {}; // size is 0 until set for the first time
+            GnssPowerMode multiplexedPowerMode = GNSS_POWER_MODE_INVALID;
+            memset(&multiplexedOptions, 0, sizeof(multiplexedOptions));
+            for (auto it2 = mTimeBasedTrackingSessions.begin();
+                 it2 != mTimeBasedTrackingSessions.end(); ++it2) {
+                // if session is not the one we are stopping and either interval
+                // is not set or there is a new smallest interval, then set the new interval
+                if (it2->first != key && (0 == multiplexedOptions.size ||
+                    it2->second.minInterval < multiplexedOptions.minInterval)) {
+                     multiplexedOptions = it2->second;
+                }
+                // if session is not the one we are stopping and either powerMode
+                // is not set or there is a new smallest powerMode, then set the new powerMode
+                if (it2->first != key && (GNSS_POWER_MODE_INVALID == multiplexedPowerMode ||
+                    it2->second.powerMode < multiplexedPowerMode)) {
+                    multiplexedPowerMode = it2->second.powerMode;
+                }
+            }
+            // if session we are stopping has smaller interval then next smallest or
+            // if session we are stopping has smaller powerMode then next smallest
+            if (it->second.minInterval < multiplexedOptions.minInterval ||
+                it->second.powerMode < multiplexedPowerMode) {
+                multiplexedOptions.powerMode = multiplexedPowerMode;
+                // restart time based tracking with the newly updated options
+                startTimeBasedTracking(client, id, multiplexedOptions);
+                // need to wait for QMI callback
+                reportToClientWithNoWait = false;
+            }
+            // else part: no QMI call is made, need to report back to client right away
+        }
+    }
+    return reportToClientWithNoWait;
+}
+
+void
+GnssAdapter::stopTracking(LocationAPI* client, uint32_t id)
+{
+    // inform engine hub that GNSS session has stopped
+    mEngHubProxy->gnssStopFix();
+
+    mLocApi->stopFix(new LocApiResponse(*getContext(),
+                     [this, client, id] (LocationError err) {
+        reportResponse(client, err, id);
+    }));
+
+    if (isDgnssNmeaRequired()) {
+        mDgnssState &= ~DGNSS_STATE_NO_NMEA_PENDING;
+    }
+    stopDgnssNtrip();
+
+    mSPEAlreadyRunningAtHighestInterval = false;
+}
+
+bool
+GnssAdapter::hasNiNotifyCallback(LocationAPI* client)
+{
+    auto it = mClientData.find(client);
+    return (it != mClientData.end() && it->second.gnssNiCb);
+}
+
+void
+GnssAdapter::gnssNiResponseCommand(LocationAPI* client,
+                                   uint32_t id,
+                                   GnssNiResponse response)
+{
+    LOC_LOGD("%s]: client %p id %u response %u", __func__, client, id, response);
+
+    struct MsgGnssNiResponse : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocationAPI* mClient;
+        uint32_t mSessionId;
+        GnssNiResponse mResponse;
+        inline MsgGnssNiResponse(GnssAdapter& adapter,
+                                 LocationAPI* client,
+                                 uint32_t sessionId,
+                                 GnssNiResponse response) :
+            LocMsg(),
+            mAdapter(adapter),
+            mClient(client),
+            mSessionId(sessionId),
+            mResponse(response) {}
+        inline virtual void proc() const {
+            NiData& niData = mAdapter.getNiData();
+            LocationError err = LOCATION_ERROR_SUCCESS;
+            if (!mAdapter.hasNiNotifyCallback(mClient)) {
+                err = LOCATION_ERROR_ID_UNKNOWN;
+            } else {
+                NiSession* pSession = NULL;
+                if (mSessionId == niData.sessionEs.reqID &&
+                    NULL != niData.sessionEs.rawRequest) {
+                    pSession = &niData.sessionEs;
+                    // ignore any SUPL NI non-Es session if a SUPL NI ES is accepted
+                    if (mResponse == GNSS_NI_RESPONSE_ACCEPT &&
+                        NULL != niData.session.rawRequest) {
+                            pthread_mutex_lock(&niData.session.tLock);
+                            niData.session.resp = GNSS_NI_RESPONSE_IGNORE;
+                            niData.session.respRecvd = true;
+                            pthread_cond_signal(&niData.session.tCond);
+                            pthread_mutex_unlock(&niData.session.tLock);
+                    }
+                } else if (mSessionId == niData.session.reqID &&
+                    NULL != niData.session.rawRequest) {
+                    pSession = &niData.session;
+                }
+
+                if (pSession) {
+                    LOC_LOGI("%s]: gnssNiResponseCommand: send user mResponse %u for id %u",
+                             __func__, mResponse, mSessionId);
+                    pthread_mutex_lock(&pSession->tLock);
+                    pSession->resp = mResponse;
+                    pSession->respRecvd = true;
+                    pthread_cond_signal(&pSession->tCond);
+                    pthread_mutex_unlock(&pSession->tLock);
+                } else {
+                    err = LOCATION_ERROR_ID_UNKNOWN;
+                    LOC_LOGE("%s]: gnssNiResponseCommand: id %u not an active session",
+                             __func__, mSessionId);
+                }
+            }
+            mAdapter.reportResponse(mClient, err, mSessionId);
+        }
+    };
+
+    sendMsg(new MsgGnssNiResponse(*this, client, id, response));
+
+}
+
+void
+GnssAdapter::gnssNiResponseCommand(GnssNiResponse response, void* rawRequest)
+{
+    LOC_LOGD("%s]: response %u", __func__, response);
+
+    struct MsgGnssNiResponse : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        const GnssNiResponse mResponse;
+        const void* mPayload;
+        inline MsgGnssNiResponse(GnssAdapter& adapter,
+                                 LocApiBase& api,
+                                 const GnssNiResponse response,
+                                 const void* rawRequest) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mResponse(response),
+            mPayload(rawRequest) {}
+        inline virtual ~MsgGnssNiResponse() {
+        }
+        inline virtual void proc() const {
+            mApi.informNiResponse(mResponse, mPayload);
+        }
+    };
+
+    sendMsg(new MsgGnssNiResponse(*this, *mLocApi, response, rawRequest));
+
+}
+
+uint32_t
+GnssAdapter::enableCommand(LocationTechnologyType techType)
+{
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGD("%s]: id %u techType %u", __func__, sessionId, techType);
+
+    struct MsgEnableGnss : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        ContextBase& mContext;
+        uint32_t mSessionId;
+        LocationTechnologyType mTechType;
+        inline MsgEnableGnss(GnssAdapter& adapter,
+                             LocApiBase& api,
+                             ContextBase& context,
+                             uint32_t sessionId,
+                             LocationTechnologyType techType) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mContext(context),
+            mSessionId(sessionId),
+            mTechType(techType) {}
+        inline virtual void proc() const {
+            LocationError err = LOCATION_ERROR_SUCCESS;
+            uint32_t afwControlId = mAdapter.getAfwControlId();
+            if (mTechType != LOCATION_TECHNOLOGY_TYPE_GNSS) {
+                err = LOCATION_ERROR_INVALID_PARAMETER;
+            } else if (afwControlId > 0) {
+                err = LOCATION_ERROR_ALREADY_STARTED;
+            } else {
+                mContext.modemPowerVote(true);
+                mAdapter.setAfwControlId(mSessionId);
+
+                GnssConfigGpsLock gpsLock = GNSS_CONFIG_GPS_LOCK_NONE;
+                if (mAdapter.mSupportNfwControl) {
+                    ContextBase::mGps_conf.GPS_LOCK &= GNSS_CONFIG_GPS_LOCK_NI;
+                    gpsLock = ContextBase::mGps_conf.GPS_LOCK;
+                }
+                mApi.sendMsg(new LocApiMsg([&mApi = mApi, gpsLock]() {
+                    mApi.setGpsLockSync(gpsLock);
+                }));
+                mAdapter.mXtraObserver.updateLockStatus(gpsLock);
+            }
+            mAdapter.reportResponse(err, mSessionId);
+        }
+    };
+
+    if (mContext != NULL) {
+        sendMsg(new MsgEnableGnss(*this, *mLocApi, *mContext, sessionId, techType));
+    } else {
+        LOC_LOGE("%s]: Context is NULL", __func__);
+    }
+
+    return sessionId;
+}
+
+void
+GnssAdapter::disableCommand(uint32_t id)
+{
+    LOC_LOGD("%s]: id %u", __func__, id);
+
+    struct MsgDisableGnss : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        ContextBase& mContext;
+        uint32_t mSessionId;
+        inline MsgDisableGnss(GnssAdapter& adapter,
+                             LocApiBase& api,
+                             ContextBase& context,
+                             uint32_t sessionId) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mContext(context),
+            mSessionId(sessionId) {}
+        inline virtual void proc() const {
+            LocationError err = LOCATION_ERROR_SUCCESS;
+            uint32_t afwControlId = mAdapter.getAfwControlId();
+            if (afwControlId != mSessionId) {
+                err = LOCATION_ERROR_ID_UNKNOWN;
+            } else {
+                mContext.modemPowerVote(false);
+                mAdapter.setAfwControlId(0);
+
+                if (mAdapter.mSupportNfwControl) {
+                    /* We need to disable MO (AFW) */
+                    ContextBase::mGps_conf.GPS_LOCK |= GNSS_CONFIG_GPS_LOCK_MO;
+                }
+                GnssConfigGpsLock gpsLock = ContextBase::mGps_conf.GPS_LOCK;
+                mApi.sendMsg(new LocApiMsg([&mApi = mApi, gpsLock]() {
+                    mApi.setGpsLockSync(gpsLock);
+                }));
+                mAdapter.mXtraObserver.updateLockStatus(gpsLock);
+            }
+            mAdapter.reportResponse(err, mSessionId);
+        }
+    };
+
+    if (mContext != NULL) {
+        sendMsg(new MsgDisableGnss(*this, *mLocApi, *mContext, id));
+    }
+
+}
+
+// This function computes the VRP based latitude, longitude and alittude, and
+// north, east and up velocity and save the result into EHubTechReport.
+void
+GnssAdapter::computeVRPBasedLla(const UlpLocation& loc, GpsLocationExtended& locExt,
+                                const LeverArmConfigInfo& leverArmConfigInfo) {
+
+    float leverArm[3];
+    float rollPitchYaw[3];
+    double lla[3];
+
+    uint16_t locFlags = loc.gpsLocation.flags;
+    uint64_t locExtFlags = locExt.flags;
+
+    // check for SPE fix
+    if (!((locExtFlags & GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE) &&
+          (locExt.locOutputEngType == LOC_OUTPUT_ENGINE_SPE))){
+        LOC_LOGv("not SPE fix, return");
+        return;
+    }
+
+    // we can only do translation if we have VRP based lever ARM info
+    LeverArmTypeMask leverArmFlags = leverArmConfigInfo.leverArmValidMask;
+    if (!(leverArmFlags & LEVER_ARM_TYPE_GNSS_TO_VRP_BIT)) {
+        LOC_LOGd("no VRP based lever ARM info");
+        return;
+    }
+
+    leverArm[0] = leverArmConfigInfo.gnssToVRP.forwardOffsetMeters;
+    leverArm[1] = leverArmConfigInfo.gnssToVRP.sidewaysOffsetMeters;
+    leverArm[2] = leverArmConfigInfo.gnssToVRP.upOffsetMeters;
+
+    if ((locFlags & LOC_GPS_LOCATION_HAS_LAT_LONG) &&
+        (locFlags & LOC_GPS_LOCATION_HAS_ALTITUDE) &&
+        (locFlags & LOCATION_HAS_BEARING_BIT)) {
+
+        lla[0] = loc.gpsLocation.latitude * DEG2RAD;
+        lla[1] = loc.gpsLocation.longitude * DEG2RAD;
+        lla[2] = loc.gpsLocation.altitude;
+
+        rollPitchYaw[0] = 0.0f;
+        rollPitchYaw[1] = 0.0f;
+        rollPitchYaw[2] = loc.gpsLocation.bearing * DEG2RAD;
+
+        loc_convert_lla_gnss_to_vrp(lla, rollPitchYaw, leverArm);
+
+        // assign the converted value into position report and
+        // set up valid mask
+        locExt.llaVRPBased.latitude  = lla[0] * RAD2DEG;
+        locExt.llaVRPBased.longitude = lla[1] * RAD2DEG;
+        locExt.llaVRPBased.altitude  = lla[2];
+        locExt.flags |= GPS_LOCATION_EXTENDED_HAS_LLA_VRP_BASED;
+    } else {
+        LOC_LOGd("SPE fix missing latitude/longitude/alitutde");
+        return;
+    }
+}
+
+void
+GnssAdapter::reportPositionEvent(const UlpLocation& ulpLocation,
+                                 const GpsLocationExtended& locationExtended,
+                                 enum loc_sess_status status,
+                                 LocPosTechMask techMask,
+                                 GnssDataNotification* pDataNotify,
+                                 int msInWeek)
+{
+    // this position is from QMI LOC API, then send report to engine hub
+    // also, send out SPE fix promptly to the clients that have registered
+    // with SPE report
+    LOC_LOGd("reportPositionEvent, eng type: %d, unpro %d, sess status %d msInWeek %d",
+             locationExtended.locOutputEngType,
+             ulpLocation.unpropagatedPosition, status, msInWeek);
+
+    struct MsgReportSPEPosition : public LocMsg {
+        GnssAdapter& mAdapter;
+        mutable UlpLocation mUlpLocation;
+        mutable GpsLocationExtended mLocationExtended;
+        enum loc_sess_status mStatus;
+        LocPosTechMask mTechMask;
+        mutable GnssDataNotification mDataNotify;
+        int mMsInWeek;
+
+        inline MsgReportSPEPosition(GnssAdapter& adapter,
+                                    const UlpLocation& ulpLocation,
+                                    const GpsLocationExtended& locationExtended,
+                                    enum loc_sess_status status,
+                                    LocPosTechMask techMask,
+                                    GnssDataNotification dataNotify,
+                                    int msInWeek) :
+            LocMsg(),
+            mAdapter(adapter),
+            mUlpLocation(ulpLocation),
+            mLocationExtended(locationExtended),
+            mStatus(status),
+            mTechMask(techMask),
+            mDataNotify(dataNotify),
+            mMsInWeek(msInWeek) {}
+        inline virtual void proc() const {
+            if (mAdapter.mTimeBasedTrackingSessions.empty() &&
+                mAdapter.mDistanceBasedTrackingSessions.empty()) {
+                LOC_LOGd("reportPositionEvent, no session on-going, throw away the SPE reports");
+                return;
+            }
+
+            if (false == mUlpLocation.unpropagatedPosition && mDataNotify.size != 0) {
+                if (mMsInWeek >= 0) {
+                    mAdapter.getDataInformation((GnssDataNotification&)mDataNotify,
+                                                mMsInWeek);
+                }
+                mAdapter.reportData(mDataNotify);
+            }
+
+            if (true == mAdapter.initEngHubProxy()){
+                // send the SPE fix to engine hub
+                mAdapter.mEngHubProxy->gnssReportPosition(mUlpLocation, mLocationExtended, mStatus);
+                // report out all SPE fix if it is not propagated, even for failed fix
+                if (false == mUlpLocation.unpropagatedPosition) {
+                    EngineLocationInfo engLocationInfo = {};
+                    engLocationInfo.location = mUlpLocation;
+                    engLocationInfo.locationExtended = mLocationExtended;
+                    engLocationInfo.sessionStatus = mStatus;
+
+                    // obtain the VRP based latitude/longitude/altitude for SPE fix
+                    computeVRPBasedLla(engLocationInfo.location,
+                                       engLocationInfo.locationExtended,
+                                       mAdapter.mLocConfigInfo.leverArmConfigInfo);
+                    mAdapter.reportEnginePositions(1, &engLocationInfo);
+                }
+                return;
+            }
+
+            // unpropagated report: is only for engine hub to consume and no need
+            // to send out to the clients
+            if (true == mUlpLocation.unpropagatedPosition) {
+                return;
+            }
+
+            // extract bug report info - this returns true if consumed by systemstatus
+            SystemStatus* s = mAdapter.getSystemStatus();
+            if ((nullptr != s) &&
+                    ((LOC_SESS_SUCCESS == mStatus) || (LOC_SESS_INTERMEDIATE == mStatus))){
+                s->eventPosition(mUlpLocation, mLocationExtended);
+            }
+
+            mAdapter.reportPosition(mUlpLocation, mLocationExtended, mStatus, mTechMask);
+        }
+    };
+
+    if (mContext != NULL) {
+        GnssDataNotification dataNotifyCopy = {};
+        if (pDataNotify) {
+            dataNotifyCopy = *pDataNotify;
+            dataNotifyCopy.size = sizeof(dataNotifyCopy);
+        }
+        sendMsg(new MsgReportSPEPosition(*this, ulpLocation, locationExtended,
+                                          status, techMask, dataNotifyCopy, msInWeek));
+    }
+}
+
+void
+GnssAdapter::reportEnginePositionsEvent(unsigned int count,
+                                        EngineLocationInfo* locationArr)
+{
+    struct MsgReportEnginePositions : public LocMsg {
+        GnssAdapter& mAdapter;
+        unsigned int mCount;
+        EngineLocationInfo mEngLocInfo[LOC_OUTPUT_ENGINE_COUNT];
+        inline MsgReportEnginePositions(GnssAdapter& adapter,
+                                        unsigned int count,
+                                        EngineLocationInfo* locationArr) :
+            LocMsg(),
+            mAdapter(adapter),
+            mCount(count) {
+            if (mCount > LOC_OUTPUT_ENGINE_COUNT) {
+                mCount = LOC_OUTPUT_ENGINE_COUNT;
+            }
+            if (mCount > 0) {
+                memcpy(mEngLocInfo, locationArr, sizeof(EngineLocationInfo)*mCount);
+            }
+        }
+        inline virtual void proc() const {
+            mAdapter.reportEnginePositions(mCount, mEngLocInfo);
+        }
+    };
+
+    sendMsg(new MsgReportEnginePositions(*this, count, locationArr));
+}
+
+bool
+GnssAdapter::needReportForGnssClient(const UlpLocation& ulpLocation,
+                                     enum loc_sess_status status,
+                                     LocPosTechMask techMask) {
+    bool reported = false;
+
+    // if engine hub is enabled, aka, any of the engine services is enabled,
+    // then always output position reported by engine hub to requesting client
+    if (true == initEngHubProxy()) {
+        reported = true;
+    } else {
+        reported = LocApiBase::needReport(ulpLocation, status, techMask);
+    }
+    return reported;
+}
+
+bool
+GnssAdapter::needReportForFlpClient(enum loc_sess_status status,
+                                    LocPosTechMask techMask) {
+    if (((LOC_SESS_INTERMEDIATE == status) && !(techMask & LOC_POS_TECH_MASK_SENSORS) &&
+        (!getAllowFlpNetworkFixes())) ||
+        (LOC_SESS_FAILURE == status)) {
+        return false;
+    } else {
+        return true;
+    }
+}
+
+bool
+GnssAdapter::isFlpClient(LocationCallbacks& locationCallbacks)
+{
+    return (locationCallbacks.gnssLocationInfoCb == nullptr &&
+            locationCallbacks.gnssSvCb == nullptr &&
+            locationCallbacks.gnssNmeaCb == nullptr &&
+            locationCallbacks.gnssDataCb == nullptr &&
+            locationCallbacks.gnssMeasurementsCb == nullptr);
+}
+
+bool GnssAdapter::needToGenerateNmeaReport(const uint32_t &gpsTimeOfWeekMs,
+        const struct timespec32_t &apTimeStamp)
+{
+    bool retVal = false;
+    uint64_t currentTimeNsec = 0;
+
+    if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER && !mTimeBasedTrackingSessions.empty()) {
+        currentTimeNsec = (apTimeStamp.tv_sec * BILLION_NSEC + apTimeStamp.tv_nsec);
+        if ((GNSS_NMEA_REPORT_RATE_NHZ == ContextBase::sNmeaReportRate) ||
+                (GPS_DEFAULT_FIX_INTERVAL_MS <= mLocPositionMode.min_interval)) {
+            retVal = true;
+        } else { /*tbf is less than 1000 milli-seconds and NMEA reporting rate is set to 1Hz */
+            /* Always send NMEA string for first position report
+             * Send when gpsTimeOfWeekMs is closely aligned with integer boundary
+             */
+            if ((0 == mPrevNmeaRptTimeNsec) ||
+                (0 != gpsTimeOfWeekMs) && (NMEA_MIN_THRESHOLD_MSEC >= (gpsTimeOfWeekMs % 1000))) {
+                retVal = true;
+            } else {
+                uint64_t timeDiffMsec = ((currentTimeNsec - mPrevNmeaRptTimeNsec) / 1000000);
+                // Send when the delta time becomes >= 1 sec
+                if (NMEA_MAX_THRESHOLD_MSEC <= timeDiffMsec) {
+                    retVal = true;
+                }
+            }
+        }
+        if (true == retVal) {
+            mPrevNmeaRptTimeNsec = currentTimeNsec;
+        }
+    }
+    return retVal;
+}
+
+void
+GnssAdapter::logLatencyInfo()
+{
+    if (0 == mGnssLatencyInfoQueue.size()) {
+        LOC_LOGv("mGnssLatencyInfoQueue.size is 0");
+        return;
+    }
+    mGnssLatencyInfoQueue.front().hlosQtimer5 = getQTimerTickCount();
+    if (0 == mGnssLatencyInfoQueue.front().hlosQtimer3) {
+        /* if SPE from engine hub is not reported then hlosQtimer3 = 0, set it
+        equal to hlosQtimer2 to make sense */
+        LOC_LOGv("hlosQtimer3 is 0, setting it to hlosQtimer2");
+        mGnssLatencyInfoQueue.front().hlosQtimer3 = mGnssLatencyInfoQueue.front().hlosQtimer2;
+    }
+    if (0 == mGnssLatencyInfoQueue.front().hlosQtimer4) {
+        /* if PPE from engine hub is not reported then hlosQtimer4 = 0, set it
+        equal to hlosQtimer3 to make sense */
+        LOC_LOGv("hlosQtimer4 is 0, setting it to hlosQtimer3");
+        mGnssLatencyInfoQueue.front().hlosQtimer4 = mGnssLatencyInfoQueue.front().hlosQtimer3;
+    }
+    if (mGnssLatencyInfoQueue.front().hlosQtimer4 < mGnssLatencyInfoQueue.front().hlosQtimer3) {
+        /* hlosQtimer3 is timestamped when SPE from engine hub is reported,
+        and hlosQtimer4 is timestamped when PPE from engine hub is reported.
+        The order is random though, hence making sure the timestamps are sorted */
+        LOC_LOGv("hlosQtimer4 is < hlosQtimer3, swapping them");
+        std::swap(mGnssLatencyInfoQueue.front().hlosQtimer3,
+                  mGnssLatencyInfoQueue.front().hlosQtimer4);
+    }
+    LOC_LOGv("meQtimer1=%" PRIi64 " "
+             "meQtimer2=%" PRIi64 " "
+             "meQtimer3=%" PRIi64 " "
+             "peQtimer1=%" PRIi64 " "
+             "peQtimer2=%" PRIi64 " "
+             "peQtimer3=%" PRIi64 " "
+             "smQtimer1=%" PRIi64 " "
+             "smQtimer2=%" PRIi64 " "
+             "smQtimer3=%" PRIi64 " "
+             "locMwQtimer=%" PRIi64 " "
+             "hlosQtimer1=%" PRIi64 " "
+             "hlosQtimer2=%" PRIi64 " "
+             "hlosQtimer3=%" PRIi64 " "
+             "hlosQtimer4=%" PRIi64 " "
+             "hlosQtimer5=%" PRIi64 " ",
+             mGnssLatencyInfoQueue.front().meQtimer1, mGnssLatencyInfoQueue.front().meQtimer2,
+             mGnssLatencyInfoQueue.front().meQtimer3, mGnssLatencyInfoQueue.front().peQtimer1,
+             mGnssLatencyInfoQueue.front().peQtimer2, mGnssLatencyInfoQueue.front().peQtimer3,
+             mGnssLatencyInfoQueue.front().smQtimer1, mGnssLatencyInfoQueue.front().smQtimer2,
+             mGnssLatencyInfoQueue.front().smQtimer3, mGnssLatencyInfoQueue.front().locMwQtimer,
+             mGnssLatencyInfoQueue.front().hlosQtimer1, mGnssLatencyInfoQueue.front().hlosQtimer2,
+             mGnssLatencyInfoQueue.front().hlosQtimer3, mGnssLatencyInfoQueue.front().hlosQtimer4,
+             mGnssLatencyInfoQueue.front().hlosQtimer5);
+    mLogger.log(mGnssLatencyInfoQueue.front());
+    mGnssLatencyInfoQueue.pop();
+    LOC_LOGv("mGnssLatencyInfoQueue.size after pop=%zu", mGnssLatencyInfoQueue.size());
+}
+
+// only fused report (when engine hub is enabled) or
+// SPE report (when engine hub is disabled) will reach this function
+void
+GnssAdapter::reportPosition(const UlpLocation& ulpLocation,
+                            const GpsLocationExtended& locationExtended,
+                            enum loc_sess_status status,
+                            LocPosTechMask techMask)
+{
+    bool reportToGnssClient = needReportForGnssClient(ulpLocation, status, techMask);
+    bool reportToFlpClient = needReportForFlpClient(status, techMask);
+
+    if (reportToGnssClient || reportToFlpClient) {
+        GnssLocationInfoNotification locationInfo = {};
+        convertLocationInfo(locationInfo, locationExtended, status);
+        convertLocation(locationInfo.location, ulpLocation, locationExtended);
+        logLatencyInfo();
+        for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+            if ((reportToFlpClient && isFlpClient(it->second)) ||
+                    (reportToGnssClient && !isFlpClient(it->second))) {
+                if (nullptr != it->second.gnssLocationInfoCb) {
+                    it->second.gnssLocationInfoCb(locationInfo);
+                } else if ((nullptr != it->second.engineLocationsInfoCb) &&
+                           (false == initEngHubProxy())) {
+                    // if engine hub is disabled, this is SPE fix from modem
+                    // we need to mark one copy marked as fused and one copy marked as PPE
+                    // and dispatch it to the engineLocationsInfoCb
+                    GnssLocationInfoNotification engLocationsInfo[2];
+                    engLocationsInfo[0] = locationInfo;
+                    engLocationsInfo[0].locOutputEngType = LOC_OUTPUT_ENGINE_FUSED;
+                    engLocationsInfo[0].flags |= GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT;
+                    engLocationsInfo[1] = locationInfo;
+                    it->second.engineLocationsInfoCb(2, engLocationsInfo);
+                } else if (nullptr != it->second.trackingCb) {
+                    it->second.trackingCb(locationInfo.location);
+                }
+            }
+        }
+
+        mGnssSvIdUsedInPosAvail = false;
+        mGnssMbSvIdUsedInPosAvail = false;
+        if (reportToGnssClient) {
+            if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA) {
+                mGnssSvIdUsedInPosAvail = true;
+                mGnssSvIdUsedInPosition = locationExtended.gnss_sv_used_ids;
+                if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MULTIBAND) {
+                    mGnssMbSvIdUsedInPosAvail = true;
+                    mGnssMbSvIdUsedInPosition = locationExtended.gnss_mb_sv_used_ids;
+                }
+            }
+
+            // if PACE is enabled
+            if ((true == mLocConfigInfo.paceConfigInfo.isValid) &&
+                (true == mLocConfigInfo.paceConfigInfo.enable)) {
+                // If fix has sensor contribution, and it is fused fix with DRE engine
+                // contributing to the fix, inject to modem
+                if ((LOC_POS_TECH_MASK_SENSORS & techMask) &&
+                        (locationInfo.flags & GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT) &&
+                        (locationInfo.locOutputEngType == LOC_OUTPUT_ENGINE_FUSED) &&
+                        (locationInfo.flags & GNSS_LOCATION_INFO_OUTPUT_ENG_MASK_BIT) &&
+                        (locationInfo.locOutputEngMask & DEAD_RECKONING_ENGINE)) {
+                    mLocApi->injectPosition(locationInfo, false);
+                }
+            }
+        }
+    }
+
+    if (needToGenerateNmeaReport(locationExtended.gpsTime.gpsTimeOfWeekMs,
+            locationExtended.timeStamp.apTimeStamp)) {
+        /*Only BlankNMEA sentence needs to be processed and sent, if both lat, long is 0 &
+          horReliability is not set. */
+        bool blank_fix = ((0 == ulpLocation.gpsLocation.latitude) &&
+                          (0 == ulpLocation.gpsLocation.longitude) &&
+                          (LOC_RELIABILITY_NOT_SET == locationExtended.horizontal_reliability));
+        uint8_t generate_nmea = (reportToGnssClient && status != LOC_SESS_FAILURE && !blank_fix);
+        bool custom_nmea_gga = (1 == ContextBase::mGps_conf.CUSTOM_NMEA_GGA_FIX_QUALITY_ENABLED);
+        bool isTagBlockGroupingEnabled =
+                (1 == ContextBase::mGps_conf.NMEA_TAG_BLOCK_GROUPING_ENABLED);
+        std::vector<std::string> nmeaArraystr;
+        int indexOfGGA = -1;
+        loc_nmea_generate_pos(ulpLocation, locationExtended, mLocSystemInfo, generate_nmea,
+                custom_nmea_gga, nmeaArraystr, indexOfGGA, isTagBlockGroupingEnabled);
+        stringstream ss;
+        for (auto itor = nmeaArraystr.begin(); itor != nmeaArraystr.end(); ++itor) {
+            ss << *itor;
+        }
+        string s = ss.str();
+        reportNmea(s.c_str(), s.length());
+
+        /* DgnssNtrip */
+        if (-1 != indexOfGGA && isDgnssNmeaRequired()) {
+            mDgnssState |= DGNSS_STATE_NO_NMEA_PENDING;
+            mStartDgnssNtripParams.nmea = std::move(nmeaArraystr[indexOfGGA]);
+            bool isLocationValid = (0 != ulpLocation.gpsLocation.latitude) ||
+                    (0 != ulpLocation.gpsLocation.longitude);
+            checkUpdateDgnssNtrip(isLocationValid);
+        }
+    }
+}
+
+void
+GnssAdapter::reportLatencyInfoEvent(const GnssLatencyInfo& gnssLatencyInfo)
+{
+    struct MsgReportLatencyInfo : public LocMsg {
+        GnssAdapter& mAdapter;
+        GnssLatencyInfo mGnssLatencyInfo;
+        inline MsgReportLatencyInfo(GnssAdapter& adapter,
+            const GnssLatencyInfo& gnssLatencyInfo) :
+            mGnssLatencyInfo(gnssLatencyInfo),
+            mAdapter(adapter) {}
+        inline virtual void proc() const {
+            mAdapter.mGnssLatencyInfoQueue.push(mGnssLatencyInfo);
+            LOC_LOGv("mGnssLatencyInfoQueue.size after push=%zu",
+                      mAdapter.mGnssLatencyInfoQueue.size());
+        }
+    };
+    sendMsg(new MsgReportLatencyInfo(*this, gnssLatencyInfo));
+}
+
+void
+GnssAdapter::reportEnginePositions(unsigned int count,
+                                   const EngineLocationInfo* locationArr)
+{
+    bool needReportEnginePositions = false;
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        if (nullptr != it->second.engineLocationsInfoCb) {
+            needReportEnginePositions = true;
+            break;
+        }
+    }
+
+    GnssLocationInfoNotification locationInfo[LOC_OUTPUT_ENGINE_COUNT] = {};
+    for (unsigned int i = 0; i < count; i++) {
+        const EngineLocationInfo* engLocation = (locationArr+i);
+        // if it is fused/default location, call reportPosition maintain legacy behavior
+        if ((GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & engLocation->locationExtended.flags) &&
+            (LOC_OUTPUT_ENGINE_FUSED == engLocation->locationExtended.locOutputEngType)) {
+            reportPosition(engLocation->location,
+                           engLocation->locationExtended,
+                           engLocation->sessionStatus,
+                           engLocation->location.tech_mask);
+        }
+
+        if (needReportEnginePositions) {
+            convertLocationInfo(locationInfo[i], engLocation->locationExtended,
+                                engLocation->sessionStatus);
+            convertLocation(locationInfo[i].location,
+                            engLocation->location,
+                            engLocation->locationExtended);
+        }
+    }
+
+    const EngineLocationInfo* engLocation = locationArr;
+    LOC_LOGv("engLocation->locationExtended.locOutputEngType=%d",
+             engLocation->locationExtended.locOutputEngType);
+
+    if (0 != mGnssLatencyInfoQueue.size()) {
+        if ((GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & engLocation->locationExtended.flags) &&
+            (LOC_OUTPUT_ENGINE_SPE == engLocation->locationExtended.locOutputEngType)) {
+            mGnssLatencyInfoQueue.front().hlosQtimer3 = getQTimerTickCount();
+            LOC_LOGv("SPE hlosQtimer3=%" PRIi64 " ", mGnssLatencyInfoQueue.front().hlosQtimer3);
+        }
+        if ((GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE & engLocation->locationExtended.flags) &&
+            (LOC_OUTPUT_ENGINE_PPE == engLocation->locationExtended.locOutputEngType)) {
+            mGnssLatencyInfoQueue.front().hlosQtimer4 = getQTimerTickCount();
+            LOC_LOGv("PPE hlosQtimer4=%" PRIi64 " ", mGnssLatencyInfoQueue.front().hlosQtimer4);
+        }
+    }
+    if (needReportEnginePositions) {
+        for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+            if (nullptr != it->second.engineLocationsInfoCb) {
+                it->second.engineLocationsInfoCb(count, locationInfo);
+            }
+        }
+    }
+}
+
+void
+GnssAdapter::reportSvEvent(const GnssSvNotification& svNotify,
+                           bool fromEngineHub)
+{
+    if (!fromEngineHub) {
+        mEngHubProxy->gnssReportSv(svNotify);
+        if (true == initEngHubProxy()){
+            return;
+        }
+    }
+
+    struct MsgReportSv : public LocMsg {
+        GnssAdapter& mAdapter;
+        const GnssSvNotification mSvNotify;
+        inline MsgReportSv(GnssAdapter& adapter,
+                           const GnssSvNotification& svNotify) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSvNotify(svNotify) {}
+        inline virtual void proc() const {
+            mAdapter.reportSv((GnssSvNotification&)mSvNotify);
+        }
+    };
+
+    sendMsg(new MsgReportSv(*this, svNotify));
+}
+
+void
+GnssAdapter::reportSv(GnssSvNotification& svNotify)
+{
+    int numSv = svNotify.count;
+    uint16_t gnssSvId = 0;
+    uint64_t svUsedIdMask = 0;
+    for (int i=0; i < numSv; i++) {
+        svUsedIdMask = 0;
+        gnssSvId = svNotify.gnssSvs[i].svId;
+        GnssSignalTypeMask signalTypeMask = svNotify.gnssSvs[i].gnssSignalTypeMask;
+        switch (svNotify.gnssSvs[i].type) {
+            case GNSS_SV_TYPE_GPS:
+                if (mGnssSvIdUsedInPosAvail) {
+                    if (mGnssMbSvIdUsedInPosAvail) {
+                        switch (signalTypeMask) {
+                        case GNSS_SIGNAL_GPS_L1CA:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l1ca_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_GPS_L1C:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l1c_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_GPS_L2:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l2_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_GPS_L5:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gps_l5_sv_used_ids_mask;
+                            break;
+                        }
+                    } else {
+                        svUsedIdMask = mGnssSvIdUsedInPosition.gps_sv_used_ids_mask;
+                    }
+                }
+                break;
+            case GNSS_SV_TYPE_GLONASS:
+                if (mGnssSvIdUsedInPosAvail) {
+                    if (mGnssMbSvIdUsedInPosAvail) {
+                        switch (signalTypeMask) {
+                        case GNSS_SIGNAL_GLONASS_G1:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.glo_g1_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_GLONASS_G2:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.glo_g2_sv_used_ids_mask;
+                            break;
+                        }
+                    } else {
+                        svUsedIdMask = mGnssSvIdUsedInPosition.glo_sv_used_ids_mask;
+                    }
+                }
+                // map the svid to respective constellation range 1..xx
+                // then repective constellation svUsedIdMask map correctly to svid
+                gnssSvId = gnssSvId - GLO_SV_PRN_MIN + 1;
+                break;
+            case GNSS_SV_TYPE_BEIDOU:
+                if (mGnssSvIdUsedInPosAvail) {
+                    if (mGnssMbSvIdUsedInPosAvail) {
+                        switch (signalTypeMask) {
+                        case GNSS_SIGNAL_BEIDOU_B1I:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b1i_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_BEIDOU_B1C:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b1c_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_BEIDOU_B2I:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b2i_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_BEIDOU_B2AI:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b2ai_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_BEIDOU_B2AQ:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.bds_b2aq_sv_used_ids_mask;
+                            break;
+                        }
+                    } else {
+                        svUsedIdMask = mGnssSvIdUsedInPosition.bds_sv_used_ids_mask;
+                    }
+                }
+                gnssSvId = gnssSvId - BDS_SV_PRN_MIN + 1;
+                break;
+            case GNSS_SV_TYPE_GALILEO:
+                if (mGnssSvIdUsedInPosAvail) {
+                    if (mGnssMbSvIdUsedInPosAvail) {
+                        switch (signalTypeMask) {
+                        case GNSS_SIGNAL_GALILEO_E1:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gal_e1_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_GALILEO_E5A:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gal_e5a_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_GALILEO_E5B:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.gal_e5b_sv_used_ids_mask;
+                            break;
+                        }
+                    } else {
+                        svUsedIdMask = mGnssSvIdUsedInPosition.gal_sv_used_ids_mask;
+                    }
+                }
+                gnssSvId = gnssSvId - GAL_SV_PRN_MIN + 1;
+                break;
+            case GNSS_SV_TYPE_QZSS:
+                if (mGnssSvIdUsedInPosAvail) {
+                    if (mGnssMbSvIdUsedInPosAvail) {
+                        switch (signalTypeMask) {
+                        case GNSS_SIGNAL_QZSS_L1CA:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l1ca_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_QZSS_L1S:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l1s_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_QZSS_L2:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l2_sv_used_ids_mask;
+                            break;
+                        case GNSS_SIGNAL_QZSS_L5:
+                            svUsedIdMask = mGnssMbSvIdUsedInPosition.qzss_l5_sv_used_ids_mask;
+                            break;
+                        }
+                    } else {
+                        svUsedIdMask = mGnssSvIdUsedInPosition.qzss_sv_used_ids_mask;
+                    }
+                }
+                gnssSvId = gnssSvId - QZSS_SV_PRN_MIN + 1;
+                break;
+            case GNSS_SV_TYPE_NAVIC:
+                if (mGnssSvIdUsedInPosAvail) {
+                    svUsedIdMask = mGnssSvIdUsedInPosition.navic_sv_used_ids_mask;
+                }
+                gnssSvId = gnssSvId - NAVIC_SV_PRN_MIN + 1;
+                break;
+            default:
+                svUsedIdMask = 0;
+                break;
+        }
+
+        // If SV ID was used in previous position fix, then set USED_IN_FIX
+        // flag, else clear the USED_IN_FIX flag.
+        if (svFitsMask(svUsedIdMask, gnssSvId) && (svUsedIdMask & (1ULL << (gnssSvId - 1)))) {
+            svNotify.gnssSvs[i].gnssSvOptionsMask |= GNSS_SV_OPTIONS_USED_IN_FIX_BIT;
+        }
+    }
+
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        if (nullptr != it->second.gnssSvCb) {
+            it->second.gnssSvCb(svNotify);
+        }
+    }
+
+    if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER &&
+        !mTimeBasedTrackingSessions.empty()) {
+        std::vector<std::string> nmeaArraystr;
+        loc_nmea_generate_sv(svNotify, nmeaArraystr);
+        stringstream ss;
+        for (auto itor = nmeaArraystr.begin(); itor != nmeaArraystr.end(); ++itor) {
+            ss << *itor;
+        }
+        string s = ss.str();
+        reportNmea(s.c_str(), s.length());
+    }
+
+    mGnssSvIdUsedInPosAvail = false;
+    mGnssMbSvIdUsedInPosAvail = false;
+}
+
+void
+GnssAdapter::reportNmeaEvent(const char* nmea, size_t length)
+{
+    if (NMEA_PROVIDER_AP == ContextBase::mGps_conf.NMEA_PROVIDER &&
+        !loc_nmea_is_debug(nmea, length)) {
+        return;
+    }
+
+    struct MsgReportNmea : public LocMsg {
+        GnssAdapter& mAdapter;
+        const char* mNmea;
+        size_t mLength;
+        inline MsgReportNmea(GnssAdapter& adapter,
+                             const char* nmea,
+                             size_t length) :
+            LocMsg(),
+            mAdapter(adapter),
+            mNmea(new char[length+1]),
+            mLength(length) {
+                if (mNmea == nullptr) {
+                    LOC_LOGE("%s] new allocation failed, fatal error.", __func__);
+                    return;
+                }
+                strlcpy((char*)mNmea, nmea, length+1);
+            }
+        inline virtual ~MsgReportNmea()
+        {
+            delete[] mNmea;
+        }
+        inline virtual void proc() const {
+            // extract bug report info - this returns true if consumed by systemstatus
+            bool ret = false;
+            SystemStatus* s = mAdapter.getSystemStatus();
+            if (nullptr != s) {
+                ret = s->setNmeaString(mNmea, mLength);
+            }
+            if (false == ret) {
+                // forward NMEA message to upper layer
+                mAdapter.reportNmea(mNmea, mLength);
+                // DgnssNtrip
+                mAdapter.reportGGAToNtrip(mNmea);
+            }
+        }
+    };
+
+    sendMsg(new MsgReportNmea(*this, nmea, length));
+}
+
+void
+GnssAdapter::reportNmea(const char* nmea, size_t length)
+{
+    GnssNmeaNotification nmeaNotification = {};
+    nmeaNotification.size = sizeof(GnssNmeaNotification);
+
+    struct timeval tv;
+    gettimeofday(&tv, (struct timezone *) NULL);
+    int64_t now = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
+    nmeaNotification.timestamp = now;
+    nmeaNotification.nmea = nmea;
+    nmeaNotification.length = length;
+
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        if (nullptr != it->second.gnssNmeaCb) {
+            it->second.gnssNmeaCb(nmeaNotification);
+        }
+    }
+
+    if (isNMEAPrintEnabled()) {
+        LOC_LOGd("[%" PRId64 ", %zu] %s", now, length, nmea);
+    }
+}
+
+void
+GnssAdapter::reportDataEvent(const GnssDataNotification& dataNotify,
+                             int msInWeek)
+{
+    struct MsgReportData : public LocMsg {
+        GnssAdapter& mAdapter;
+        GnssDataNotification mDataNotify;
+        int mMsInWeek;
+        inline MsgReportData(GnssAdapter& adapter,
+                             const GnssDataNotification& dataNotify,
+                             int msInWeek) :
+            LocMsg(),
+            mAdapter(adapter),
+            mDataNotify(dataNotify),
+            mMsInWeek(msInWeek) {
+        }
+        inline virtual void proc() const {
+            if (mMsInWeek >= 0) {
+                mAdapter.getDataInformation((GnssDataNotification&)mDataNotify,
+                                            mMsInWeek);
+            }
+            mAdapter.reportData((GnssDataNotification&)mDataNotify);
+        }
+    };
+
+    sendMsg(new MsgReportData(*this, dataNotify, msInWeek));
+}
+
+void
+GnssAdapter::reportData(GnssDataNotification& dataNotify)
+{
+    for (int sig = 0; sig < GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES; sig++) {
+        if (GNSS_LOC_DATA_JAMMER_IND_BIT ==
+            (dataNotify.gnssDataMask[sig] & GNSS_LOC_DATA_JAMMER_IND_BIT)) {
+            LOC_LOGv("jammerInd[%d]=%f", sig, dataNotify.jammerInd[sig]);
+        }
+        if (GNSS_LOC_DATA_AGC_BIT ==
+            (dataNotify.gnssDataMask[sig] & GNSS_LOC_DATA_AGC_BIT)) {
+            LOC_LOGv("agc[%d]=%f", sig, dataNotify.agc[sig]);
+        }
+    }
+    for (auto it = mClientData.begin(); it != mClientData.end(); ++it) {
+        if (nullptr != it->second.gnssDataCb) {
+            it->second.gnssDataCb(dataNotify);
+        }
+    }
+}
+
+bool
+GnssAdapter::requestNiNotifyEvent(const GnssNiNotification &notify, const void* data,
+                                  const LocInEmergency emergencyState)
+{
+    LOC_LOGI("%s]: notif_type: %d, timeout: %d, default_resp: %d"
+             "requestor_id: %s (encoding: %d) text: %s text (encoding: %d) extras: %s",
+             __func__, notify.type, notify.timeout, notify.timeoutResponse,
+             notify.requestor, notify.requestorEncoding,
+             notify.message, notify.messageEncoding, notify.extras);
+
+    struct MsgReportNiNotify : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        const GnssNiNotification mNotify;
+        const void* mData;
+        const LocInEmergency mEmergencyState;
+        inline MsgReportNiNotify(GnssAdapter& adapter,
+                                 LocApiBase& api,
+                                 const GnssNiNotification& notify,
+                                 const void* data,
+                                 const LocInEmergency emergencyState) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mNotify(notify),
+            mData(data),
+            mEmergencyState(emergencyState) {}
+        inline virtual void proc() const {
+            bool bIsInEmergency = false;
+            bool bInformNiAccept = false;
+
+            bIsInEmergency = ((LOC_IN_EMERGENCY_UNKNOWN == mEmergencyState) &&
+                    mAdapter.getE911State()) ||                // older modems
+                    (LOC_IN_EMERGENCY_SET == mEmergencyState); // newer modems
+
+            if ((mAdapter.mSupportNfwControl || 0 == mAdapter.getAfwControlId()) &&
+                (GNSS_NI_TYPE_SUPL == mNotify.type || GNSS_NI_TYPE_EMERGENCY_SUPL == mNotify.type)
+                && !bIsInEmergency &&
+                !(GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT & mNotify.options) &&
+                (GNSS_CONFIG_GPS_LOCK_NI & ContextBase::mGps_conf.GPS_LOCK) &&
+                1 == ContextBase::mGps_conf.NI_SUPL_DENY_ON_NFW_LOCKED) {
+                /* If all these conditions are TRUE, then deny the NI Request:
+                -'Q' Lock behavior OR 'P' Lock behavior and GNSS is Locked
+                -NI SUPL Request type or NI SUPL Emergency Request type
+                -NOT in an Emergency Call Session
+                -NOT Privacy Override option
+                -NFW is locked and config item NI_SUPL_DENY_ON_NFW_LOCKED = 1 */
+                mApi.informNiResponse(GNSS_NI_RESPONSE_DENY, mData);
+            } else if (GNSS_NI_TYPE_EMERGENCY_SUPL == mNotify.type) {
+                bInformNiAccept = bIsInEmergency ||
+                        (GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO == ContextBase::mGps_conf.SUPL_ES);
+
+                if (bInformNiAccept) {
+                    mAdapter.requestNiNotify(mNotify, mData, bInformNiAccept);
+                } else {
+                    mApi.informNiResponse(GNSS_NI_RESPONSE_DENY, mData);
+                }
+            } else if (GNSS_NI_TYPE_CONTROL_PLANE == mNotify.type) {
+                if (bIsInEmergency && (1 == ContextBase::mGps_conf.CP_MTLR_ES)) {
+                    mApi.informNiResponse(GNSS_NI_RESPONSE_ACCEPT, mData);
+                }
+                else {
+                    mAdapter.requestNiNotify(mNotify, mData, false);
+                }
+            } else {
+                mAdapter.requestNiNotify(mNotify, mData, false);
+            }
+        }
+    };
+
+    sendMsg(new MsgReportNiNotify(*this, *mLocApi, notify, data, emergencyState));
+
+    return true;
+}
+
+void
+GnssAdapter::reportLocationSystemInfoEvent(const LocationSystemInfo & locationSystemInfo) {
+
+    // send system info to engine hub
+    mEngHubProxy->gnssReportSystemInfo(locationSystemInfo);
+
+    struct MsgLocationSystemInfo : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocationSystemInfo mSystemInfo;
+        inline MsgLocationSystemInfo(GnssAdapter& adapter,
+            const LocationSystemInfo& systemInfo) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSystemInfo(systemInfo) {}
+        inline virtual void proc() const {
+            mAdapter.reportLocationSystemInfo(mSystemInfo);
+        }
+    };
+
+    sendMsg(new MsgLocationSystemInfo(*this, locationSystemInfo));
+}
+
+void
+GnssAdapter::reportLocationSystemInfo(const LocationSystemInfo & locationSystemInfo) {
+    // save the info into the master copy piece by piece, as other system info
+    // may come at different time
+    if (locationSystemInfo.systemInfoMask & LOCATION_SYS_INFO_LEAP_SECOND) {
+        mLocSystemInfo.systemInfoMask |= LOCATION_SYS_INFO_LEAP_SECOND;
+
+        const LeapSecondSystemInfo &srcLeapSecondSysInfo = locationSystemInfo.leapSecondSysInfo;
+        LeapSecondSystemInfo &dstLeapSecondSysInfo = mLocSystemInfo.leapSecondSysInfo;
+        if (srcLeapSecondSysInfo.leapSecondInfoMask &
+                LEAP_SECOND_SYS_INFO_CURRENT_LEAP_SECONDS_BIT) {
+            dstLeapSecondSysInfo.leapSecondInfoMask |=
+                LEAP_SECOND_SYS_INFO_CURRENT_LEAP_SECONDS_BIT;
+            dstLeapSecondSysInfo.leapSecondCurrent = srcLeapSecondSysInfo.leapSecondCurrent;
+        }
+        // once leap second change event is complete, modem may send up event invalidate the leap
+        // second change info while AP is still processing report during leap second transition
+        // so, we choose to keep this info around even though it is old
+        if (srcLeapSecondSysInfo.leapSecondInfoMask & LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT) {
+            dstLeapSecondSysInfo.leapSecondInfoMask |= LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT;
+            dstLeapSecondSysInfo.leapSecondChangeInfo = srcLeapSecondSysInfo.leapSecondChangeInfo;
+        }
+    }
+
+    // we received new info, inform client of the newly received info
+    if (locationSystemInfo.systemInfoMask) {
+        for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+            if (it->second.locationSystemInfoCb != nullptr) {
+                it->second.locationSystemInfoCb(locationSystemInfo);
+            }
+        }
+    }
+}
+
+static void* niThreadProc(void *args)
+{
+    NiSession* pSession = (NiSession*)args;
+    int rc = 0;          /* return code from pthread calls */
+
+    struct timespec present_time;
+    struct timespec expire_time;
+
+    pthread_mutex_lock(&pSession->tLock);
+    /* Calculate absolute expire time */
+    clock_gettime(CLOCK_MONOTONIC, &present_time);
+    expire_time.tv_sec  = present_time.tv_sec + pSession->respTimeLeft;
+    expire_time.tv_nsec = present_time.tv_nsec;
+    LOC_LOGD("%s]: time out set for abs time %ld with delay %d sec",
+             __func__, (long)expire_time.tv_sec, pSession->respTimeLeft);
+
+    while (!pSession->respRecvd) {
+        rc = pthread_cond_timedwait(&pSession->tCond,
+                                    &pSession->tLock,
+                                    &expire_time);
+        if (rc == ETIMEDOUT) {
+            pSession->resp = GNSS_NI_RESPONSE_NO_RESPONSE;
+            LOC_LOGD("%s]: time out after valting for specified time. Ret Val %d",
+                     __func__, rc);
+            break;
+        }
+    }
+    LOC_LOGD("%s]: Java layer has sent us a user response and return value from "
+             "pthread_cond_timedwait = %d pSession->resp is %u", __func__, rc, pSession->resp);
+    pSession->respRecvd = false; /* Reset the user response flag for the next session*/
+
+    // adding this check to support modem restart, in which case, we need the thread
+    // to exit without calling sending data. We made sure that rawRequest is NULL in
+    // loc_eng_ni_reset_on_engine_restart()
+    GnssAdapter* adapter = pSession->adapter;
+    GnssNiResponse resp;
+    void* rawRequest = NULL;
+    bool sendResponse = false;
+
+    if (NULL != pSession->rawRequest) {
+        if (pSession->resp != GNSS_NI_RESPONSE_IGNORE) {
+            resp = pSession->resp;
+            rawRequest = pSession->rawRequest;
+            sendResponse = true;
+        } else {
+            free(pSession->rawRequest);
+        }
+        pSession->rawRequest = NULL;
+    }
+    pthread_mutex_unlock(&pSession->tLock);
+
+    pSession->respTimeLeft = 0;
+    pSession->reqID = 0;
+
+    if (sendResponse) {
+        adapter->gnssNiResponseCommand(resp, rawRequest);
+    }
+
+    return NULL;
+}
+
+bool
+GnssAdapter::requestNiNotify(const GnssNiNotification& notify, const void* data,
+                             const bool bInformNiAccept)
+{
+    NiSession* pSession = NULL;
+    gnssNiCallback gnssNiCb = nullptr;
+
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        if (nullptr != it->second.gnssNiCb) {
+            gnssNiCb = it->second.gnssNiCb;
+            break;
+        }
+    }
+    if (nullptr == gnssNiCb) {
+        if (GNSS_NI_TYPE_EMERGENCY_SUPL == notify.type) {
+            if (bInformNiAccept) {
+                mLocApi->informNiResponse(GNSS_NI_RESPONSE_ACCEPT, data);
+                NiData& niData = getNiData();
+                // ignore any SUPL NI non-Es session if a SUPL NI ES is accepted
+                if (NULL != niData.session.rawRequest) {
+                    pthread_mutex_lock(&niData.session.tLock);
+                    niData.session.resp = GNSS_NI_RESPONSE_IGNORE;
+                    niData.session.respRecvd = true;
+                    pthread_cond_signal(&niData.session.tCond);
+                    pthread_mutex_unlock(&niData.session.tLock);
+                }
+            }
+        }
+        EXIT_LOG(%s, "no clients with gnssNiCb.");
+        return false;
+    }
+
+    if (notify.type == GNSS_NI_TYPE_EMERGENCY_SUPL) {
+        if (NULL != mNiData.sessionEs.rawRequest) {
+            LOC_LOGI("%s]: supl es NI in progress, new supl es NI ignored, type: %d",
+                     __func__, notify.type);
+            if (NULL != data) {
+                free((void*)data);
+            }
+        } else {
+            pSession = &mNiData.sessionEs;
+        }
+    } else {
+        if (NULL != mNiData.session.rawRequest ||
+            NULL != mNiData.sessionEs.rawRequest) {
+            LOC_LOGI("%s]: supl NI in progress, new supl NI ignored, type: %d",
+                     __func__, notify.type);
+            if (NULL != data) {
+                free((void*)data);
+            }
+        } else {
+            pSession = &mNiData.session;
+        }
+    }
+
+    if (pSession) {
+        /* Save request */
+        pSession->rawRequest = (void*)data;
+        pSession->reqID = ++mNiData.reqIDCounter;
+        pSession->adapter = this;
+
+        int sessionId = pSession->reqID;
+
+        /* For robustness, spawn a thread at this point to timeout to clear up the notification
+         * status, even though the OEM layer in java does not do so.
+         **/
+        pSession->respTimeLeft =
+             5 + (notify.timeout != 0 ? notify.timeout : LOC_NI_NO_RESPONSE_TIME);
+
+        int rc = 0;
+        rc = pthread_create(&pSession->thread, NULL, niThreadProc, pSession);
+        if (rc) {
+            LOC_LOGE("%s]: Loc NI thread is not created.", __func__);
+        }
+        rc = pthread_detach(pSession->thread);
+        if (rc) {
+            LOC_LOGE("%s]: Loc NI thread is not detached.", __func__);
+        }
+
+        if (nullptr != gnssNiCb) {
+            gnssNiCb(sessionId, notify);
+        }
+    }
+
+    return true;
+}
+
+void
+GnssAdapter::reportGnssMeasurementsEvent(const GnssMeasurements& gnssMeasurements,
+                                            int msInWeek)
+{
+    LOC_LOGD("%s]: msInWeek=%d", __func__, msInWeek);
+
+    if (0 != gnssMeasurements.gnssMeasNotification.count) {
+        struct MsgReportGnssMeasurementData : public LocMsg {
+            GnssAdapter& mAdapter;
+            GnssMeasurements mGnssMeasurements;
+            GnssMeasurementsNotification mMeasurementsNotify;
+            inline MsgReportGnssMeasurementData(GnssAdapter& adapter,
+                                                const GnssMeasurements& gnssMeasurements,
+                                                int msInWeek) :
+                    LocMsg(),
+                    mAdapter(adapter),
+                    mMeasurementsNotify(gnssMeasurements.gnssMeasNotification) {
+                if (-1 != msInWeek) {
+                    mAdapter.getAgcInformation(mMeasurementsNotify, msInWeek);
+                }
+            }
+            inline virtual void proc() const {
+                mAdapter.reportGnssMeasurementData(mMeasurementsNotify);
+            }
+        };
+
+        sendMsg(new MsgReportGnssMeasurementData(*this, gnssMeasurements, msInWeek));
+    }
+    mEngHubProxy->gnssReportSvMeasurement(gnssMeasurements.gnssSvMeasurementSet);
+    if (mDGnssNeedReport) {
+        reportDGnssDataUsable(gnssMeasurements.gnssSvMeasurementSet);
+    }
+}
+
+void
+GnssAdapter::reportGnssMeasurementData(const GnssMeasurementsNotification& measurements)
+{
+    for (auto it=mClientData.begin(); it != mClientData.end(); ++it) {
+        if (nullptr != it->second.gnssMeasurementsCb) {
+            it->second.gnssMeasurementsCb(measurements);
+        }
+    }
+}
+
+void
+GnssAdapter::reportDGnssDataUsable(const GnssSvMeasurementSet &svMeasurementSet)
+{
+    uint32_t i;
+    bool preDGnssDataUsage = mDGnssDataUsage;
+
+    mDGnssDataUsage = false;
+    for (i = 0; i < svMeasurementSet.svMeasCount; i++) {
+        const Gnss_SVMeasurementStructType& svMeas = svMeasurementSet.svMeas[i];
+        if (svMeas.dgnssSvMeas.dgnssMeasStatus) {
+            mDGnssDataUsage = true;
+            break;
+        }
+    }
+    if (mDGnssDataUsage != preDGnssDataUsage) {
+        if (mCdfwInterface) {
+            mCdfwInterface->reportUsable(mQDgnssListenerHDL, mDGnssDataUsage);
+        }
+    }
+}
+
+void
+GnssAdapter::reportSvPolynomialEvent(GnssSvPolynomial &svPolynomial)
+{
+    LOC_LOGD("%s]: ", __func__);
+    mEngHubProxy->gnssReportSvPolynomial(svPolynomial);
+}
+
+void
+GnssAdapter::reportSvEphemerisEvent(GnssSvEphemerisReport & svEphemeris)
+{
+    LOC_LOGD("%s]:", __func__);
+    mEngHubProxy->gnssReportSvEphemeris(svEphemeris);
+}
+
+
+bool
+GnssAdapter::requestOdcpiEvent(OdcpiRequestInfo& request)
+{
+    struct MsgRequestOdcpi : public LocMsg {
+        GnssAdapter& mAdapter;
+        OdcpiRequestInfo mOdcpiRequest;
+        inline MsgRequestOdcpi(GnssAdapter& adapter, OdcpiRequestInfo& request) :
+                LocMsg(),
+                mAdapter(adapter),
+                mOdcpiRequest(request) {}
+        inline virtual void proc() const {
+            mAdapter.requestOdcpi(mOdcpiRequest);
+        }
+    };
+
+    sendMsg(new MsgRequestOdcpi(*this, request));
+    return true;
+}
+
+void GnssAdapter::requestOdcpi(const OdcpiRequestInfo& request)
+{
+    if (nullptr != mOdcpiRequestCb) {
+        LOC_LOGd("request: type %d, tbf %d, isEmergency %d"
+                 " requestActive: %d timerActive: %d",
+                 request.type, request.tbfMillis, request.isEmergencyMode,
+                 mOdcpiRequestActive, mOdcpiTimer.isActive());
+        // ODCPI START and ODCPI STOP from modem can come in quick succession
+        // so the mOdcpiTimer helps avoid spamming the framework as well as
+        // extending the odcpi session past 30 seconds if needed
+        if (ODCPI_REQUEST_TYPE_START == request.type) {
+            if (false == mOdcpiRequestActive && false == mOdcpiTimer.isActive()) {
+                mOdcpiRequestCb(request);
+                mOdcpiRequestActive = true;
+                mOdcpiTimer.start();
+            // if the current active odcpi session is non-emergency, and the new
+            // odcpi request is emergency, replace the odcpi request with new request
+            // and restart the timer
+            } else if (false == mOdcpiRequest.isEmergencyMode &&
+                       true == request.isEmergencyMode) {
+                mOdcpiRequestCb(request);
+                mOdcpiRequestActive = true;
+                if (true == mOdcpiTimer.isActive()) {
+                    mOdcpiTimer.restart();
+                } else {
+                    mOdcpiTimer.start();
+                }
+            // if ODCPI request is not active but the timer is active, then
+            // just update the active state and wait for timer to expire
+            // before requesting new ODCPI to avoid spamming ODCPI requests
+            } else if (false == mOdcpiRequestActive && true == mOdcpiTimer.isActive()) {
+                mOdcpiRequestActive = true;
+            }
+            mOdcpiRequest = request;
+        // the request is being stopped, but allow timer to expire first
+        // before stopping the timer just in case more ODCPI requests come
+        // to avoid spamming more odcpi requests to the framework
+        } else if (ODCPI_REQUEST_TYPE_STOP == request.type) {
+            LOC_LOGd("request: type %d, isEmergency %d", request.type, request.isEmergencyMode);
+            mOdcpiRequestCb(request);
+            mOdcpiRequestActive = false;
+        } else {
+            LOC_LOGE("Invalid ODCPI request type..");
+        }
+    } else {
+        LOC_LOGw("ODCPI request not supported");
+    }
+}
+
+bool GnssAdapter::reportDeleteAidingDataEvent(GnssAidingData& aidingData)
+{
+    LOC_LOGD("%s]:", __func__);
+    mEngHubProxy->gnssDeleteAidingData(aidingData);
+    return true;
+}
+
+bool GnssAdapter::reportKlobucharIonoModelEvent(GnssKlobucharIonoModel & ionoModel)
+{
+    LOC_LOGD("%s]:", __func__);
+    mEngHubProxy->gnssReportKlobucharIonoModel(ionoModel);
+    return true;
+}
+
+bool GnssAdapter::reportGnssAdditionalSystemInfoEvent(
+        GnssAdditionalSystemInfo & additionalSystemInfo)
+{
+    LOC_LOGD("%s]:", __func__);
+    mEngHubProxy->gnssReportAdditionalSystemInfo(additionalSystemInfo);
+    return true;
+}
+
+bool GnssAdapter::reportQwesCapabilities(
+        const std::unordered_map<LocationQwesFeatureType, bool> &featureMap)
+{
+    struct MsgReportQwesFeatureStatus : public LocMsg {
+        GnssAdapter& mAdapter;
+        const std::unordered_map<LocationQwesFeatureType, bool> mFeatureMap;
+        inline MsgReportQwesFeatureStatus(GnssAdapter& adapter,
+                const std::unordered_map<LocationQwesFeatureType, bool> &featureMap) :
+            LocMsg(),
+            mAdapter(adapter),
+            mFeatureMap(std::move(featureMap)) {}
+        inline virtual void proc() const {
+            LOC_LOGi("ReportQwesFeatureStatus before caps %" PRIx64 " ",
+                mAdapter.getCapabilities());
+            ContextBase::setQwesFeatureStatus(mFeatureMap);
+            LOC_LOGi("ReportQwesFeatureStatus After caps %" PRIx64 " ",
+                mAdapter.getCapabilities());
+            mAdapter.broadcastCapabilities(mAdapter.getCapabilities());
+        }
+    };
+
+    sendMsg(new MsgReportQwesFeatureStatus(*this, featureMap));
+    return true;
+}
+
+void GnssAdapter::initOdcpiCommand(const OdcpiRequestCallback& callback,
+                                   OdcpiPrioritytype priority)
+{
+    struct MsgInitOdcpi : public LocMsg {
+        GnssAdapter& mAdapter;
+        OdcpiRequestCallback mOdcpiCb;
+        OdcpiPrioritytype mPriority;
+        inline MsgInitOdcpi(GnssAdapter& adapter,
+                const OdcpiRequestCallback& callback,
+                OdcpiPrioritytype priority) :
+                LocMsg(),
+                mAdapter(adapter),
+                mOdcpiCb(callback), mPriority(priority){}
+        inline virtual void proc() const {
+            mAdapter.initOdcpi(mOdcpiCb, mPriority);
+        }
+    };
+
+    sendMsg(new MsgInitOdcpi(*this, callback, priority));
+}
+
+void GnssAdapter::initOdcpi(const OdcpiRequestCallback& callback,
+            OdcpiPrioritytype priority)
+{
+    LOC_LOGd("In priority: %d, Curr priority: %d", priority, mCallbackPriority);
+    if (priority >= mCallbackPriority) {
+        mOdcpiRequestCb = callback;
+        mCallbackPriority = priority;
+        /* Register for WIFI request */
+        updateEvtMask(LOC_API_ADAPTER_BIT_REQUEST_WIFI,
+                LOC_REGISTRATION_MASK_ENABLED);
+    }
+}
+
+void GnssAdapter::injectOdcpiCommand(const Location& location)
+{
+    struct MsgInjectOdcpi : public LocMsg {
+        GnssAdapter& mAdapter;
+        Location mLocation;
+        inline MsgInjectOdcpi(GnssAdapter& adapter, const Location& location) :
+                LocMsg(),
+                mAdapter(adapter),
+                mLocation(location) {}
+        inline virtual void proc() const {
+            mAdapter.injectOdcpi(mLocation);
+        }
+    };
+
+    sendMsg(new MsgInjectOdcpi(*this, location));
+}
+
+void GnssAdapter::injectOdcpi(const Location& location)
+{
+    LOC_LOGd("ODCPI Injection: requestActive: %d timerActive: %d"
+             "lat %.7f long %.7f",
+            mOdcpiRequestActive, mOdcpiTimer.isActive(),
+            location.latitude, location.longitude);
+
+    mLocApi->injectPosition(location, true);
+}
+
+// Called in the context of LocTimer thread
+void OdcpiTimer::timeOutCallback()
+{
+    if (nullptr != mAdapter) {
+        mAdapter->odcpiTimerExpireEvent();
+    }
+}
+
+// Called in the context of LocTimer thread
+void GnssAdapter::odcpiTimerExpireEvent()
+{
+    struct MsgOdcpiTimerExpire : public LocMsg {
+        GnssAdapter& mAdapter;
+        inline MsgOdcpiTimerExpire(GnssAdapter& adapter) :
+                LocMsg(),
+                mAdapter(adapter) {}
+        inline virtual void proc() const {
+            mAdapter.odcpiTimerExpire();
+        }
+    };
+    sendMsg(new MsgOdcpiTimerExpire(*this));
+}
+void GnssAdapter::odcpiTimerExpire()
+{
+    LOC_LOGd("requestActive: %d timerActive: %d",
+            mOdcpiRequestActive, mOdcpiTimer.isActive());
+
+    // if ODCPI request is still active after timer
+    // expires, request again and restart timer
+    if (mOdcpiRequestActive) {
+        mOdcpiRequestCb(mOdcpiRequest);
+        mOdcpiTimer.restart();
+    } else {
+        mOdcpiTimer.stop();
+    }
+}
+
+void
+GnssAdapter::invokeGnssEnergyConsumedCallback(uint64_t energyConsumedSinceFirstBoot) {
+    if (mGnssEnergyConsumedCb) {
+        mGnssEnergyConsumedCb(energyConsumedSinceFirstBoot);
+        mGnssEnergyConsumedCb = nullptr;
+    }
+}
+
+bool
+GnssAdapter::reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot){
+    LOC_LOGD("%s]: %" PRIu64 " ", __func__, energyConsumedSinceFirstBoot);
+
+    struct MsgReportGnssGnssEngEnergyConsumed : public LocMsg {
+        GnssAdapter& mAdapter;
+        uint64_t mGnssEnergyConsumedSinceFirstBoot;
+        inline MsgReportGnssGnssEngEnergyConsumed(GnssAdapter& adapter,
+                                                  uint64_t energyConsumed) :
+                LocMsg(),
+                mAdapter(adapter),
+                mGnssEnergyConsumedSinceFirstBoot(energyConsumed) {}
+        inline virtual void proc() const {
+            mAdapter.invokeGnssEnergyConsumedCallback(mGnssEnergyConsumedSinceFirstBoot);
+        }
+    };
+
+    sendMsg(new MsgReportGnssGnssEngEnergyConsumed(*this, energyConsumedSinceFirstBoot));
+    return true;
+}
+
+void GnssAdapter::initDefaultAgps() {
+    LOC_LOGD("%s]: ", __func__);
+    void *handle = nullptr;
+
+    LocAgpsGetAgpsCbInfo getAgpsCbInfo =
+        (LocAgpsGetAgpsCbInfo)dlGetSymFromLib(handle, "libloc_net_iface.so",
+            "LocNetIfaceAgps_getAgpsCbInfo");
+    // Below step is to make sure we init nativeAgpsHandler
+    // for Android platforms only
+    AgpsCbInfo cbInfo = {};
+    if (nullptr != getAgpsCbInfo) {
+        cbInfo = getAgpsCbInfo(agpsOpenResultCb, agpsCloseResultCb, this);
+    } else {
+        cbInfo = mNativeAgpsHandler.getAgpsCbInfo();
+    }
+
+    if (cbInfo.statusV4Cb == nullptr) {
+        LOC_LOGE("%s]: statusV4Cb is nullptr!", __func__);
+        dlclose(handle);
+        return;
+    }
+
+    initAgps(cbInfo);
+}
+
+void GnssAdapter::initDefaultAgpsCommand() {
+    LOC_LOGD("%s]: ", __func__);
+
+    struct MsgInitDefaultAgps : public LocMsg {
+        GnssAdapter& mAdapter;
+        inline MsgInitDefaultAgps(GnssAdapter& adapter) :
+            LocMsg(),
+            mAdapter(adapter) {
+            }
+        inline virtual void proc() const {
+            mAdapter.initDefaultAgps();
+        }
+    };
+
+    sendMsg(new MsgInitDefaultAgps(*this));
+}
+
+/* INIT LOC AGPS MANAGER */
+
+void GnssAdapter::initAgps(const AgpsCbInfo& cbInfo) {
+    LOC_LOGD("%s]:cbInfo.atlType - %d", __func__, cbInfo.atlType);
+
+    if (!((ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSB) ||
+            (ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSA))) {
+        return;
+    }
+
+    mAgpsManager.createAgpsStateMachines(cbInfo);
+    /* Register for AGPS event mask */
+    updateEvtMask(LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST,
+            LOC_REGISTRATION_MASK_ENABLED);
+}
+
+void GnssAdapter::initAgpsCommand(const AgpsCbInfo& cbInfo){
+    LOC_LOGI("GnssAdapter::initAgpsCommand");
+
+    /* Message to initialize AGPS module */
+    struct AgpsMsgInit: public LocMsg {
+        const AgpsCbInfo mCbInfo;
+        GnssAdapter& mAdapter;
+
+        inline AgpsMsgInit(const AgpsCbInfo& cbInfo,
+                GnssAdapter& adapter) :
+                LocMsg(), mCbInfo(cbInfo), mAdapter(adapter) {
+            LOC_LOGV("AgpsMsgInit");
+        }
+
+        inline virtual void proc() const {
+            LOC_LOGV("AgpsMsgInit::proc()");
+            mAdapter.initAgps(mCbInfo);
+        }
+    };
+
+    /* Send message to initialize AGPS Manager */
+    sendMsg(new AgpsMsgInit(cbInfo, *this));
+}
+
+void GnssAdapter::initNfwCommand(const NfwCbInfo& cbInfo) {
+    LOC_LOGi("GnssAdapter::initNfwCommand");
+
+    /* Message to initialize NFW */
+    struct MsgInitNfw : public LocMsg {
+        const NfwCbInfo mCbInfo;
+        GnssAdapter& mAdapter;
+
+        inline MsgInitNfw(const NfwCbInfo& cbInfo,
+            GnssAdapter& adapter) :
+            LocMsg(), mCbInfo(cbInfo), mAdapter(adapter) {
+            LOC_LOGv("MsgInitNfw");
+        }
+
+        inline virtual void proc() const {
+            LOC_LOGv("MsgInitNfw::proc()");
+            mAdapter.initNfw(mCbInfo);
+        }
+    };
+
+    /* Send message to initialize NFW */
+    sendMsg(new MsgInitNfw(cbInfo, *this));
+}
+
+void GnssAdapter::reportNfwNotificationEvent(GnssNfwNotification& notification) {
+    LOC_LOGi("GnssAdapter::reportNfwNotificationEvent");
+
+    struct MsgReportNfwNotification : public LocMsg {
+        const GnssNfwNotification mNotification;
+        GnssAdapter& mAdapter;
+
+        inline MsgReportNfwNotification(const GnssNfwNotification& notification,
+            GnssAdapter& adapter) :
+            LocMsg(), mNotification(notification), mAdapter(adapter) {
+            LOC_LOGv("MsgReportNfwNotification");
+        }
+
+        inline virtual void proc() const {
+            LOC_LOGv("MsgReportNfwNotification::proc()");
+            mAdapter.reportNfwNotification(mNotification);
+        }
+    };
+
+    sendMsg(new MsgReportNfwNotification(notification, *this));
+}
+
+/* GnssAdapter::requestATL
+ * Method triggered in QMI thread as part of handling below message:
+ * eQMI_LOC_SERVER_REQUEST_OPEN_V02
+ * Triggers the AGPS state machine to setup AGPS call for below WWAN types:
+ * eQMI_LOC_WWAN_TYPE_INTERNET_V02
+ * eQMI_LOC_WWAN_TYPE_AGNSS_V02
+ * eQMI_LOC_WWAN_TYPE_AGNSS_EMERGENCY_V02 */
+bool GnssAdapter::requestATL(int connHandle, LocAGpsType agpsType,
+                             LocApnTypeMask apnTypeMask){
+
+    LOC_LOGI("GnssAdapter::requestATL handle=%d agpsType=0x%X apnTypeMask=0x%X",
+        connHandle, agpsType, apnTypeMask);
+
+    sendMsg( new AgpsMsgRequestATL(
+             &mAgpsManager, connHandle, (AGpsExtType)agpsType,
+             apnTypeMask));
+
+    return true;
+}
+
+/* GnssAdapter::releaseATL
+ * Method triggered in QMI thread as part of handling below message:
+ * eQMI_LOC_SERVER_REQUEST_CLOSE_V02
+ * Triggers teardown of an existing AGPS call */
+bool GnssAdapter::releaseATL(int connHandle){
+
+    LOC_LOGI("GnssAdapter::releaseATL");
+
+    /* Release SUPL/INTERNET/SUPL_ES ATL */
+    struct AgpsMsgReleaseATL: public LocMsg {
+
+        AgpsManager* mAgpsManager;
+        int mConnHandle;
+
+        inline AgpsMsgReleaseATL(AgpsManager* agpsManager, int connHandle) :
+                LocMsg(), mAgpsManager(agpsManager), mConnHandle(connHandle) {
+
+            LOC_LOGV("AgpsMsgReleaseATL");
+        }
+
+        inline virtual void proc() const {
+
+            LOC_LOGV("AgpsMsgReleaseATL::proc()");
+            mAgpsManager->releaseATL(mConnHandle);
+        }
+    };
+
+    sendMsg( new AgpsMsgReleaseATL(&mAgpsManager, connHandle));
+
+    return true;
+}
+
+void GnssAdapter::reportPdnTypeFromWds(int pdnType, AGpsExtType agpsType, std::string apnName,
+        AGpsBearerType bearerType) {
+    LOC_LOGd("pdnType from WDS QMI: %d, agpsType: %d, apnName: %s, bearerType: %d",
+            pdnType, agpsType, apnName.c_str(), bearerType);
+
+    struct MsgReportAtlPdn : public LocMsg {
+        GnssAdapter& mAdapter;
+        int mPdnType;
+        AgpsManager* mAgpsManager;
+        AGpsExtType mAgpsType;
+        string mApnName;
+        AGpsBearerType mBearerType;
+
+        inline MsgReportAtlPdn(GnssAdapter& adapter, int pdnType,
+                AgpsManager* agpsManager, AGpsExtType agpsType,
+                const string& apnName, AGpsBearerType bearerType) :
+            LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType),
+            mApnName(apnName), mBearerType(bearerType),
+            mAdapter(adapter), mPdnType(pdnType) {}
+        inline virtual void proc() const {
+            mAgpsManager->reportAtlOpenSuccess(mAgpsType,
+                    const_cast<char*>(mApnName.c_str()),
+                    mApnName.length(), mPdnType<=0? mBearerType:mPdnType);
+        }
+    };
+
+    AGpsBearerType atlPdnType = (pdnType+1) & 3; // convert WDS QMI pdn type to AgpsBearerType
+    sendMsg(new MsgReportAtlPdn(*this, atlPdnType, &mAgpsManager,
+                agpsType, apnName, bearerType));
+}
+
+
+void GnssAdapter::dataConnOpenCommand(
+        AGpsExtType agpsType,
+        const char* apnName, int apnLen, AGpsBearerType bearerType){
+
+    LOC_LOGI("GnssAdapter::frameworkDataConnOpen");
+
+    struct AgpsMsgAtlOpenSuccess: public LocMsg {
+        GnssAdapter& mAdapter;
+        AgpsManager* mAgpsManager;
+        AGpsExtType mAgpsType;
+        char* mApnName;
+        AGpsBearerType mBearerType;
+
+        inline AgpsMsgAtlOpenSuccess(GnssAdapter& adapter, AgpsManager* agpsManager,
+                AGpsExtType agpsType, const char* apnName, int apnLen, AGpsBearerType bearerType) :
+                LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType), mApnName(
+                        new char[apnLen + 1]), mBearerType(bearerType), mAdapter(adapter) {
+
+            LOC_LOGV("AgpsMsgAtlOpenSuccess");
+            if (mApnName == nullptr) {
+                LOC_LOGE("%s] new allocation failed, fatal error.", __func__);
+                // Reporting the failure here
+                mAgpsManager->reportAtlClosed(mAgpsType);
+                return;
+            }
+            memcpy(mApnName, apnName, apnLen);
+            mApnName[apnLen] = 0;
+        }
+
+        inline ~AgpsMsgAtlOpenSuccess() {
+            delete[] mApnName;
+        }
+
+        inline virtual void proc() const {
+            LOC_LOGv("AgpsMsgAtlOpenSuccess::proc()");
+            string apn(mApnName);
+            //Use QMI WDS API to query IP Protocol from modem profile
+            void* libHandle = nullptr;
+            getPdnTypeFromWds* getPdnTypeFunc = (getPdnTypeFromWds*)dlGetSymFromLib(libHandle,
+            #ifdef USE_GLIB
+                    "libloc_api_wds.so", "_Z10getPdnTypeRKNSt7__cxx1112basic_string"\
+                    "IcSt11char_traitsIcESaIcEEESt8functionIFviEE");
+            #else
+                    "libloc_api_wds.so", "_Z10getPdnTypeRKNSt3__112basic_stringIcNS_11char_traits"\
+                    "IcEENS_9allocatorIcEEEENS_8functionIFviEEE");
+            #endif
+
+            std::function<void(int)> wdsPdnTypeCb = std::bind(&GnssAdapter::reportPdnTypeFromWds,
+                    &mAdapter, std::placeholders::_1, mAgpsType, apn, mBearerType);
+           if (getPdnTypeFunc != nullptr) {
+               LOC_LOGv("dlGetSymFromLib success");
+               (*getPdnTypeFunc)(apn, wdsPdnTypeCb);
+           } else {
+               mAgpsManager->reportAtlOpenSuccess(mAgpsType, mApnName, apn.length(), mBearerType);
+           }
+        }
+    };
+    // Added inital length checks for apnlen check to avoid security issues
+    // In case of failure reporting the same
+    if (NULL == apnName || apnLen > MAX_APN_LEN || (strlen(apnName) != apnLen)) {
+        LOC_LOGe("%s]: incorrect apnlen length or incorrect apnName", __func__);
+        mAgpsManager.reportAtlClosed(agpsType);
+    } else {
+        sendMsg( new AgpsMsgAtlOpenSuccess(*this,
+                    &mAgpsManager, agpsType, apnName, apnLen, bearerType));
+    }
+}
+
+void GnssAdapter::dataConnClosedCommand(AGpsExtType agpsType){
+
+    LOC_LOGI("GnssAdapter::frameworkDataConnClosed");
+
+    struct AgpsMsgAtlClosed: public LocMsg {
+
+        AgpsManager* mAgpsManager;
+        AGpsExtType mAgpsType;
+
+        inline AgpsMsgAtlClosed(AgpsManager* agpsManager, AGpsExtType agpsType) :
+                LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType) {
+
+            LOC_LOGV("AgpsMsgAtlClosed");
+        }
+
+        inline virtual void proc() const {
+
+            LOC_LOGV("AgpsMsgAtlClosed::proc()");
+            mAgpsManager->reportAtlClosed(mAgpsType);
+        }
+    };
+
+    sendMsg( new AgpsMsgAtlClosed(&mAgpsManager, (AGpsExtType)agpsType));
+}
+
+void GnssAdapter::dataConnFailedCommand(AGpsExtType agpsType){
+
+    LOC_LOGI("GnssAdapter::frameworkDataConnFailed");
+
+    struct AgpsMsgAtlOpenFailed: public LocMsg {
+
+        AgpsManager* mAgpsManager;
+        AGpsExtType mAgpsType;
+
+        inline AgpsMsgAtlOpenFailed(AgpsManager* agpsManager, AGpsExtType agpsType) :
+                LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType) {
+
+            LOC_LOGV("AgpsMsgAtlOpenFailed");
+        }
+
+        inline virtual void proc() const {
+
+            LOC_LOGV("AgpsMsgAtlOpenFailed::proc()");
+            mAgpsManager->reportAtlOpenFailed(mAgpsType);
+        }
+    };
+
+    sendMsg( new AgpsMsgAtlOpenFailed(&mAgpsManager, (AGpsExtType)agpsType));
+}
+
+void GnssAdapter::convertSatelliteInfo(std::vector<GnssDebugSatelliteInfo>& out,
+                                       const GnssSvType& in_constellation,
+                                       const SystemStatusReports& in)
+{
+    uint64_t sv_mask = 0ULL;
+    uint32_t svid_min = 0;
+    uint32_t svid_num = 0;
+    uint32_t svid_idx = 0;
+
+    uint64_t eph_health_good_mask = 0ULL;
+    uint64_t eph_health_bad_mask = 0ULL;
+    uint64_t server_perdiction_available_mask = 0ULL;
+    float server_perdiction_age = 0.0f;
+
+    // set constellationi based parameters
+    switch (in_constellation) {
+        case GNSS_SV_TYPE_GPS:
+            svid_min = GNSS_BUGREPORT_GPS_MIN;
+            svid_num = GPS_NUM;
+            svid_idx = 0;
+            if (!in.mSvHealth.empty()) {
+                eph_health_good_mask = in.mSvHealth.back().mGpsGoodMask;
+                eph_health_bad_mask  = in.mSvHealth.back().mGpsBadMask;
+            }
+            if (!in.mXtra.empty()) {
+                server_perdiction_available_mask = in.mXtra.back().mGpsXtraValid;
+                server_perdiction_age = (float)(in.mXtra.back().mGpsXtraAge);
+            }
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            svid_min = GNSS_BUGREPORT_GLO_MIN;
+            svid_num = GLO_NUM;
+            svid_idx = GPS_NUM;
+            if (!in.mSvHealth.empty()) {
+                eph_health_good_mask = in.mSvHealth.back().mGloGoodMask;
+                eph_health_bad_mask  = in.mSvHealth.back().mGloBadMask;
+            }
+            if (!in.mXtra.empty()) {
+                server_perdiction_available_mask = in.mXtra.back().mGloXtraValid;
+                server_perdiction_age = (float)(in.mXtra.back().mGloXtraAge);
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            svid_min = GNSS_BUGREPORT_QZSS_MIN;
+            svid_num = QZSS_NUM;
+            svid_idx = GPS_NUM+GLO_NUM+BDS_NUM+GAL_NUM;
+            if (!in.mSvHealth.empty()) {
+                eph_health_good_mask = in.mSvHealth.back().mQzssGoodMask;
+                eph_health_bad_mask  = in.mSvHealth.back().mQzssBadMask;
+            }
+            if (!in.mXtra.empty()) {
+                server_perdiction_available_mask = in.mXtra.back().mQzssXtraValid;
+                server_perdiction_age = (float)(in.mXtra.back().mQzssXtraAge);
+            }
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            svid_min = GNSS_BUGREPORT_BDS_MIN;
+            svid_num = BDS_NUM;
+            svid_idx = GPS_NUM+GLO_NUM;
+            if (!in.mSvHealth.empty()) {
+                eph_health_good_mask = in.mSvHealth.back().mBdsGoodMask;
+                eph_health_bad_mask  = in.mSvHealth.back().mBdsBadMask;
+            }
+            if (!in.mXtra.empty()) {
+                server_perdiction_available_mask = in.mXtra.back().mBdsXtraValid;
+                server_perdiction_age = (float)(in.mXtra.back().mBdsXtraAge);
+            }
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            svid_min = GNSS_BUGREPORT_GAL_MIN;
+            svid_num = GAL_NUM;
+            svid_idx = GPS_NUM+GLO_NUM+BDS_NUM;
+            if (!in.mSvHealth.empty()) {
+                eph_health_good_mask = in.mSvHealth.back().mGalGoodMask;
+                eph_health_bad_mask  = in.mSvHealth.back().mGalBadMask;
+            }
+            if (!in.mXtra.empty()) {
+                server_perdiction_available_mask = in.mXtra.back().mGalXtraValid;
+                server_perdiction_age = (float)(in.mXtra.back().mGalXtraAge);
+            }
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            svid_min = GNSS_BUGREPORT_NAVIC_MIN;
+            svid_num = NAVIC_NUM;
+            svid_idx = GPS_NUM+GLO_NUM+QZSS_NUM+BDS_NUM+GAL_NUM;
+            if (!in.mSvHealth.empty()) {
+                eph_health_good_mask = in.mSvHealth.back().mNavicGoodMask;
+                eph_health_bad_mask  = in.mSvHealth.back().mNavicBadMask;
+            }
+            if (!in.mXtra.empty()) {
+                server_perdiction_available_mask = in.mXtra.back().mNavicXtraValid;
+                server_perdiction_age = (float)(in.mXtra.back().mNavicXtraAge);
+            }
+            break;
+        default:
+            return;
+    }
+
+    // extract each sv info from systemstatus report
+    for(uint32_t i=0; i<svid_num && (svid_idx+i)<SV_ALL_NUM; i++) {
+
+        GnssDebugSatelliteInfo s = {};
+        s.size = sizeof(s);
+        s.svid = i + svid_min;
+        s.constellation = in_constellation;
+
+        if (!in.mNavData.empty()) {
+            s.mEphemerisType   = in.mNavData.back().mNav[svid_idx+i].mType;
+            s.mEphemerisSource = in.mNavData.back().mNav[svid_idx+i].mSource;
+        }
+        else {
+            s.mEphemerisType   = GNSS_EPH_TYPE_UNKNOWN;
+            s.mEphemerisSource = GNSS_EPH_SOURCE_UNKNOWN;
+        }
+
+        sv_mask = 0x1ULL << i;
+        if (eph_health_good_mask & sv_mask) {
+            s.mEphemerisHealth = GNSS_EPH_HEALTH_GOOD;
+        }
+        else if (eph_health_bad_mask & sv_mask) {
+            s.mEphemerisHealth = GNSS_EPH_HEALTH_BAD;
+        }
+        else {
+            s.mEphemerisHealth = GNSS_EPH_HEALTH_UNKNOWN;
+        }
+
+        if (!in.mNavData.empty()) {
+            s.ephemerisAgeSeconds =
+                (float)(in.mNavData.back().mNav[svid_idx+i].mAgeSec);
+        }
+        else {
+            s.ephemerisAgeSeconds = 0.0f;
+        }
+
+        if (server_perdiction_available_mask & sv_mask) {
+            s.serverPredictionIsAvailable = true;
+        }
+        else {
+            s.serverPredictionIsAvailable = false;
+        }
+
+        s.serverPredictionAgeSeconds = server_perdiction_age;
+        out.push_back(s);
+    }
+
+    return;
+}
+
+bool GnssAdapter::getDebugReport(GnssDebugReport& r)
+{
+    LOC_LOGD("%s]: ", __func__);
+
+    SystemStatus* systemstatus = getSystemStatus();
+    if (nullptr == systemstatus) {
+        return false;
+    }
+
+    SystemStatusReports reports = {};
+    systemstatus->getReport(reports, true);
+
+    r.size = sizeof(r);
+
+    // location block
+    r.mLocation.size = sizeof(r.mLocation);
+    if(!reports.mLocation.empty() && reports.mLocation.back().mValid) {
+        r.mLocation.mValid = true;
+        r.mLocation.mLocation.latitude =
+            reports.mLocation.back().mLocation.gpsLocation.latitude;
+        r.mLocation.mLocation.longitude =
+            reports.mLocation.back().mLocation.gpsLocation.longitude;
+        r.mLocation.mLocation.altitude =
+            reports.mLocation.back().mLocation.gpsLocation.altitude;
+        r.mLocation.mLocation.speed =
+            (double)(reports.mLocation.back().mLocation.gpsLocation.speed);
+        r.mLocation.mLocation.bearing =
+            (double)(reports.mLocation.back().mLocation.gpsLocation.bearing);
+        r.mLocation.mLocation.accuracy =
+            (double)(reports.mLocation.back().mLocation.gpsLocation.accuracy);
+
+        r.mLocation.verticalAccuracyMeters =
+            reports.mLocation.back().mLocationEx.vert_unc;
+        r.mLocation.speedAccuracyMetersPerSecond =
+            reports.mLocation.back().mLocationEx.speed_unc;
+        r.mLocation.bearingAccuracyDegrees =
+            reports.mLocation.back().mLocationEx.bearing_unc;
+
+        r.mLocation.mUtcReported =
+            reports.mLocation.back().mUtcReported;
+    }
+    else if(!reports.mBestPosition.empty() && reports.mBestPosition.back().mValid) {
+        r.mLocation.mValid = true;
+        r.mLocation.mLocation.latitude =
+                (double)(reports.mBestPosition.back().mBestLat) * RAD2DEG;
+        r.mLocation.mLocation.longitude =
+                (double)(reports.mBestPosition.back().mBestLon) * RAD2DEG;
+        r.mLocation.mLocation.altitude = reports.mBestPosition.back().mBestAlt;
+        r.mLocation.mLocation.accuracy =
+                (double)(reports.mBestPosition.back().mBestHepe);
+
+        r.mLocation.mUtcReported = reports.mBestPosition.back().mUtcReported;
+    }
+    else {
+        r.mLocation.mValid = false;
+    }
+
+    if (r.mLocation.mValid) {
+        LOC_LOGV("getDebugReport - lat=%f lon=%f alt=%f speed=%f",
+            r.mLocation.mLocation.latitude,
+            r.mLocation.mLocation.longitude,
+            r.mLocation.mLocation.altitude,
+            r.mLocation.mLocation.speed);
+    }
+
+    // time block
+    r.mTime.size = sizeof(r.mTime);
+    if(!reports.mTimeAndClock.empty() && reports.mTimeAndClock.back().mTimeValid) {
+        r.mTime.mValid = true;
+        r.mTime.timeEstimate =
+            (((int64_t)(reports.mTimeAndClock.back().mGpsWeek)*7 +
+                        GNSS_UTC_TIME_OFFSET)*24*60*60 -
+              (int64_t)(reports.mTimeAndClock.back().mLeapSeconds))*1000ULL +
+              (int64_t)(reports.mTimeAndClock.back().mGpsTowMs);
+
+        if (reports.mTimeAndClock.back().mTimeUncNs > 0) {
+            // TimeUncNs value is available
+            r.mTime.timeUncertaintyNs =
+                    (float)(reports.mTimeAndClock.back().mLeapSecUnc)*1000.0f +
+                    (float)(reports.mTimeAndClock.back().mTimeUncNs);
+        } else {
+            // fall back to legacy TimeUnc
+            r.mTime.timeUncertaintyNs =
+                    ((float)(reports.mTimeAndClock.back().mTimeUnc) +
+                     (float)(reports.mTimeAndClock.back().mLeapSecUnc))*1000.0f;
+        }
+
+        r.mTime.frequencyUncertaintyNsPerSec =
+            (float)(reports.mTimeAndClock.back().mClockFreqBiasUnc);
+        LOC_LOGV("getDebugReport - timeestimate=%" PRIu64 " unc=%f frequnc=%f",
+                r.mTime.timeEstimate,
+                r.mTime.timeUncertaintyNs, r.mTime.frequencyUncertaintyNsPerSec);
+    }
+    else {
+        r.mTime.mValid = false;
+    }
+
+    // satellite info block
+    convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_GPS, reports);
+    convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_GLONASS, reports);
+    convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_QZSS, reports);
+    convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_BEIDOU, reports);
+    convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_GALILEO, reports);
+    convertSatelliteInfo(r.mSatelliteInfo, GNSS_SV_TYPE_NAVIC, reports);
+    LOC_LOGV("getDebugReport - satellite=%zu", r.mSatelliteInfo.size());
+
+    return true;
+}
+
+/* get AGC information from system status and fill it */
+void
+GnssAdapter::getAgcInformation(GnssMeasurementsNotification& measurements, int msInWeek)
+{
+    SystemStatus* systemstatus = getSystemStatus();
+
+    if (nullptr != systemstatus) {
+        SystemStatusReports reports = {};
+        systemstatus->getReport(reports, true);
+
+        if ((!reports.mRfAndParams.empty()) && (!reports.mTimeAndClock.empty()) &&
+            (abs(msInWeek - (int)reports.mTimeAndClock.back().mGpsTowMs) < 2000)) {
+
+            for (size_t i = 0; i < measurements.count; i++) {
+                switch (measurements.measurements[i].svType) {
+                case GNSS_SV_TYPE_GPS:
+                case GNSS_SV_TYPE_QZSS:
+                    measurements.measurements[i].agcLevelDb =
+                            reports.mRfAndParams.back().mAgcGps;
+                    measurements.measurements[i].flags |=
+                            GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT;
+                    break;
+
+                case GNSS_SV_TYPE_GALILEO:
+                    measurements.measurements[i].agcLevelDb =
+                            reports.mRfAndParams.back().mAgcGal;
+                    measurements.measurements[i].flags |=
+                            GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT;
+                    break;
+
+                case GNSS_SV_TYPE_GLONASS:
+                    measurements.measurements[i].agcLevelDb =
+                            reports.mRfAndParams.back().mAgcGlo;
+                    measurements.measurements[i].flags |=
+                            GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT;
+                    break;
+
+                case GNSS_SV_TYPE_BEIDOU:
+                    measurements.measurements[i].agcLevelDb =
+                            reports.mRfAndParams.back().mAgcBds;
+                    measurements.measurements[i].flags |=
+                            GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT;
+                    break;
+
+                case GNSS_SV_TYPE_SBAS:
+                case GNSS_SV_TYPE_UNKNOWN:
+                default:
+                    break;
+                }
+            }
+        }
+    }
+}
+
+/* get Data information from system status and fill it */
+void
+GnssAdapter::getDataInformation(GnssDataNotification& data, int msInWeek)
+{
+    SystemStatus* systemstatus = getSystemStatus();
+
+    LOC_LOGV("%s]: msInWeek=%d", __func__, msInWeek);
+    if (nullptr != systemstatus) {
+        SystemStatusReports reports = {};
+        systemstatus->getReport(reports, true);
+
+        if ((!reports.mRfAndParams.empty()) && (!reports.mTimeAndClock.empty()) &&
+            (abs(msInWeek - (int)reports.mTimeAndClock.back().mGpsTowMs) < 2000)) {
+
+            for (int sig = GNSS_LOC_SIGNAL_TYPE_GPS_L1CA;
+                 sig < GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES; sig++) {
+                data.gnssDataMask[sig] = 0;
+                data.jammerInd[sig] = 0.0;
+                data.agc[sig] = 0.0;
+            }
+            if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mAgcGps) {
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GPS_L1CA] |=
+                        GNSS_LOC_DATA_AGC_BIT;
+                data.agc[GNSS_LOC_SIGNAL_TYPE_GPS_L1CA] =
+                        reports.mRfAndParams.back().mAgcGps;
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA] |=
+                        GNSS_LOC_DATA_AGC_BIT;
+                data.agc[GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA] =
+                        reports.mRfAndParams.back().mAgcGps;
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA] |=
+                        GNSS_LOC_DATA_AGC_BIT;
+                data.agc[GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA] =
+                    reports.mRfAndParams.back().mAgcGps;
+            }
+            if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mJammerGps) {
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GPS_L1CA] |=
+                        GNSS_LOC_DATA_JAMMER_IND_BIT;
+                data.jammerInd[GNSS_LOC_SIGNAL_TYPE_GPS_L1CA] =
+                        (double)reports.mRfAndParams.back().mJammerGps;
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA] |=
+                        GNSS_LOC_DATA_JAMMER_IND_BIT;
+                data.jammerInd[GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA] =
+                        (double)reports.mRfAndParams.back().mJammerGps;
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA] |=
+                        GNSS_LOC_DATA_JAMMER_IND_BIT;
+                data.jammerInd[GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA] =
+                    (double)reports.mRfAndParams.back().mJammerGps;
+            }
+            if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mAgcGlo) {
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GLONASS_G1] |=
+                        GNSS_LOC_DATA_AGC_BIT;
+                data.agc[GNSS_LOC_SIGNAL_TYPE_GLONASS_G1] =
+                        reports.mRfAndParams.back().mAgcGlo;
+            }
+            if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mJammerGlo) {
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GLONASS_G1] |=
+                        GNSS_LOC_DATA_JAMMER_IND_BIT;
+                data.jammerInd[GNSS_LOC_SIGNAL_TYPE_GLONASS_G1] =
+                        (double)reports.mRfAndParams.back().mJammerGlo;
+            }
+            if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mAgcBds) {
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I] |=
+                        GNSS_LOC_DATA_AGC_BIT;
+                data.agc[GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I] =
+                        reports.mRfAndParams.back().mAgcBds;
+            }
+            if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mJammerBds) {
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I] |=
+                        GNSS_LOC_DATA_JAMMER_IND_BIT;
+                data.jammerInd[GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I] =
+                        (double)reports.mRfAndParams.back().mJammerBds;
+            }
+            if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mAgcGal) {
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C] |=
+                        GNSS_LOC_DATA_AGC_BIT;
+                data.agc[GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C] =
+                        reports.mRfAndParams.back().mAgcGal;
+            }
+            if (GNSS_INVALID_JAMMER_IND != reports.mRfAndParams.back().mJammerGal) {
+                data.gnssDataMask[GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C] |=
+                        GNSS_LOC_DATA_JAMMER_IND_BIT;
+                data.jammerInd[GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C] =
+                        (double)reports.mRfAndParams.back().mJammerGal;
+            }
+        }
+    }
+}
+
+/* Callbacks registered with loc_net_iface library */
+static void agpsOpenResultCb (bool isSuccess, AGpsExtType agpsType, const char* apn,
+        AGpsBearerType bearerType, void* userDataPtr) {
+    LOC_LOGD("%s]: ", __func__);
+    if (userDataPtr == nullptr) {
+        LOC_LOGE("%s]: userDataPtr is nullptr.", __func__);
+        return;
+    }
+    if (apn == nullptr) {
+        LOC_LOGE("%s]: apn is nullptr.", __func__);
+        return;
+    }
+    GnssAdapter* adapter = (GnssAdapter*)userDataPtr;
+    if (isSuccess) {
+        adapter->dataConnOpenCommand(agpsType, apn, strlen(apn), bearerType);
+    } else {
+        adapter->dataConnFailedCommand(agpsType);
+    }
+}
+
+static void agpsCloseResultCb (bool isSuccess, AGpsExtType agpsType, void* userDataPtr) {
+    LOC_LOGD("%s]: ", __func__);
+    if (userDataPtr == nullptr) {
+        LOC_LOGE("%s]: userDataPtr is nullptr.", __func__);
+        return;
+    }
+    GnssAdapter* adapter = (GnssAdapter*)userDataPtr;
+    if (isSuccess) {
+        adapter->dataConnClosedCommand(agpsType);
+    } else {
+        adapter->dataConnFailedCommand(agpsType);
+    }
+}
+
+void
+GnssAdapter::saveGnssEnergyConsumedCallback(GnssEnergyConsumedCallback energyConsumedCb) {
+    mGnssEnergyConsumedCb = energyConsumedCb;
+}
+
+void
+GnssAdapter::getGnssEnergyConsumedCommand(GnssEnergyConsumedCallback energyConsumedCb) {
+    struct MsgGetGnssEnergyConsumed : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        GnssEnergyConsumedCallback mEnergyConsumedCb;
+        inline MsgGetGnssEnergyConsumed(GnssAdapter& adapter, LocApiBase& api,
+                                        GnssEnergyConsumedCallback energyConsumedCb) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mEnergyConsumedCb(energyConsumedCb){}
+        inline virtual void proc() const {
+            mAdapter.saveGnssEnergyConsumedCallback(mEnergyConsumedCb);
+            mApi.getGnssEnergyConsumed();
+        }
+    };
+
+    sendMsg(new MsgGetGnssEnergyConsumed(*this, *mLocApi, energyConsumedCb));
+}
+
+void
+GnssAdapter::nfwControlCommand(bool enable) {
+    struct MsgControlNfwLocationAccess : public LocMsg {
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+        bool mEnable;
+        inline MsgControlNfwLocationAccess(GnssAdapter& adapter, LocApiBase& api,
+            bool enable) :
+            LocMsg(),
+            mAdapter(adapter),
+            mApi(api),
+            mEnable(enable) {}
+        inline virtual void proc() const {
+            GnssConfigGpsLock gpsLock;
+
+            gpsLock = ContextBase::mGps_conf.GPS_LOCK;
+            if (mEnable) {
+                gpsLock &= ~GNSS_CONFIG_GPS_LOCK_NI;
+            } else {
+                gpsLock |= GNSS_CONFIG_GPS_LOCK_NI;
+            }
+            ContextBase::mGps_conf.GPS_LOCK = gpsLock;
+            mApi.sendMsg(new LocApiMsg([&mApi = mApi, gpsLock]() {
+                mApi.setGpsLockSync((GnssConfigGpsLock)gpsLock);
+            }));
+        }
+    };
+
+    if (mSupportNfwControl) {
+        sendMsg(new MsgControlNfwLocationAccess(*this, *mLocApi, enable));
+    } else {
+        LOC_LOGw("NFW control is not supported, do not use this for NFW");
+    }
+}
+
+// Set tunc constrained mode, use 0 session id to indicate
+// that no callback is needed. Session id 0 is used for calls that
+// are not invoked from the integration api, e.g.: initial configuration
+// from the configure file
+void
+GnssAdapter::setConstrainedTunc(bool enable, float tuncConstraint,
+                                uint32_t energyBudget, uint32_t sessionId) {
+
+    mLocConfigInfo.tuncConfigInfo.isValid = true;
+    mLocConfigInfo.tuncConfigInfo.enable = enable;
+    mLocConfigInfo.tuncConfigInfo.tuncThresholdMs = tuncConstraint;
+    mLocConfigInfo.tuncConfigInfo.energyBudget = energyBudget;
+
+    LocApiResponse* locApiResponse = nullptr;
+    if (sessionId != 0) {
+        locApiResponse =
+                new LocApiResponse(*getContext(),
+                                   [this, sessionId] (LocationError err) {
+                                    reportResponse(err, sessionId);});
+        if (!locApiResponse) {
+            LOC_LOGe("memory alloc failed");
+        }
+    }
+    mLocApi->setConstrainedTuncMode(
+            enable, tuncConstraint, energyBudget, locApiResponse);
+}
+
+uint32_t
+GnssAdapter::setConstrainedTuncCommand (bool enable, float tuncConstraint,
+                                        uint32_t energyBudget) {
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGd("session id %u", sessionId);
+
+    struct MsgEnableTUNC : public LocMsg {
+        GnssAdapter& mAdapter;
+        uint32_t mSessionId;
+        bool mEnable;
+        float mTuncConstraint;
+        uint32_t mEnergyBudget;
+
+        inline MsgEnableTUNC(GnssAdapter& adapter,
+                             uint32_t sessionId,
+                             bool enable,
+                             float tuncConstraint,
+                             uint32_t energyBudget) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mEnable(enable),
+            mTuncConstraint(tuncConstraint),
+            mEnergyBudget(energyBudget) {}
+        inline virtual void proc() const {
+            mAdapter.setConstrainedTunc(mEnable, mTuncConstraint,
+                                        mEnergyBudget, mSessionId);
+        }
+    };
+
+    sendMsg(new MsgEnableTUNC(*this, sessionId, enable,
+                              tuncConstraint, energyBudget));
+
+    return sessionId;
+}
+
+// Set position assisted clock estimator, use 0 session id to indicate
+// that no callback is needed. Session id 0 is used for calls that are
+// not invoked from the integration api, e.g.: initial configuration
+// from the configure file.
+void
+GnssAdapter::setPositionAssistedClockEstimator(bool enable,
+                                               uint32_t sessionId) {
+
+    mLocConfigInfo.paceConfigInfo.isValid = true;
+    mLocConfigInfo.paceConfigInfo.enable = enable;
+    LocApiResponse* locApiResponse = nullptr;
+    if (sessionId != 0) {
+        locApiResponse =
+                new LocApiResponse(*getContext(),
+                                   [this, sessionId] (LocationError err) {
+                                   reportResponse(err, sessionId);});
+        if (!locApiResponse) {
+            LOC_LOGe("memory alloc failed");
+        }
+    }
+    mLocApi->setPositionAssistedClockEstimatorMode(enable, locApiResponse);
+}
+
+uint32_t
+GnssAdapter::setPositionAssistedClockEstimatorCommand(bool enable) {
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGd("session id %u", sessionId);
+
+    struct MsgEnablePACE : public LocMsg {
+        GnssAdapter& mAdapter;
+        uint32_t mSessionId;
+        bool mEnable;
+        inline MsgEnablePACE(GnssAdapter& adapter,
+                             uint32_t sessionId, bool enable) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mEnable(enable){}
+        inline virtual void proc() const {
+            mAdapter.setPositionAssistedClockEstimator(mEnable, mSessionId);
+        }
+    };
+
+    sendMsg(new MsgEnablePACE(*this, sessionId, enable));
+    return sessionId;
+}
+
+void GnssAdapter::gnssUpdateSvConfig(
+        uint32_t sessionId, const GnssSvTypeConfig& constellationEnablementConfig,
+        const GnssSvIdConfig&   blacklistSvConfig) {
+
+    // suspend all tracking sessions to apply the constellation config
+    suspendSessions();
+    if (constellationEnablementConfig.size == sizeof(constellationEnablementConfig)) {
+        // check whether if any constellation is removed from the new config
+        GnssSvTypesMask currentEnabledMask = mGnssSvTypeConfig.enabledSvTypesMask;
+        GnssSvTypesMask newEnabledMask = constellationEnablementConfig.enabledSvTypesMask;
+        GnssSvTypesMask enabledRemoved = currentEnabledMask & (currentEnabledMask ^ newEnabledMask);
+        // Send reset if any constellation is removed from the enabled list
+        if (enabledRemoved != 0) {
+            mLocApi->resetConstellationControl();
+        }
+
+        // if the constellation config is valid, issue request to modem
+        // to enable/disable constellation
+        mLocApi->setConstellationControl(mGnssSvTypeConfig);
+    } else if (constellationEnablementConfig.size == 0) {
+        // when the size is not set, meaning reset to modem default
+        mLocApi->resetConstellationControl();
+    }
+    // save the constellation settings to be used for modem SSR
+    mGnssSvTypeConfig = constellationEnablementConfig;
+
+    // handle blacklisted SV settings
+    mGnssSvIdConfig   = blacklistSvConfig;
+    // process blacklist svs info
+    mBlacklistedSvIds.clear();
+    // need to save the balcklisted sv info into mBlacklistedSvIds as well
+    convertFromGnssSvIdConfig(blacklistSvConfig, mBlacklistedSvIds);
+    LocApiResponse* locApiResponse = new LocApiResponse(*getContext(),
+            [this, sessionId] (LocationError err) {
+            reportResponse(err, sessionId);});
+    if (!locApiResponse) {
+        LOC_LOGe("memory alloc failed");
+    }
+    mLocApi->setBlacklistSv(mGnssSvIdConfig, locApiResponse);
+
+    // resume all tracking sessions after the constellation config has been applied
+    restartSessions(false);
+}
+
+uint32_t
+GnssAdapter::gnssUpdateSvConfigCommand(
+        const GnssSvTypeConfig& constellationEnablementConfig,
+        const GnssSvIdConfig& blacklistSvConfig) {
+
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGd("session id %u", sessionId);
+
+    struct MsgUpdateSvConfig : public LocMsg {
+        GnssAdapter&     mAdapter;
+        uint32_t         mSessionId;
+        GnssSvTypeConfig mConstellationEnablementConfig;
+        GnssSvIdConfig   mBlacklistSvIdConfig;
+
+        inline MsgUpdateSvConfig(GnssAdapter& adapter,
+                                 uint32_t sessionId,
+                                 const GnssSvTypeConfig& constellationEnablementConfig,
+                                 const GnssSvIdConfig& blacklistSvConfig) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mConstellationEnablementConfig(constellationEnablementConfig),
+            mBlacklistSvIdConfig(blacklistSvConfig) {}
+        inline virtual void proc() const {
+            mAdapter.gnssUpdateSvConfig(mSessionId, mConstellationEnablementConfig,
+                                        mBlacklistSvIdConfig);
+        }
+    };
+
+    if (sessionId != 0) {
+        sendMsg(new MsgUpdateSvConfig(*this, sessionId, constellationEnablementConfig,
+                                      blacklistSvConfig));
+    }
+    return sessionId;
+}
+
+void GnssAdapter::gnssUpdateSecondaryBandConfig(
+        uint32_t sessionId, const GnssSvTypeConfig& secondaryBandConfig) {
+
+    LocApiResponse* locApiResponse = new LocApiResponse(*getContext(),
+            [this, sessionId] (LocationError err) {
+            reportResponse(err, sessionId);});
+    if (!locApiResponse) {
+        LOC_LOGe("memory alloc failed");
+    }
+
+    // handle secondary band info
+    mGnssSeconaryBandConfig = secondaryBandConfig;
+    gnssSecondaryBandConfigUpdate(locApiResponse);
+}
+
+uint32_t
+GnssAdapter::gnssUpdateSecondaryBandConfigCommand(
+        const GnssSvTypeConfig& secondaryBandConfig) {
+
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGd("session id %u", sessionId);
+
+    struct MsgUpdateSecondaryBandConfig : public LocMsg {
+        GnssAdapter&     mAdapter;
+        uint32_t         mSessionId;
+        GnssSvTypeConfig mSecondaryBandConfig;
+
+        inline MsgUpdateSecondaryBandConfig(GnssAdapter& adapter,
+                                 uint32_t sessionId,
+                                 const GnssSvTypeConfig& secondaryBandConfig) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mSecondaryBandConfig(secondaryBandConfig) {}
+        inline virtual void proc() const {
+            mAdapter.gnssUpdateSecondaryBandConfig(mSessionId,  mSecondaryBandConfig);
+        }
+    };
+
+    if (sessionId != 0) {
+        sendMsg(new MsgUpdateSecondaryBandConfig(*this, sessionId, secondaryBandConfig));
+    }
+    return sessionId;
+}
+
+// This function currently retrieves secondary band configuration
+// for constellation enablement/disablement.
+void
+GnssAdapter::gnssGetSecondaryBandConfig(uint32_t sessionId) {
+
+    LocApiResponse* locApiResponse = new LocApiResponse(*getContext(),
+            [this, sessionId] (LocationError err) {
+            reportResponse(err, sessionId);});
+    if (!locApiResponse) {
+        LOC_LOGe("memory alloc failed");
+    }
+
+    mLocApi->getConstellationMultiBandConfig(sessionId, locApiResponse);
+}
+
+uint32_t
+GnssAdapter::gnssGetSecondaryBandConfigCommand() {
+
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGd("session id %u", sessionId);
+
+    struct MsgGetSecondaryBandConfig : public LocMsg {
+        GnssAdapter& mAdapter;
+        uint32_t     mSessionId;
+        inline MsgGetSecondaryBandConfig(GnssAdapter& adapter,
+                              uint32_t sessionId) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId) {}
+        inline virtual void proc() const {
+            mAdapter.gnssGetSecondaryBandConfig(mSessionId);
+        }
+    };
+
+    if (sessionId != 0) {
+        sendMsg(new MsgGetSecondaryBandConfig(*this, sessionId));
+    }
+    return sessionId;
+}
+
+void
+GnssAdapter::configLeverArm(uint32_t sessionId,
+                            const LeverArmConfigInfo& configInfo) {
+
+    LocationError err = LOCATION_ERROR_NOT_SUPPORTED;
+    if (true == mEngHubProxy->configLeverArm(configInfo)) {
+        err = LOCATION_ERROR_SUCCESS;
+    }
+    reportResponse(err, sessionId);
+}
+
+uint32_t
+GnssAdapter::configLeverArmCommand(const LeverArmConfigInfo& configInfo) {
+
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGd("session id %u", sessionId);
+
+    struct MsgConfigLeverArm : public LocMsg {
+        GnssAdapter&       mAdapter;
+        uint32_t           mSessionId;
+        LeverArmConfigInfo mConfigInfo;
+
+        inline MsgConfigLeverArm(GnssAdapter& adapter,
+                                 uint32_t sessionId,
+                                 const LeverArmConfigInfo& configInfo) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mConfigInfo(configInfo) {}
+        inline virtual void proc() const {
+            // save the lever ARM config info for translating position from GNSS antenna based
+            // to VRP based
+            if (mConfigInfo.leverArmValidMask & LEVER_ARM_TYPE_GNSS_TO_VRP_BIT) {
+                mAdapter.mLocConfigInfo.leverArmConfigInfo.leverArmValidMask |=
+                        LEVER_ARM_TYPE_GNSS_TO_VRP_BIT;
+                mAdapter.mLocConfigInfo.leverArmConfigInfo.gnssToVRP = mConfigInfo.gnssToVRP;
+            }
+            mAdapter.configLeverArm(mSessionId, mConfigInfo);
+        }
+    };
+
+    sendMsg(new MsgConfigLeverArm(*this, sessionId, configInfo));
+    return sessionId;
+}
+
+bool GnssAdapter::initMeasCorr(bool bSendCbWhenNotSupported) {
+    LOC_LOGv("GnssAdapter::initMeasCorr");
+    /* Message to initialize Measurement Corrections */
+    struct MsgInitMeasCorr : public LocMsg {
+        GnssAdapter& mAdapter;
+        GnssMeasurementCorrectionsCapabilitiesMask mCapMask;
+
+        inline MsgInitMeasCorr(GnssAdapter& adapter,
+                GnssMeasurementCorrectionsCapabilitiesMask capMask) :
+            LocMsg(), mAdapter(adapter), mCapMask(capMask) {
+            LOC_LOGv("MsgInitMeasCorr");
+        }
+
+        inline virtual void proc() const {
+            LOC_LOGv("MsgInitMeasCorr::proc()");
+
+            mAdapter.mMeasCorrSetCapabilitiesCb(mCapMask);
+        }
+    };
+    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_MEASUREMENTS_CORRECTION)) {
+        sendMsg(new MsgInitMeasCorr(*this, GNSS_MEAS_CORR_LOS_SATS |
+                GNSS_MEAS_CORR_EXCESS_PATH_LENGTH | GNSS_MEAS_CORR_REFLECTING_PLANE));
+        return true;
+    } else {
+        LOC_LOGv("MEASUREMENTS_CORRECTION feature is not supported in the modem");
+        if (bSendCbWhenNotSupported) {
+            sendMsg(new MsgInitMeasCorr(*this, 0));
+        }
+        return false;
+    }
+}
+
+bool GnssAdapter::openMeasCorrCommand(const measCorrSetCapabilitiesCb setCapabilitiesCb) {
+    LOC_LOGi("GnssAdapter::openMeasCorrCommand");
+
+    /* Send message to initialize Measurement Corrections */
+        mMeasCorrSetCapabilitiesCb = setCapabilitiesCb;
+        mIsMeasCorrInterfaceOpen = true;
+        if (isEngineCapabilitiesKnown()) {
+        LOC_LOGv("Capabilities are known, proceed with measurement corrections init");
+            return initMeasCorr(false);
+        } else {
+        LOC_LOGv("Capabilities are not known, wait for open");
+            return true;
+        }
+}
+
+bool GnssAdapter::measCorrSetCorrectionsCommand(const GnssMeasurementCorrections gnssMeasCorr) {
+    LOC_LOGi("GnssAdapter::measCorrSetCorrectionsCommand");
+
+    /* Message to set Measurement Corrections */
+    struct MsgSetCorrectionsMeasCorr : public LocMsg {
+        const GnssMeasurementCorrections mGnssMeasCorr;
+        GnssAdapter& mAdapter;
+        LocApiBase& mApi;
+
+        inline MsgSetCorrectionsMeasCorr(
+            const GnssMeasurementCorrections gnssMeasCorr,
+            GnssAdapter& adapter,
+            LocApiBase& api) :
+            LocMsg(),
+            mGnssMeasCorr(gnssMeasCorr),
+            mAdapter(adapter),
+            mApi(api) {
+            LOC_LOGv("MsgSetCorrectionsMeasCorr");
+        }
+
+        inline virtual void proc() const {
+            LOC_LOGv("MsgSetCorrectionsMeasCorr::proc()");
+            mApi.setMeasurementCorrections(mGnssMeasCorr);
+        }
+    };
+
+    if (ContextBase::isFeatureSupported(LOC_SUPPORTED_FEATURE_MEASUREMENTS_CORRECTION)) {
+        sendMsg(new MsgSetCorrectionsMeasCorr(gnssMeasCorr, *this, *mLocApi));
+        return true;
+    } else {
+        LOC_LOGw("Measurement Corrections are not supported!");
+        return false;
+    }
+}
+uint32_t GnssAdapter::antennaInfoInitCommand(const antennaInfoCb antennaInfoCallback) {
+    LOC_LOGi("GnssAdapter::antennaInfoInitCommand");
+
+    /* Message to initialize Antenna Information */
+    struct MsgInitAi : public LocMsg {
+        const antennaInfoCb mAntennaInfoCb;
+        GnssAdapter& mAdapter;
+
+        inline MsgInitAi(const antennaInfoCb antennaInfoCallback, GnssAdapter& adapter) :
+            LocMsg(), mAntennaInfoCb(antennaInfoCallback), mAdapter(adapter) {
+            LOC_LOGv("MsgInitAi");
+        }
+
+        inline virtual void proc() const {
+            LOC_LOGv("MsgInitAi::proc()");
+            mAdapter.reportGnssAntennaInformation(mAntennaInfoCb);
+        }
+    };
+    if (mIsAntennaInfoInterfaceOpened) {
+        return ANTENNA_INFO_ERROR_ALREADY_INIT;
+    } else {
+        mIsAntennaInfoInterfaceOpened = true;
+        sendMsg(new MsgInitAi(antennaInfoCallback, *this));
+        return ANTENNA_INFO_SUCCESS;
+    }
+}
+
+void
+GnssAdapter::configRobustLocation(uint32_t sessionId,
+                                  bool enable, bool enableForE911) {
+
+    mLocConfigInfo.robustLocationConfigInfo.isValid = true;
+    mLocConfigInfo.robustLocationConfigInfo.enable = enable;
+    mLocConfigInfo.robustLocationConfigInfo.enableFor911 = enableForE911;
+
+    LocApiResponse* locApiResponse = nullptr;
+    if (sessionId != 0) {
+        locApiResponse =
+                new LocApiResponse(*getContext(),
+                                   [this, sessionId] (LocationError err) {
+                                   reportResponse(err, sessionId);});
+        if (!locApiResponse) {
+            LOC_LOGe("memory alloc failed");
+        }
+    }
+    mLocApi->configRobustLocation(enable, enableForE911, locApiResponse);
+}
+
+uint32_t GnssAdapter::configRobustLocationCommand(
+        bool enable, bool enableForE911) {
+
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGd("session id %u", sessionId);
+
+    struct MsgConfigRobustLocation : public LocMsg {
+        GnssAdapter&     mAdapter;
+        uint32_t         mSessionId;
+        bool             mEnable;
+        bool             mEnableForE911;
+
+        inline MsgConfigRobustLocation(GnssAdapter& adapter,
+                                uint32_t sessionId,
+                                bool     enable,
+                                bool     enableForE911) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mEnable(enable),
+            mEnableForE911(enableForE911) {}
+        inline virtual void proc() const {
+            mAdapter.configRobustLocation(mSessionId, mEnable, mEnableForE911);
+        }
+    };
+
+    sendMsg(new MsgConfigRobustLocation(*this, sessionId, enable, enableForE911));
+    return sessionId;
+}
+
+void
+GnssAdapter::configMinGpsWeek(uint32_t sessionId, uint16_t minGpsWeek) {
+    // suspend all sessions for modem to take the min GPS week config
+    suspendSessions();
+
+    LocApiResponse* locApiResponse = nullptr;
+    if (sessionId != 0) {
+        locApiResponse =
+                new LocApiResponse(*getContext(),
+                                   [this, sessionId] (LocationError err) {
+                                   reportResponse(err, sessionId);});
+        if (!locApiResponse) {
+            LOC_LOGe("memory alloc failed");
+        }
+    }
+    mLocApi->configMinGpsWeek(minGpsWeek, locApiResponse);
+
+    // resume all tracking sessions after the min GPS week config
+    // has been changed
+    restartSessions(false);
+}
+
+uint32_t GnssAdapter::configMinGpsWeekCommand(uint16_t minGpsWeek) {
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGd("session id %u", sessionId);
+
+    struct MsgConfigMinGpsWeek : public LocMsg {
+        GnssAdapter&     mAdapter;
+        uint32_t         mSessionId;
+        uint16_t         mMinGpsWeek;
+
+        inline MsgConfigMinGpsWeek(GnssAdapter& adapter,
+                                   uint32_t sessionId,
+                                   uint16_t minGpsWeek) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mMinGpsWeek(minGpsWeek) {}
+        inline virtual void proc() const {
+            mAdapter.configMinGpsWeek(mSessionId, mMinGpsWeek);
+        }
+    };
+
+    sendMsg(new MsgConfigMinGpsWeek(*this, sessionId, minGpsWeek));
+    return sessionId;
+}
+
+uint32_t GnssAdapter::configDeadReckoningEngineParamsCommand(
+        const DeadReckoningEngineConfig& dreConfig) {
+
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGd("session id %u", sessionId);
+
+    struct MsgConfigDrEngine : public LocMsg {
+        GnssAdapter& mAdapter;
+        uint32_t     mSessionId;
+        DeadReckoningEngineConfig mDreConfig;
+
+        inline MsgConfigDrEngine(GnssAdapter& adapter,
+                                  uint32_t sessionId,
+                                  const DeadReckoningEngineConfig& dreConfig) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mDreConfig(dreConfig) {}
+        inline virtual void proc() const {
+            LocationError err = LOCATION_ERROR_NOT_SUPPORTED;
+            if (true == mAdapter.mEngHubProxy->configDeadReckoningEngineParams(mDreConfig)) {
+                err = LOCATION_ERROR_SUCCESS;
+            }
+            mAdapter.reportResponse(err, mSessionId);
+        }
+    };
+
+    sendMsg(new MsgConfigDrEngine(*this, sessionId, dreConfig));
+    return sessionId;
+}
+
+uint32_t GnssAdapter::configEngineRunStateCommand(
+        PositioningEngineMask engType, LocEngineRunState engState) {
+
+    // generated session id will be none-zero
+    uint32_t sessionId = generateSessionId();
+    LOC_LOGe("session id %u, eng type 0x%x, eng state %d, dre enabled %d",
+             sessionId, engType, engState, mDreIntEnabled);
+
+    struct MsgConfigEngineRunState : public LocMsg {
+        GnssAdapter& mAdapter;
+        uint32_t     mSessionId;
+        PositioningEngineMask mEngType;
+        LocEngineRunState mEngState;
+
+        inline MsgConfigEngineRunState(GnssAdapter& adapter,
+                                       uint32_t sessionId,
+                                       PositioningEngineMask engType,
+                                       LocEngineRunState engState) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mEngType(engType),
+            mEngState(engState) {}
+        inline virtual void proc() const {
+            LocationError err = LOCATION_ERROR_NOT_SUPPORTED;
+            // Currently, only DR engine supports pause/resume request
+            if ((mEngType == DEAD_RECKONING_ENGINE) &&
+                (mAdapter.mDreIntEnabled == true)) {
+                if (true == mAdapter.mEngHubProxy->configEngineRunState(mEngType, mEngState)) {
+                    err = LOCATION_ERROR_SUCCESS;
+                }
+            }
+            mAdapter.reportResponse(err, mSessionId);
+        }
+    };
+
+    sendMsg(new MsgConfigEngineRunState(*this, sessionId, engType, engState));
+
+    return sessionId;
+}
+
+void GnssAdapter::reportGnssConfigEvent(uint32_t sessionId, const GnssConfig& gnssConfig)
+{
+    struct MsgReportGnssConfig : public LocMsg {
+        GnssAdapter& mAdapter;
+        uint32_t     mSessionId;
+        mutable GnssConfig   mGnssConfig;
+        inline MsgReportGnssConfig(GnssAdapter& adapter,
+                                   uint32_t sessionId,
+                                   const GnssConfig& gnssConfig) :
+            LocMsg(),
+            mAdapter(adapter),
+            mSessionId(sessionId),
+            mGnssConfig(gnssConfig) {}
+        inline virtual void proc() const {
+            // Invoke control clients config callback
+            if (nullptr != mAdapter.mControlCallbacks.gnssConfigCb) {
+                mAdapter.mControlCallbacks.gnssConfigCb(mSessionId, mGnssConfig);
+            } else {
+                LOC_LOGe("Failed to report, callback not registered");
+            }
+        }
+    };
+
+    sendMsg(new MsgReportGnssConfig(*this, sessionId, gnssConfig));
+}
+
+/* ==== Eng Hub Proxy ================================================================= */
+/* ======== UTILITIES ================================================================= */
+void
+GnssAdapter::initEngHubProxyCommand() {
+    LOC_LOGD("%s]: ", __func__);
+
+    struct MsgInitEngHubProxy : public LocMsg {
+        GnssAdapter* mAdapter;
+        inline MsgInitEngHubProxy(GnssAdapter* adapter) :
+            LocMsg(),
+            mAdapter(adapter) {}
+        inline virtual void proc() const {
+            mAdapter->initEngHubProxy();
+        }
+    };
+
+    sendMsg(new MsgInitEngHubProxy(this));
+}
+
+bool
+GnssAdapter::initEngHubProxy() {
+    static bool firstTime = true;
+    static bool engHubLoadSuccessful = false;
+
+    const char *error = nullptr;
+    unsigned int processListLength = 0;
+    loc_process_info_s_type* processInfoList = nullptr;
+
+    do {
+        // load eng hub only once
+        if (firstTime == false) {
+            break;
+        }
+
+        int rc = loc_read_process_conf(LOC_PATH_IZAT_CONF, &processListLength,
+                                       &processInfoList);
+        if (rc != 0) {
+            LOC_LOGE("%s]: failed to parse conf file", __func__);
+            break;
+        }
+
+        bool pluginDaemonEnabled = false;
+        // go over the conf table to see whether any plugin daemon is enabled
+        for (unsigned int i = 0; i < processListLength; i++) {
+            if ((strncmp(processInfoList[i].name[0], PROCESS_NAME_ENGINE_SERVICE,
+                         strlen(PROCESS_NAME_ENGINE_SERVICE)) == 0) &&
+                (processInfoList[i].proc_status == ENABLED)) {
+                pluginDaemonEnabled = true;
+                // check if this is DRE-INT engine
+                if ((processInfoList[i].args[1]!= nullptr) &&
+                    (strncmp(processInfoList[i].args[1], "DRE-INT", sizeof("DRE-INT")) == 0)) {
+                    mDreIntEnabled = true;
+                    break;
+                }
+            }
+        }
+
+        // no plugin daemon is enabled for this platform,
+        // check if external engine is present for which we need
+        // libloc_eng_hub.so to be loaded
+        if (pluginDaemonEnabled == false) {
+            UTIL_READ_CONF(LOC_PATH_IZAT_CONF, izatConfParamTable);
+            if (!loadEngHubForExternalEngine) {
+                break;
+            }
+        }
+
+        // load the engine hub .so, if the .so is not present
+        // all EngHubProxyBase calls will turn into no-op.
+        void *handle = nullptr;
+        if ((handle = dlopen("libloc_eng_hub.so", RTLD_NOW)) == nullptr) {
+            if ((error = dlerror()) != nullptr) {
+                LOC_LOGE("%s]: libloc_eng_hub.so not found %s !", __func__, error);
+            }
+            break;
+        }
+
+        // prepare the callback functions
+        // callback function for engine hub to report back position event
+        GnssAdapterReportEnginePositionsEventCb reportPositionEventCb =
+            [this](int count, EngineLocationInfo* locationArr) {
+                    // report from engine hub on behalf of PPE will be treated as fromUlp
+                    reportEnginePositionsEvent(count, locationArr);
+            };
+
+        // callback function for engine hub to report back sv event
+        GnssAdapterReportSvEventCb reportSvEventCb =
+            [this](const GnssSvNotification& svNotify, bool fromEngineHub) {
+                   reportSvEvent(svNotify, fromEngineHub);
+            };
+
+        // callback function for engine hub to request for complete aiding data
+        GnssAdapterReqAidingDataCb reqAidingDataCb =
+            [this] (const GnssAidingDataSvMask& svDataMask) {
+            mLocApi->requestForAidingData(svDataMask);
+        };
+
+        GnssAdapterUpdateNHzRequirementCb updateNHzRequirementCb =
+            [this] (bool nHzNeeded, bool nHzMeasNeeded) {
+
+            if (nHzMeasNeeded &&
+                    (!checkMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT))) {
+                updateEvtMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT,
+                    LOC_REGISTRATION_MASK_ENABLED);
+            } else if (checkMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT)) {
+                updateEvtMask(LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT,
+                    LOC_REGISTRATION_MASK_DISABLED);
+            }
+
+            if (mNHzNeeded != nHzNeeded) {
+                mNHzNeeded = nHzNeeded;
+                checkAndRestartSPESession();
+            }
+        };
+
+        GnssAdapterUpdateQwesFeatureStatusCb updateQwesFeatureStatusCb =
+            [this] (const std::unordered_map<LocationQwesFeatureType, bool> &featureMap) {
+            reportQwesCapabilities(featureMap);
+        };
+
+        getEngHubProxyFn* getter = (getEngHubProxyFn*) dlsym(handle, "getEngHubProxy");
+        if(getter != nullptr) {
+            EngineHubProxyBase* hubProxy = (*getter) (mMsgTask, mSystemStatus->getOsObserver(),
+                      reportPositionEventCb,
+                      reportSvEventCb, reqAidingDataCb,
+                      updateNHzRequirementCb,
+                      updateQwesFeatureStatusCb);
+            if (hubProxy != nullptr) {
+                mEngHubProxy = hubProxy;
+                engHubLoadSuccessful = true;
+            }
+        }
+        else {
+            LOC_LOGD("%s]: entered, did not find function", __func__);
+        }
+
+        LOC_LOGD("%s]: first time initialization %d, returned %d",
+                 __func__, firstTime, engHubLoadSuccessful);
+
+    } while (0);
+
+    if (processInfoList != nullptr) {
+        free (processInfoList);
+        processInfoList = nullptr;
+    }
+
+    firstTime = false;
+    return engHubLoadSuccessful;
+}
+
+std::vector<double>
+GnssAdapter::parseDoublesString(char* dString) {
+    std::vector<double> dVector;
+    char* tmp = NULL;
+    char* substr;
+
+    dVector.clear();
+    for (substr = strtok_r(dString, " ", &tmp);
+        substr != NULL;
+        substr = strtok_r(NULL, " ", &tmp)) {
+        dVector.push_back(std::stod(substr));
+    }
+    return dVector;
+}
+
+void
+GnssAdapter::reportGnssAntennaInformation(const antennaInfoCb antennaInfoCallback)
+{
+#define MAX_TEXT_WIDTH      50
+#define MAX_COLUMN_WIDTH    20
+
+    /* parse antenna_corrections file and fill in
+    a vector of GnssAntennaInformation data structure */
+
+    std::vector<GnssAntennaInformation> gnssAntennaInformations;
+    GnssAntennaInformation gnssAntennaInfo;
+
+    uint32_t antennaInfoVectorSize;
+    loc_param_s_type ant_info_vector_table[] =
+    {
+        { "ANTENNA_INFO_VECTOR_SIZE", &antennaInfoVectorSize, NULL, 'n' }
+    };
+    UTIL_READ_CONF(LOC_PATH_ANT_CORR, ant_info_vector_table);
+
+    for (uint32_t i = 0; i < antennaInfoVectorSize; i++) {
+        double carrierFrequencyMHz;
+        char pcOffsetStr[LOC_MAX_PARAM_STRING];
+        uint32_t numberOfRows = 0;
+        uint32_t numberOfColumns = 0;
+        uint32_t numberOfRowsSGC = 0;
+        uint32_t numberOfColumnsSGC = 0;
+
+        gnssAntennaInfo.phaseCenterVariationCorrectionMillimeters.clear();
+        gnssAntennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.clear();
+        gnssAntennaInfo.signalGainCorrectionDbi.clear();
+        gnssAntennaInfo.signalGainCorrectionUncertaintyDbi.clear();
+        string s1 = "CARRIER_FREQUENCY_";
+        s1 += to_string(i);
+        string s2 = "PC_OFFSET_";
+        s2 += to_string(i);
+        string s3 = "NUMBER_OF_ROWS_";
+        s3 += to_string(i);
+        string s4 = "NUMBER_OF_COLUMNS_";
+        s4 += to_string(i);
+        string s5 = "NUMBER_OF_ROWS_SGC_";
+        s5 += to_string(i);
+        string s6 = "NUMBER_OF_COLUMNS_SGC_";
+        s6 += to_string(i);
+
+        gnssAntennaInfo.size = sizeof(gnssAntennaInfo);
+        loc_param_s_type ant_cf_table[] =
+        {
+            { s1.c_str(), &carrierFrequencyMHz, NULL, 'f' },
+            { s2.c_str(), &pcOffsetStr, NULL, 's' },
+            { s3.c_str(), &numberOfRows, NULL, 'n' },
+            { s4.c_str(), &numberOfColumns, NULL, 'n' },
+            { s5.c_str(), &numberOfRowsSGC, NULL, 'n' },
+            { s6.c_str(), &numberOfColumnsSGC, NULL, 'n' },
+        };
+        UTIL_READ_CONF(LOC_PATH_ANT_CORR, ant_cf_table);
+
+        if (0 == numberOfRowsSGC) {
+            numberOfRowsSGC = numberOfRows;
+        }
+        if (0 == numberOfColumnsSGC) {
+            numberOfColumnsSGC = numberOfColumns;
+        }
+
+        gnssAntennaInfo.carrierFrequencyMHz = carrierFrequencyMHz;
+
+        // now parse pcOffsetStr to get each entry
+        std::vector<double> pcOffset;
+        pcOffset = parseDoublesString(pcOffsetStr);
+        gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.size =
+                sizeof(gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters);
+        gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.x = pcOffset[0];
+        gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.xUncertainty = pcOffset[1];
+        gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.y = pcOffset[2];
+        gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.yUncertainty = pcOffset[3];
+        gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.z = pcOffset[4];
+        gnssAntennaInfo.phaseCenterOffsetCoordinateMillimeters.zUncertainty = pcOffset[5];
+
+        uint16_t array_size = MAX_TEXT_WIDTH + MAX_COLUMN_WIDTH*numberOfColumns;
+        uint16_t array_size_SGC = MAX_TEXT_WIDTH + MAX_COLUMN_WIDTH*numberOfColumnsSGC;
+        for (uint32_t j = 0; j < numberOfRows; j++) {
+            char pcVarCorrStr[array_size];
+            char pcVarCorrUncStr[array_size];
+
+            string s1 = "PC_VARIATION_CORRECTION_" + to_string(i) + "_ROW_";
+            s1 += to_string(j);
+            string s2 = "PC_VARIATION_CORRECTION_UNC_" + to_string(i) + "_ROW_";
+            s2 += to_string(j);
+
+            loc_param_s_type ant_row_table[] =
+            {
+                { s1.c_str(), &pcVarCorrStr, NULL, 's' },
+                { s2.c_str(), &pcVarCorrUncStr, NULL, 's' },
+            };
+            UTIL_READ_CONF_LONG(LOC_PATH_ANT_CORR, ant_row_table, array_size);
+
+            gnssAntennaInfo.phaseCenterVariationCorrectionMillimeters.push_back(
+                    parseDoublesString(pcVarCorrStr));
+            gnssAntennaInfo.phaseCenterVariationCorrectionUncertaintyMillimeters.push_back(
+                    parseDoublesString(pcVarCorrUncStr));
+        }
+        for (uint32_t j = 0; j < numberOfRowsSGC; j++) {
+            char sigGainCorrStr[array_size_SGC];
+            char sigGainCorrUncStr[array_size_SGC];
+
+            string s3 = "SIGNAL_GAIN_CORRECTION_" + to_string(i) + "_ROW_";
+            s3 += to_string(j);
+            string s4 = "SIGNAL_GAIN_CORRECTION_UNC_" + to_string(i) + "_ROW_";
+            s4 += to_string(j);
+
+            loc_param_s_type ant_row_table[] =
+            {
+                { s3.c_str(), &sigGainCorrStr, NULL, 's' },
+                { s4.c_str(), &sigGainCorrUncStr, NULL, 's' },
+            };
+            UTIL_READ_CONF_LONG(LOC_PATH_ANT_CORR, ant_row_table, array_size_SGC);
+
+            gnssAntennaInfo.signalGainCorrectionDbi.push_back(
+                    parseDoublesString(sigGainCorrStr));
+            gnssAntennaInfo.signalGainCorrectionUncertaintyDbi.push_back(
+                    parseDoublesString(sigGainCorrUncStr));
+        }
+        gnssAntennaInformations.push_back(std::move(gnssAntennaInfo));
+    }
+    if (antennaInfoVectorSize > 0) {
+        antennaInfoCallback(gnssAntennaInformations);
+    }
+}
+
+/* ==== DGnss Usable Reporter ========================================================= */
+/* ======== UTILITIES ================================================================= */
+
+void GnssAdapter::initCDFWService()
+{
+    LOC_LOGv("mCdfwInterface %p", mCdfwInterface);
+    if (nullptr == mCdfwInterface) {
+        void* libHandle = nullptr;
+        const char* libName = "libcdfw.so";
+
+        libHandle = nullptr;
+        getCdfwInterface getter  = (getCdfwInterface)dlGetSymFromLib(libHandle,
+                          libName, "getQCdfwInterface");
+        if (nullptr == getter) {
+            LOC_LOGe("dlGetSymFromLib getQCdfwInterface failed");
+        } else {
+            mCdfwInterface = getter();
+        }
+
+        if (nullptr != mCdfwInterface) {
+            QDgnssSessionActiveCb qDgnssSessionActiveCb = [this] (bool sessionActive) {
+                mDGnssNeedReport = sessionActive;
+            };
+            mCdfwInterface->startDgnssApiService(*mMsgTask);
+            mQDgnssListenerHDL = mCdfwInterface->createUsableReporter(qDgnssSessionActiveCb);
+        }
+    }
+}
+
+/*==== DGnss Ntrip Source ==========================================================*/
+void GnssAdapter::enablePPENtripStreamCommand(const GnssNtripConnectionParams& params,
+                                              bool enableRTKEngine) {
+
+    (void)enableRTKEngine; //future parameter, not used
+    if (0 == params.size || params.hostNameOrIp.empty() || params.mountPoint.empty() ||
+            params.username.empty() || params.password.empty()) {
+        LOC_LOGe("Ntrip parameters are invalid!");
+        return;
+    }
+
+    struct enableNtripMsg : public LocMsg {
+        GnssAdapter& mAdapter;
+        const GnssNtripConnectionParams mParams;
+
+        inline enableNtripMsg(GnssAdapter& adapter,
+                const GnssNtripConnectionParams& params) :
+            LocMsg(),
+            mAdapter(adapter),
+            mParams(std::move(params)) {}
+        inline virtual void proc() const {
+            mAdapter.handleEnablePPENtrip(mParams);
+        }
+    };
+    sendMsg(new enableNtripMsg(*this, params));
+}
+
+void GnssAdapter::handleEnablePPENtrip(const GnssNtripConnectionParams& params) {
+    LOC_LOGd("%d %s %d %s %s %s %d mSendNmeaConsent %d",
+             params.useSSL, params.hostNameOrIp.data(), params.port,
+             params.mountPoint.data(), params.username.data(), params.password.data(),
+             params.requiresNmeaLocation, mSendNmeaConsent);
+
+    GnssNtripConnectionParams* pNtripParams = &(mStartDgnssNtripParams.ntripParams);
+
+    if (pNtripParams->useSSL == params.useSSL &&
+            0 == pNtripParams->hostNameOrIp.compare(params.hostNameOrIp) &&
+            pNtripParams->port == params.port &&
+            0 == pNtripParams->mountPoint.compare(params.mountPoint) &&
+            0 == pNtripParams->username.compare(params.username) &&
+            0 == pNtripParams->password.compare(params.password) &&
+            pNtripParams->requiresNmeaLocation == params.requiresNmeaLocation &&
+            mDgnssState & DGNSS_STATE_ENABLE_NTRIP_COMMAND) {
+        LOC_LOGd("received same Ntrip param");
+        return;
+    }
+
+    mDgnssState |= DGNSS_STATE_ENABLE_NTRIP_COMMAND;
+    mDgnssState |= DGNSS_STATE_NO_NMEA_PENDING;
+    mDgnssState &= ~DGNSS_STATE_NTRIP_SESSION_STARTED;
+
+    mStartDgnssNtripParams.ntripParams = std::move(params);
+    mStartDgnssNtripParams.nmea.clear();
+    if (mSendNmeaConsent && pNtripParams->requiresNmeaLocation) {
+        mDgnssState &= ~DGNSS_STATE_NO_NMEA_PENDING;
+        mDgnssLastNmeaBootTimeMilli = 0;
+        return;
+    }
+
+    checkUpdateDgnssNtrip(false);
+}
+
+void GnssAdapter::disablePPENtripStreamCommand() {
+    struct disableNtripMsg : public LocMsg {
+        GnssAdapter& mAdapter;
+
+        inline disableNtripMsg(GnssAdapter& adapter) :
+            LocMsg(),
+            mAdapter(adapter) {}
+        inline virtual void proc() const {
+            mAdapter.handleDisablePPENtrip();
+        }
+    };
+    sendMsg(new disableNtripMsg(*this));
+}
+
+void GnssAdapter::handleDisablePPENtrip() {
+    mDgnssState &= ~DGNSS_STATE_ENABLE_NTRIP_COMMAND;
+    mDgnssState |= DGNSS_STATE_NO_NMEA_PENDING;
+    stopDgnssNtrip();
+}
+
+void GnssAdapter::checkUpdateDgnssNtrip(bool isLocationValid) {
+    LOC_LOGd("isInSession %d mDgnssState 0x%x isLocationValid %d",
+            isInSession(), mDgnssState, isLocationValid);
+    if (isInSession()) {
+        uint64_t curBootTime = getBootTimeMilliSec();
+        if (mDgnssState == (DGNSS_STATE_ENABLE_NTRIP_COMMAND | DGNSS_STATE_NO_NMEA_PENDING)) {
+            mDgnssState |= DGNSS_STATE_NTRIP_SESSION_STARTED;
+            mXtraObserver.startDgnssSource(mStartDgnssNtripParams);
+            if (isDgnssNmeaRequired()) {
+                mDgnssLastNmeaBootTimeMilli = curBootTime;
+            }
+        } else if ((mDgnssState & DGNSS_STATE_NTRIP_SESSION_STARTED) && isLocationValid &&
+            isDgnssNmeaRequired() &&
+            curBootTime - mDgnssLastNmeaBootTimeMilli > DGNSS_RANGE_UPDATE_TIME_10MIN_IN_MILLI ) {
+            mXtraObserver.updateNmeaToDgnssServer(mStartDgnssNtripParams.nmea);
+            mDgnssLastNmeaBootTimeMilli = curBootTime;
+        }
+    }
+}
+
+void GnssAdapter::stopDgnssNtrip() {
+    LOC_LOGd("isInSession %d mDgnssState 0x%x", isInSession(), mDgnssState);
+    mStartDgnssNtripParams.nmea.clear();
+    if (mDgnssState & DGNSS_STATE_NTRIP_SESSION_STARTED) {
+        mDgnssState &= ~DGNSS_STATE_NTRIP_SESSION_STARTED;
+        mXtraObserver.stopDgnssSource();
+    }
+}
+
+void GnssAdapter::reportGGAToNtrip(const char* nmea) {
+
+#define POS_OF_GGA (3)  //start position of "GGA"
+#define COMMAS_BEFORE_VALID (6) //"$GPGGA,,,,,,0,,,,,,,,*hh"
+
+    if (!isDgnssNmeaRequired()) {
+        return;
+    }
+
+    if (nullptr == nmea || 0 == strlen(nmea)) {
+        return;
+    }
+
+    string nmeaString(nmea);
+    size_t foundPos = nmeaString.find("GGA");
+    size_t foundNth = 0;
+    string GGAString;
+
+    if (foundPos != string::npos && foundPos >= POS_OF_GGA) {
+        size_t foundNextSentence = nmeaString.find("$", foundPos);
+        if (foundNextSentence != string::npos) {
+            /* remove other sentences after GGA */
+            GGAString = nmeaString.substr(foundPos - POS_OF_GGA, foundNextSentence);
+        } else {
+            /* GGA is the last sentence */
+            GGAString = nmeaString.substr(foundPos - POS_OF_GGA);
+        }
+        LOC_LOGd("GGAString %s", GGAString.c_str());
+
+        foundPos = GGAString.find(",");
+        while (foundPos != string::npos && foundNth < COMMAS_BEFORE_VALID) {
+            foundPos++;
+            foundNth++;
+            foundPos = GGAString.find(",", foundPos);
+        }
+
+        if (COMMAS_BEFORE_VALID == foundNth && GGAString.at(foundPos-1) != '0') {
+            mDgnssState |= DGNSS_STATE_NO_NMEA_PENDING;
+            mStartDgnssNtripParams.nmea = std::move(GGAString);
+            checkUpdateDgnssNtrip(true);
+        }
+    }
+
+    return;
+}
diff --git a/gps/gnss/GnssAdapter.h b/gps/gnss/GnssAdapter.h
new file mode 100644
index 0000000..d7b4275
--- /dev/null
+++ b/gps/gnss/GnssAdapter.h
@@ -0,0 +1,651 @@
+/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef GNSS_ADAPTER_H
+#define GNSS_ADAPTER_H
+
+#include <LocAdapterBase.h>
+#include <LocContext.h>
+#include <IOsObserver.h>
+#include <EngineHubProxyBase.h>
+#include <LocationAPI.h>
+#include <Agps.h>
+#include <SystemStatus.h>
+#include <XtraSystemStatusObserver.h>
+#include <map>
+#include <functional>
+#include <loc_misc_utils.h>
+#include <queue>
+#include <NativeAgpsHandler.h>
+
+#define MAX_URL_LEN 256
+#define NMEA_SENTENCE_MAX_LENGTH 200
+#define GLONASS_SV_ID_OFFSET 64
+#define MAX_SATELLITES_IN_USE 12
+#define LOC_NI_NO_RESPONSE_TIME 20
+#define LOC_GPS_NI_RESPONSE_IGNORE 4
+#define ODCPI_EXPECTED_INJECTION_TIME_MS 10000
+#define DELETE_AIDING_DATA_EXPECTED_TIME_MS 5000
+
+class GnssAdapter;
+
+typedef std::map<LocationSessionKey, LocationOptions> LocationSessionMap;
+typedef std::map<LocationSessionKey, TrackingOptions> TrackingOptionsMap;
+
+class OdcpiTimer : public LocTimer {
+public:
+    OdcpiTimer(GnssAdapter* adapter) :
+            LocTimer(), mAdapter(adapter), mActive(false) {}
+
+    inline void start() {
+        mActive = true;
+        LocTimer::start(ODCPI_EXPECTED_INJECTION_TIME_MS, false);
+    }
+    inline void stop() {
+        mActive = false;
+        LocTimer::stop();
+    }
+    inline void restart() {
+        stop();
+        start();
+    }
+    inline bool isActive() {
+        return mActive;
+    }
+
+private:
+    // Override
+    virtual void timeOutCallback() override;
+
+    GnssAdapter* mAdapter;
+    bool mActive;
+};
+
+typedef struct {
+    pthread_t               thread;        /* NI thread */
+    uint32_t                respTimeLeft;  /* examine time for NI response */
+    bool                    respRecvd;     /* NI User reponse received or not from Java layer*/
+    void*                   rawRequest;
+    uint32_t                reqID;         /* ID to check against response */
+    GnssNiResponse          resp;
+    pthread_cond_t          tCond;
+    pthread_mutex_t         tLock;
+    GnssAdapter*            adapter;
+} NiSession;
+typedef struct {
+    NiSession session;    /* SUPL NI Session */
+    NiSession sessionEs;  /* Emergency SUPL NI Session */
+    uint32_t reqIDCounter;
+} NiData;
+
+typedef enum {
+    NMEA_PROVIDER_AP = 0, // Application Processor Provider of NMEA
+    NMEA_PROVIDER_MP      // Modem Processor Provider of NMEA
+} NmeaProviderType;
+typedef struct {
+    GnssSvType svType;
+    const char* talker;
+    uint64_t mask;
+    uint32_t svIdOffset;
+} NmeaSvMeta;
+
+typedef struct {
+    double latitude;
+    double longitude;
+    float  accuracy;
+    // the CPI will be blocked until the boot time
+    // specified in blockedTillTsMs
+    int64_t blockedTillTsMs;
+    // CPIs whose both latitude and longitude differ
+    // no more than latLonThreshold will be blocked
+    // in units of degree
+    double latLonDiffThreshold;
+} BlockCPIInfo;
+
+typedef struct {
+    bool isValid;
+    bool enable;
+    float tuncThresholdMs; // need to be specified if enable is true
+    uint32_t energyBudget; // need to be specified if enable is true
+} TuncConfigInfo;
+
+typedef struct {
+    bool isValid;
+    bool enable;
+} PaceConfigInfo;
+
+typedef struct {
+    bool isValid;
+    bool enable;
+    bool enableFor911;
+} RobustLocationConfigInfo;
+
+typedef struct {
+    TuncConfigInfo tuncConfigInfo;
+    PaceConfigInfo paceConfigInfo;
+    RobustLocationConfigInfo robustLocationConfigInfo;
+    LeverArmConfigInfo  leverArmConfigInfo;
+} LocIntegrationConfigInfo;
+
+using namespace loc_core;
+
+namespace loc_core {
+    class SystemStatus;
+}
+
+typedef std::function<void(
+    uint64_t gnssEnergyConsumedFromFirstBoot
+)> GnssEnergyConsumedCallback;
+
+typedef void* QDgnssListenerHDL;
+typedef std::function<void(
+    bool    sessionActive
+)> QDgnssSessionActiveCb;
+
+struct CdfwInterface {
+    void (*startDgnssApiService)(const MsgTask& msgTask);
+    QDgnssListenerHDL (*createUsableReporter)(
+            QDgnssSessionActiveCb sessionActiveCb);
+    void (*destroyUsableReporter)(QDgnssListenerHDL handle);
+    void (*reportUsable)(QDgnssListenerHDL handle, bool usable);
+};
+
+typedef uint16_t  DGnssStateBitMask;
+#define DGNSS_STATE_ENABLE_NTRIP_COMMAND      0X01
+#define DGNSS_STATE_NO_NMEA_PENDING           0X02
+#define DGNSS_STATE_NTRIP_SESSION_STARTED     0X04
+
+class GnssReportLoggerUtil {
+public:
+    typedef void (*LogGnssLatency)(const GnssLatencyInfo& gnssLatencyMeasInfo);
+
+    GnssReportLoggerUtil() : mLogLatency(nullptr) {
+        const char* libname = "liblocdiagiface.so";
+        void* libHandle = nullptr;
+        mLogLatency = (LogGnssLatency)dlGetSymFromLib(libHandle, libname, "LogGnssLatency");
+    }
+
+    bool isLogEnabled();
+    void log(const GnssLatencyInfo& gnssLatencyMeasInfo);
+
+private:
+    LogGnssLatency mLogLatency;
+};
+
+class GnssAdapter : public LocAdapterBase {
+
+    /* ==== Engine Hub ===================================================================== */
+    EngineHubProxyBase* mEngHubProxy;
+    bool mNHzNeeded;
+    bool mSPEAlreadyRunningAtHighestInterval;
+
+    /* ==== TRACKING ======================================================================= */
+    TrackingOptionsMap mTimeBasedTrackingSessions;
+    LocationSessionMap mDistanceBasedTrackingSessions;
+    LocPosMode mLocPositionMode;
+    GnssSvUsedInPosition mGnssSvIdUsedInPosition;
+    bool mGnssSvIdUsedInPosAvail;
+    GnssSvMbUsedInPosition mGnssMbSvIdUsedInPosition;
+    bool mGnssMbSvIdUsedInPosAvail;
+
+    /* ==== CONTROL ======================================================================== */
+    LocationControlCallbacks mControlCallbacks;
+    uint32_t mAfwControlId;
+    uint32_t mNmeaMask;
+    uint64_t mPrevNmeaRptTimeNsec;
+    GnssSvIdConfig mGnssSvIdConfig;
+    GnssSvTypeConfig mGnssSeconaryBandConfig;
+    GnssSvTypeConfig mGnssSvTypeConfig;
+    GnssSvTypeConfigCallback mGnssSvTypeConfigCb;
+    bool mSupportNfwControl;
+    LocIntegrationConfigInfo mLocConfigInfo;
+
+    /* ==== NI ============================================================================= */
+    NiData mNiData;
+
+    /* ==== AGPS =========================================================================== */
+    // This must be initialized via initAgps()
+    AgpsManager mAgpsManager;
+    void initAgps(const AgpsCbInfo& cbInfo);
+
+    /* ==== NFW =========================================================================== */
+    NfwStatusCb mNfwCb;
+    IsInEmergencySession mIsE911Session;
+    inline void initNfw(const NfwCbInfo& cbInfo) {
+        mNfwCb = (NfwStatusCb)cbInfo.visibilityControlCb;
+        mIsE911Session = (IsInEmergencySession)cbInfo.isInEmergencySession;
+    }
+
+    /* ==== Measurement Corrections========================================================= */
+    bool mIsMeasCorrInterfaceOpen;
+    measCorrSetCapabilitiesCb mMeasCorrSetCapabilitiesCb;
+    bool initMeasCorr(bool bSendCbWhenNotSupported);
+    bool mIsAntennaInfoInterfaceOpened;
+
+    /* ==== DGNSS Data Usable Report======================================================== */
+    QDgnssListenerHDL mQDgnssListenerHDL;
+    const CdfwInterface* mCdfwInterface;
+    bool mDGnssNeedReport;
+    bool mDGnssDataUsage;
+    void reportDGnssDataUsable(const GnssSvMeasurementSet &svMeasurementSet);
+
+    /* ==== ODCPI ========================================================================== */
+    OdcpiRequestCallback mOdcpiRequestCb;
+    bool mOdcpiRequestActive;
+    OdcpiPrioritytype mCallbackPriority;
+    OdcpiTimer mOdcpiTimer;
+    OdcpiRequestInfo mOdcpiRequest;
+    void odcpiTimerExpire();
+
+    /* ==== DELETEAIDINGDATA =============================================================== */
+    int64_t mLastDeleteAidingDataTime;
+
+    /* === SystemStatus ===================================================================== */
+    SystemStatus* mSystemStatus;
+    std::string mServerUrl;
+    std::string mMoServerUrl;
+    XtraSystemStatusObserver mXtraObserver;
+    LocationSystemInfo mLocSystemInfo;
+    std::vector<GnssSvIdSource> mBlacklistedSvIds;
+    PowerStateType mSystemPowerState;
+
+    /* === Misc ===================================================================== */
+    BlockCPIInfo mBlockCPIInfo;
+    bool mPowerOn;
+    uint32_t mAllowFlpNetworkFixes;
+    std::queue<GnssLatencyInfo> mGnssLatencyInfoQueue;
+    GnssReportLoggerUtil mLogger;
+    bool mDreIntEnabled;
+
+    /* === NativeAgpsHandler ======================================================== */
+    NativeAgpsHandler mNativeAgpsHandler;
+
+    /* === Misc callback from QMI LOC API ============================================== */
+    GnssEnergyConsumedCallback mGnssEnergyConsumedCb;
+    std::function<void(bool)> mPowerStateCb;
+
+    /*==== CONVERSION ===================================================================*/
+    static void convertOptions(LocPosMode& out, const TrackingOptions& trackingOptions);
+    static void convertLocation(Location& out, const UlpLocation& ulpLocation,
+                                const GpsLocationExtended& locationExtended);
+    static void convertLocationInfo(GnssLocationInfoNotification& out,
+                                    const GpsLocationExtended& locationExtended,
+                                    loc_sess_status status);
+    static uint16_t getNumSvUsed(uint64_t svUsedIdsMask,
+                                 int totalSvCntInThisConstellation);
+
+    /* ======== UTILITIES ================================================================== */
+    inline void initOdcpi(const OdcpiRequestCallback& callback, OdcpiPrioritytype priority);
+    inline void injectOdcpi(const Location& location);
+    static bool isFlpClient(LocationCallbacks& locationCallbacks);
+
+    /*==== DGnss Ntrip Source ==========================================================*/
+    StartDgnssNtripParams   mStartDgnssNtripParams;
+    bool    mSendNmeaConsent;
+    DGnssStateBitMask   mDgnssState;
+    void checkUpdateDgnssNtrip(bool isLocationValid);
+    void stopDgnssNtrip();
+    uint64_t   mDgnssLastNmeaBootTimeMilli;
+
+protected:
+
+    /* ==== CLIENT ========================================================================= */
+    virtual void updateClientsEventMask();
+    virtual void stopClientSessions(LocationAPI* client);
+    inline void setNmeaReportRateConfig();
+    void logLatencyInfo();
+
+public:
+    GnssAdapter();
+    virtual inline ~GnssAdapter() { }
+
+    /* ==== SSR ============================================================================ */
+    /* ======== EVENTS ====(Called from QMI Thread)========================================= */
+    virtual void handleEngineUpEvent();
+    /* ======== UTILITIES ================================================================== */
+    void restartSessions(bool modemSSR = false);
+    void checkAndRestartTimeBasedSession();
+    void checkAndRestartSPESession();
+    void suspendSessions();
+
+    /* ==== CLIENT ========================================================================= */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    virtual void addClientCommand(LocationAPI* client, const LocationCallbacks& callbacks);
+
+    /* ==== TRACKING ======================================================================= */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    uint32_t startTrackingCommand(
+            LocationAPI* client, TrackingOptions& trackingOptions);
+    void updateTrackingOptionsCommand(
+            LocationAPI* client, uint32_t id, TrackingOptions& trackingOptions);
+    void stopTrackingCommand(LocationAPI* client, uint32_t id);
+    /* ======== RESPONSES ================================================================== */
+    void reportResponse(LocationAPI* client, LocationError err, uint32_t sessionId);
+    /* ======== UTILITIES ================================================================== */
+    bool isTimeBasedTrackingSession(LocationAPI* client, uint32_t sessionId);
+    bool isDistanceBasedTrackingSession(LocationAPI* client, uint32_t sessionId);
+    bool hasCallbacksToStartTracking(LocationAPI* client);
+    bool isTrackingSession(LocationAPI* client, uint32_t sessionId);
+    void saveTrackingSession(LocationAPI* client, uint32_t sessionId,
+                             const TrackingOptions& trackingOptions);
+    void eraseTrackingSession(LocationAPI* client, uint32_t sessionId);
+
+    bool setLocPositionMode(const LocPosMode& mode);
+    LocPosMode& getLocPositionMode() { return mLocPositionMode; }
+
+    bool startTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t sessionId,
+                                         const TrackingOptions& trackingOptions);
+    void startTimeBasedTracking(LocationAPI* client, uint32_t sessionId,
+            const TrackingOptions& trackingOptions);
+    bool stopTimeBasedTrackingMultiplex(LocationAPI* client, uint32_t id);
+    void stopTracking(LocationAPI* client, uint32_t id);
+    bool updateTrackingMultiplex(LocationAPI* client, uint32_t id,
+            const TrackingOptions& trackingOptions);
+    void updateTracking(LocationAPI* client, uint32_t sessionId,
+            const TrackingOptions& updatedOptions, const TrackingOptions& oldOptions);
+    bool checkAndSetSPEToRunforNHz(TrackingOptions & out);
+
+    void setConstrainedTunc(bool enable, float tuncConstraint,
+                            uint32_t energyBudget, uint32_t sessionId);
+    void setPositionAssistedClockEstimator(bool enable, uint32_t sessionId);
+    void gnssUpdateSvConfig(uint32_t sessionId,
+                        const GnssSvTypeConfig& constellationEnablementConfig,
+                        const GnssSvIdConfig& blacklistSvConfig);
+
+    void gnssUpdateSecondaryBandConfig(
+        uint32_t sessionId, const GnssSvTypeConfig& secondaryBandConfig);
+    void gnssGetSecondaryBandConfig(uint32_t sessionId);
+    void resetSvConfig(uint32_t sessionId);
+    void configLeverArm(uint32_t sessionId, const LeverArmConfigInfo& configInfo);
+    void configRobustLocation(uint32_t sessionId, bool enable, bool enableForE911);
+    void configMinGpsWeek(uint32_t sessionId, uint16_t minGpsWeek);
+
+    /* ==== NI ============================================================================= */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    void gnssNiResponseCommand(LocationAPI* client, uint32_t id, GnssNiResponse response);
+    /* ======================(Called from NI Thread)======================================== */
+    void gnssNiResponseCommand(GnssNiResponse response, void* rawRequest);
+    /* ======== UTILITIES ================================================================== */
+    bool hasNiNotifyCallback(LocationAPI* client);
+    NiData& getNiData() { return mNiData; }
+
+    /* ==== CONTROL CLIENT ================================================================= */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    uint32_t enableCommand(LocationTechnologyType techType);
+    void disableCommand(uint32_t id);
+    void setControlCallbacksCommand(LocationControlCallbacks& controlCallbacks);
+    void readConfigCommand();
+    void requestUlpCommand();
+    void initEngHubProxyCommand();
+    uint32_t* gnssUpdateConfigCommand(const GnssConfig& config);
+    uint32_t* gnssGetConfigCommand(GnssConfigFlagsMask mask);
+    uint32_t gnssDeleteAidingDataCommand(GnssAidingData& data);
+    void deleteAidingData(const GnssAidingData &data, uint32_t sessionId);
+    void gnssUpdateXtraThrottleCommand(const bool enabled);
+    std::vector<LocationError> gnssUpdateConfig(const std::string& oldMoServerUrl,
+            const std::string& moServerUrl,
+            const std::string& serverUrl,
+            GnssConfig& gnssConfigRequested,
+            GnssConfig& gnssConfigNeedEngineUpdate, size_t count = 0);
+
+    /* ==== 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 gnssSvIdConfigUpdateSync(const std::vector<GnssSvIdSource>& blacklistedSvIds);
+    LocationError gnssSvIdConfigUpdateSync();
+    void gnssSvIdConfigUpdate(const std::vector<GnssSvIdSource>& blacklistedSvIds);
+    void gnssSvIdConfigUpdate();
+    void gnssSvTypeConfigUpdate(const GnssSvTypeConfig& config);
+    void gnssSvTypeConfigUpdate(bool sendReset = false);
+    inline void gnssSetSvTypeConfig(const GnssSvTypeConfig& config)
+    { mGnssSvTypeConfig = config; }
+    inline void gnssSetSvTypeConfigCallback(GnssSvTypeConfigCallback callback)
+    { mGnssSvTypeConfigCb = callback; }
+    inline GnssSvTypeConfigCallback gnssGetSvTypeConfigCallback()
+    { return mGnssSvTypeConfigCb; }
+    void setConfig();
+    void gnssSecondaryBandConfigUpdate(LocApiResponse* locApiResponse= nullptr);
+
+    /* ========= AGPS ====================================================================== */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    void initDefaultAgpsCommand();
+    void initAgpsCommand(const AgpsCbInfo& cbInfo);
+    void initNfwCommand(const NfwCbInfo& cbInfo);
+    void dataConnOpenCommand(AGpsExtType agpsType,
+            const char* apnName, int apnLen, AGpsBearerType bearerType);
+    void dataConnClosedCommand(AGpsExtType agpsType);
+    void dataConnFailedCommand(AGpsExtType agpsType);
+    void getGnssEnergyConsumedCommand(GnssEnergyConsumedCallback energyConsumedCb);
+    void nfwControlCommand(bool enable);
+    uint32_t setConstrainedTuncCommand (bool enable, float tuncConstraint,
+                                        uint32_t energyBudget);
+    uint32_t setPositionAssistedClockEstimatorCommand (bool enable);
+    uint32_t gnssUpdateSvConfigCommand(const GnssSvTypeConfig& constellationEnablementConfig,
+                                       const GnssSvIdConfig& blacklistSvConfig);
+    uint32_t gnssUpdateSecondaryBandConfigCommand(
+                                       const GnssSvTypeConfig& secondaryBandConfig);
+    uint32_t gnssGetSecondaryBandConfigCommand();
+    uint32_t configLeverArmCommand(const LeverArmConfigInfo& configInfo);
+    uint32_t configRobustLocationCommand(bool enable, bool enableForE911);
+    bool openMeasCorrCommand(const measCorrSetCapabilitiesCb setCapabilitiesCb);
+    bool measCorrSetCorrectionsCommand(const GnssMeasurementCorrections gnssMeasCorr);
+    inline void closeMeasCorrCommand() { mIsMeasCorrInterfaceOpen = false; }
+    uint32_t antennaInfoInitCommand(const antennaInfoCb antennaInfoCallback);
+    inline void antennaInfoCloseCommand() { mIsAntennaInfoInterfaceOpened = false; }
+    uint32_t configMinGpsWeekCommand(uint16_t minGpsWeek);
+    uint32_t configDeadReckoningEngineParamsCommand(const DeadReckoningEngineConfig& dreConfig);
+    uint32_t configEngineRunStateCommand(PositioningEngineMask engType,
+                                         LocEngineRunState engState);
+
+    /* ========= ODCPI ===================================================================== */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    void initOdcpiCommand(const OdcpiRequestCallback& callback, OdcpiPrioritytype priority);
+    void injectOdcpiCommand(const Location& location);
+    /* ======== RESPONSES ================================================================== */
+    void reportResponse(LocationError err, uint32_t sessionId);
+    void reportResponse(size_t count, LocationError* errs, uint32_t* ids);
+    /* ======== UTILITIES ================================================================== */
+    LocationControlCallbacks& getControlCallbacks() { return mControlCallbacks; }
+    void setControlCallbacks(const LocationControlCallbacks& controlCallbacks)
+    { mControlCallbacks = controlCallbacks; }
+    void setAfwControlId(uint32_t id) { mAfwControlId = id; }
+    uint32_t getAfwControlId() { return mAfwControlId; }
+    virtual bool isInSession() { return !mTimeBasedTrackingSessions.empty(); }
+    void initDefaultAgps();
+    bool initEngHubProxy();
+    void initCDFWService();
+    void odcpiTimerExpireEvent();
+
+    /* ==== REPORTS ======================================================================== */
+    /* ======== EVENTS ====(Called from QMI/EngineHub Thread)===================================== */
+    virtual void reportPositionEvent(const UlpLocation& ulpLocation,
+                                     const GpsLocationExtended& locationExtended,
+                                     enum loc_sess_status status,
+                                     LocPosTechMask techMask,
+                                     GnssDataNotification* pDataNotify = nullptr,
+                                     int msInWeek = -1);
+    virtual void reportEnginePositionsEvent(unsigned int count,
+                                            EngineLocationInfo* locationArr);
+
+    virtual void reportSvEvent(const GnssSvNotification& svNotify,
+                               bool fromEngineHub=false);
+    virtual void reportNmeaEvent(const char* nmea, size_t length);
+    virtual void reportDataEvent(const GnssDataNotification& dataNotify, int msInWeek);
+    virtual bool requestNiNotifyEvent(const GnssNiNotification& notify, const void* data,
+                                      const LocInEmergency emergencyState);
+    virtual void reportGnssMeasurementsEvent(const GnssMeasurements& gnssMeasurements,
+                                                int msInWeek);
+    virtual void reportSvPolynomialEvent(GnssSvPolynomial &svPolynomial);
+    virtual void reportSvEphemerisEvent(GnssSvEphemerisReport & svEphemeris);
+    virtual void reportGnssSvIdConfigEvent(const GnssSvIdConfig& config);
+    virtual void reportGnssSvTypeConfigEvent(const GnssSvTypeConfig& config);
+    virtual void reportGnssConfigEvent(uint32_t sessionId, const GnssConfig& gnssConfig);
+    virtual bool reportGnssEngEnergyConsumedEvent(uint64_t energyConsumedSinceFirstBoot);
+    virtual void reportLocationSystemInfoEvent(const LocationSystemInfo& locationSystemInfo);
+
+    virtual bool requestATL(int connHandle, LocAGpsType agps_type, LocApnTypeMask apn_type_mask);
+    virtual bool releaseATL(int connHandle);
+    virtual bool requestOdcpiEvent(OdcpiRequestInfo& request);
+    virtual bool reportDeleteAidingDataEvent(GnssAidingData& aidingData);
+    virtual bool reportKlobucharIonoModelEvent(GnssKlobucharIonoModel& ionoModel);
+    virtual bool reportGnssAdditionalSystemInfoEvent(
+            GnssAdditionalSystemInfo& additionalSystemInfo);
+    virtual void reportNfwNotificationEvent(GnssNfwNotification& notification);
+    virtual void reportLatencyInfoEvent(const GnssLatencyInfo& gnssLatencyInfo);
+    virtual bool reportQwesCapabilities
+    (
+        const std::unordered_map<LocationQwesFeatureType, bool> &featureMap
+    );
+    void reportPdnTypeFromWds(int pdnType, AGpsExtType agpsType, std::string apnName,
+            AGpsBearerType bearerType);
+
+    /* ======== UTILITIES ================================================================= */
+    bool needReportForGnssClient(const UlpLocation& ulpLocation,
+            enum loc_sess_status status, LocPosTechMask techMask);
+    bool needReportForFlpClient(enum loc_sess_status status, LocPosTechMask techMask);
+    bool needToGenerateNmeaReport(const uint32_t &gpsTimeOfWeekMs,
+        const struct timespec32_t &apTimeStamp);
+    void reportPosition(const UlpLocation &ulpLocation,
+                        const GpsLocationExtended &locationExtended,
+                        enum loc_sess_status status,
+                        LocPosTechMask techMask);
+    void reportEnginePositions(unsigned int count,
+                               const EngineLocationInfo* locationArr);
+    void reportSv(GnssSvNotification& svNotify);
+    void reportNmea(const char* nmea, size_t length);
+    void reportData(GnssDataNotification& dataNotify);
+    bool requestNiNotify(const GnssNiNotification& notify, const void* data,
+                         const bool bInformNiAccept);
+    void reportGnssMeasurementData(const GnssMeasurementsNotification& measurements);
+    void reportGnssSvIdConfig(const GnssSvIdConfig& config);
+    void reportGnssSvTypeConfig(const GnssSvTypeConfig& config);
+    void reportGnssConfig(uint32_t sessionId, const GnssConfig& gnssConfig);
+    void requestOdcpi(const OdcpiRequestInfo& request);
+    void invokeGnssEnergyConsumedCallback(uint64_t energyConsumedSinceFirstBoot);
+    void saveGnssEnergyConsumedCallback(GnssEnergyConsumedCallback energyConsumedCb);
+    void reportLocationSystemInfo(const LocationSystemInfo & locationSystemInfo);
+    inline void reportNfwNotification(const GnssNfwNotification& notification) {
+        if (NULL != mNfwCb) {
+            mNfwCb(notification);
+        }
+    }
+    inline bool getE911State(void) {
+        if (NULL != mIsE911Session) {
+            return mIsE911Session();
+        }
+        return false;
+    }
+
+    void updateSystemPowerState(PowerStateType systemPowerState);
+    void reportSvPolynomial(const GnssSvPolynomial &svPolynomial);
+
+
+    std::vector<double> parseDoublesString(char* dString);
+    void reportGnssAntennaInformation(const antennaInfoCb antennaInfoCallback);
+
+    /*======== GNSSDEBUG ================================================================*/
+    bool getDebugReport(GnssDebugReport& report);
+    /* get AGC information from system status and fill it */
+    void getAgcInformation(GnssMeasurementsNotification& measurements, int msInWeek);
+    /* get Data information from system status and fill it */
+    void getDataInformation(GnssDataNotification& data, int msInWeek);
+
+    /*==== SYSTEM STATUS ================================================================*/
+    inline SystemStatus* getSystemStatus(void) { return mSystemStatus; }
+    std::string& getServerUrl(void) { return mServerUrl; }
+    std::string& getMoServerUrl(void) { return mMoServerUrl; }
+
+    /*==== CONVERSION ===================================================================*/
+    static uint32_t convertSuplVersion(const GnssConfigSuplVersion suplVersion);
+    static uint32_t convertEP4ES(const GnssConfigEmergencyPdnForEmergencySupl);
+    static uint32_t convertSuplEs(const GnssConfigSuplEmergencyServices suplEmergencyServices);
+    static uint32_t convertLppeCp(const GnssConfigLppeControlPlaneMask lppeControlPlaneMask);
+    static uint32_t convertLppeUp(const GnssConfigLppeUserPlaneMask lppeUserPlaneMask);
+    static uint32_t convertAGloProt(const GnssConfigAGlonassPositionProtocolMask);
+    static uint32_t convertSuplMode(const GnssConfigSuplModeMask suplModeMask);
+    static void convertSatelliteInfo(std::vector<GnssDebugSatelliteInfo>& out,
+                                     const GnssSvType& in_constellation,
+                                     const SystemStatusReports& in);
+    static bool convertToGnssSvIdConfig(
+            const std::vector<GnssSvIdSource>& blacklistedSvIds, GnssSvIdConfig& config);
+    static void convertFromGnssSvIdConfig(
+            const GnssSvIdConfig& svConfig, std::vector<GnssSvIdSource>& blacklistedSvIds);
+    static void convertGnssSvIdMaskToList(
+            uint64_t svIdMask, std::vector<GnssSvIdSource>& svIds,
+            GnssSvId initialSvId, GnssSvType svType);
+    static void computeVRPBasedLla(const UlpLocation& loc, GpsLocationExtended& locExt,
+                                   const LeverArmConfigInfo& leverArmConfigInfo);
+
+    void injectLocationCommand(double latitude, double longitude, float accuracy);
+    void injectLocationExtCommand(const GnssLocationInfoNotification &locationInfo);
+
+    void injectTimeCommand(int64_t time, int64_t timeReference, int32_t uncertainty);
+    void blockCPICommand(double latitude, double longitude, float accuracy,
+                         int blockDurationMsec, double latLonDiffThreshold);
+
+    /* ==== MISCELLANEOUS ================================================================== */
+    /* ======== COMMANDS ====(Called from Client Thread)==================================== */
+    void getPowerStateChangesCommand(std::function<void(bool)> powerStateCb);
+    /* ======== UTILITIES ================================================================== */
+    void reportPowerStateIfChanged();
+    void savePowerStateCallback(std::function<void(bool)> powerStateCb){
+            mPowerStateCb = powerStateCb; }
+    bool getPowerState() { return mPowerOn; }
+    inline PowerStateType getSystemPowerState() { return mSystemPowerState; }
+
+    void setAllowFlpNetworkFixes(uint32_t allow) { mAllowFlpNetworkFixes = allow; }
+    uint32_t getAllowFlpNetworkFixes() { return mAllowFlpNetworkFixes; }
+    void setSuplHostServer(const char* server, int port, LocServerType type);
+    void notifyClientOfCachedLocationSystemInfo(LocationAPI* client,
+                                                const LocationCallbacks& callbacks);
+    LocationCapabilitiesMask getCapabilities();
+    void updateSystemPowerStateCommand(PowerStateType systemPowerState);
+
+    /*==== DGnss Usable Report Flag ====================================================*/
+    inline void setDGnssUsableFLag(bool dGnssNeedReport) { mDGnssNeedReport = dGnssNeedReport;}
+    inline bool isNMEAPrintEnabled() {
+       return ((mContext != NULL) && (0 != mContext->mGps_conf.ENABLE_NMEA_PRINT));
+    }
+
+    /*==== DGnss Ntrip Source ==========================================================*/
+    void updateNTRIPGGAConsentCommand(bool consentAccepted) { mSendNmeaConsent = consentAccepted; }
+    void enablePPENtripStreamCommand(const GnssNtripConnectionParams& params, bool enableRTKEngine);
+    void disablePPENtripStreamCommand();
+    void handleEnablePPENtrip(const GnssNtripConnectionParams& params);
+    void handleDisablePPENtrip();
+    void reportGGAToNtrip(const char* nmea);
+    inline bool isDgnssNmeaRequired() { return mSendNmeaConsent &&
+            mStartDgnssNtripParams.ntripParams.requiresNmeaLocation;}
+};
+
+#endif //GNSS_ADAPTER_H
diff --git a/gps/gnss/Makefile.am b/gps/gnss/Makefile.am
new file mode 100644
index 0000000..dd313a1
--- /dev/null
+++ b/gps/gnss/Makefile.am
@@ -0,0 +1,32 @@
+AM_CFLAGS = \
+     $(LOCPLA_CFLAGS) \
+     $(LOCHAL_CFLAGS) \
+     $(GPSUTILS_CFLAGS) \
+     $(LOCCORE_CFLAGS) \
+     -I./ \
+     -I../utils \
+     -I$(WORKSPACE)/hardware/qcom/gps/core/data-items \
+     -I../location \
+     -std=c++1y
+
+libgnss_la_SOURCES = \
+    location_gnss.cpp \
+    GnssAdapter.cpp \
+    XtraSystemStatusObserver.cpp \
+    Agps.cpp \
+    NativeAgpsHandler.cpp
+
+if USE_GLIB
+libgnss_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+libgnss_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -avoid-version
+libgnss_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+libgnss_la_CFLAGS = $(AM_CFLAGS)
+libgnss_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0
+libgnss_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+libgnss_la_LIBADD = -lstdc++ -ldl $(GPSUTILS_LIBS) $(LOCCORE_LIBS)
+
+#Create and Install libraries
+lib_LTLIBRARIES = libgnss.la
diff --git a/gps/gnss/NativeAgpsHandler.cpp b/gps/gnss/NativeAgpsHandler.cpp
new file mode 100644
index 0000000..ce4c03a
--- /dev/null
+++ b/gps/gnss/NativeAgpsHandler.cpp
@@ -0,0 +1,127 @@
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_TAG "LocSvc_NativeAgpsHandler"
+
+#include <LocAdapterBase.h>
+#include <SystemStatus.h>
+#include <DataItemId.h>
+#include <DataItemsFactoryProxy.h>
+#include <DataItemConcreteTypesBase.h>
+#include <loc_log.h>
+#include <NativeAgpsHandler.h>
+#include <GnssAdapter.h>
+
+using namespace loc_core;
+
+// IDataItemObserver overrides
+void NativeAgpsHandler::getName(string& name) {
+    name = "NativeAgpsHandler";
+}
+
+void NativeAgpsHandler::notify(const list<IDataItemCore*>& dlist) {
+    for (auto each : dlist) {
+        switch (each->getId()) {
+            case NETWORKINFO_DATA_ITEM_ID: {
+                    NetworkInfoDataItemBase* networkInfo =
+                        static_cast<NetworkInfoDataItemBase*>(each);
+                    uint64_t mobileBit = (uint64_t )1 << loc_core::TYPE_MOBILE;
+                    uint64_t allTypes = networkInfo->mAllTypes;
+                    mConnected = ((networkInfo->mAllTypes & mobileBit) == mobileBit);
+                    /**
+                     * mApn Telephony preferred Access Point Name to use for
+                     * carrier data connection when connected to a cellular network.
+                     * Empty string, otherwise.
+                     */
+                    mApn = networkInfo->mApn;
+                    LOC_LOGd("updated mConnected:%d, mApn: %s", mConnected, mApn.c_str());
+                    break;
+            }
+            default:
+                    break;
+        }
+    }
+}
+
+NativeAgpsHandler* NativeAgpsHandler::sLocalHandle = nullptr;
+NativeAgpsHandler::NativeAgpsHandler(IOsObserver* sysStatObs, GnssAdapter& adapter) :
+        mSystemStatusObsrvr(sysStatObs), mConnected(false), mAdapter(adapter) {
+    sLocalHandle = this;
+    list<DataItemId> subItemIdList = {NETWORKINFO_DATA_ITEM_ID};
+    mSystemStatusObsrvr->subscribe(subItemIdList, this);
+}
+
+NativeAgpsHandler::~NativeAgpsHandler() {
+    if (nullptr != mSystemStatusObsrvr) {
+        LOC_LOGd("Unsubscribe for network info.");
+        list<DataItemId> subItemIdList = {NETWORKINFO_DATA_ITEM_ID};
+        mSystemStatusObsrvr->unsubscribe(subItemIdList, this);
+    }
+    sLocalHandle = nullptr;
+    mSystemStatusObsrvr = nullptr;
+}
+
+
+AgpsCbInfo NativeAgpsHandler::getAgpsCbInfo() {
+    AgpsCbInfo nativeCbInfo = {};
+    nativeCbInfo.statusV4Cb = (void*)agnssStatusIpV4Cb;
+    nativeCbInfo.atlType = AGPS_ATL_TYPE_WWAN;
+    return nativeCbInfo;
+}
+
+void NativeAgpsHandler::agnssStatusIpV4Cb(AGnssExtStatusIpV4 statusInfo) {
+    if (nullptr != sLocalHandle) {
+        sLocalHandle->processATLRequestRelease(statusInfo);
+    } else {
+        LOC_LOGe("sLocalHandle is null");
+    }
+}
+
+void NativeAgpsHandler::processATLRequestRelease(AGnssExtStatusIpV4 statusInfo) {
+    if (LOC_AGPS_TYPE_WWAN_ANY == statusInfo.type) {
+        LOC_LOGd("status.type = %d status.apnTypeMask = 0x%X", statusInfo.type,
+                 statusInfo.apnTypeMask);
+        switch (statusInfo.status) {
+        case LOC_GPS_REQUEST_AGPS_DATA_CONN:
+            if (mConnected) {
+                mAdapter.dataConnOpenCommand(LOC_AGPS_TYPE_WWAN_ANY, mApn.c_str(), mApn.size(),
+                    AGPS_APN_BEARER_IPV4);
+            } else {
+                mAdapter.dataConnFailedCommand(LOC_AGPS_TYPE_WWAN_ANY);
+            }
+            break;
+        case LOC_GPS_RELEASE_AGPS_DATA_CONN:
+            mAdapter.dataConnClosedCommand(LOC_AGPS_TYPE_WWAN_ANY);
+            break;
+        default:
+            LOC_LOGe("Invalid Request: %d", statusInfo.status);
+        }
+    } else {
+        LOC_LOGe("mAgpsManger is null or invalid request type!");
+    }
+}
diff --git a/gps/gnss/NativeAgpsHandler.h b/gps/gnss/NativeAgpsHandler.h
new file mode 100644
index 0000000..fb0b46c
--- /dev/null
+++ b/gps/gnss/NativeAgpsHandler.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef NATIVEAGPSHANDLER_H
+#define NATIVEAGPSHANDLER_H
+
+#include <cinttypes>
+#include <string.h>
+#include <gps_extended_c.h>
+#include <IDataItemObserver.h>
+#include <IDataItemCore.h>
+#include <IOsObserver.h>
+
+using namespace std;
+using loc_core::IOsObserver;
+using loc_core::IDataItemObserver;
+using loc_core::IDataItemCore;
+
+class GnssAdapter;
+
+class NativeAgpsHandler : public IDataItemObserver {
+public:
+    NativeAgpsHandler(IOsObserver* sysStatObs, GnssAdapter& adapter);
+    ~NativeAgpsHandler();
+    AgpsCbInfo getAgpsCbInfo();
+    // IDataItemObserver overrides
+    virtual void notify(const list<IDataItemCore*>& dlist);
+    inline virtual void getName(string& name);
+private:
+    static NativeAgpsHandler* sLocalHandle;
+    static void agnssStatusIpV4Cb(AGnssExtStatusIpV4 statusInfo);
+    void processATLRequestRelease(AGnssExtStatusIpV4 statusInfo);
+    IOsObserver* mSystemStatusObsrvr;
+    bool mConnected;
+    string mApn;
+    GnssAdapter& mAdapter;
+};
+
+#endif // NATIVEAGPSHANDLER_H
diff --git a/gps/gnss/XtraSystemStatusObserver.cpp b/gps/gnss/XtraSystemStatusObserver.cpp
new file mode 100644
index 0000000..d65622f
--- /dev/null
+++ b/gps/gnss/XtraSystemStatusObserver.cpp
@@ -0,0 +1,384 @@
+/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_TAG "LocSvc_XtraSystemStatusObs"
+
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include <math.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string>
+#include <loc_log.h>
+#include <loc_nmea.h>
+#include <SystemStatus.h>
+#include <vector>
+#include <sstream>
+#include <XtraSystemStatusObserver.h>
+#include <LocAdapterBase.h>
+#include <DataItemId.h>
+#include <DataItemsFactoryProxy.h>
+#include <DataItemConcreteTypesBase.h>
+
+using namespace loc_util;
+using namespace loc_core;
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LocSvc_XSSO"
+
+class XtraIpcListener : public ILocIpcListener {
+    IOsObserver*    mSystemStatusObsrvr;
+    const MsgTask* mMsgTask;
+    XtraSystemStatusObserver& mXSSO;
+public:
+    inline XtraIpcListener(IOsObserver* observer, const MsgTask* msgTask,
+                           XtraSystemStatusObserver& xsso) :
+            mSystemStatusObsrvr(observer), mMsgTask(msgTask), mXSSO(xsso) {}
+    virtual void onReceive(const char* data, uint32_t length,
+                           const LocIpcRecver* recver) override {
+#define STRNCMP(str, constStr) strncmp(str, constStr, sizeof(constStr)-1)
+        if (!STRNCMP(data, "ping")) {
+            LOC_LOGd("ping received");
+#ifdef USE_GLIB
+        } else if (!STRNCMP(data, "connectBackhaul")) {
+            char clientName[30] = {0};
+            sscanf(data, "%*s %29s", clientName);
+            mSystemStatusObsrvr->connectBackhaul(string(clientName));
+        } else if (!STRNCMP(data, "disconnectBackhaul")) {
+            char clientName[30] = {0};
+            sscanf(data, "%*s %29s", clientName);
+            mSystemStatusObsrvr->disconnectBackhaul(string(clientName));
+#endif
+        } else if (!STRNCMP(data, "requestStatus")) {
+            int32_t xtraStatusUpdated = 0;
+            sscanf(data, "%*s %d", &xtraStatusUpdated);
+
+            struct HandleStatusRequestMsg : public LocMsg {
+                XtraSystemStatusObserver& mXSSO;
+                int32_t mXtraStatusUpdated;
+                inline HandleStatusRequestMsg(XtraSystemStatusObserver& xsso,
+                                              int32_t xtraStatusUpdated) :
+                        mXSSO(xsso), mXtraStatusUpdated(xtraStatusUpdated) {}
+                inline void proc() const override {
+                    mXSSO.onStatusRequested(mXtraStatusUpdated);
+                    /* SSR for DGnss Ntrip Source*/
+                    mXSSO.restartDgnssSource();
+                }
+            };
+            mMsgTask->sendMsg(new HandleStatusRequestMsg(mXSSO, xtraStatusUpdated));
+        } else {
+            LOC_LOGw("unknown event: %s", data);
+        }
+    }
+};
+
+XtraSystemStatusObserver::XtraSystemStatusObserver(IOsObserver* sysStatObs,
+                                                   const MsgTask* msgTask) :
+        mSystemStatusObsrvr(sysStatObs), mMsgTask(msgTask),
+        mGpsLock(-1), mConnections(~0), mXtraThrottle(true),
+        mReqStatusReceived(false),
+        mIsConnectivityStatusKnown(false),
+        mSender(LocIpc::getLocIpcLocalSender(LOC_IPC_XTRA)),
+        mDelayLocTimer(*mSender) {
+    subscribe(true);
+    auto recver = LocIpc::getLocIpcLocalRecver(
+            make_shared<XtraIpcListener>(sysStatObs, msgTask, *this),
+            LOC_IPC_HAL);
+    mIpc.startNonBlockingListening(recver);
+    mDelayLocTimer.start(100 /*.1 sec*/,  false);
+}
+
+bool XtraSystemStatusObserver::updateLockStatus(GnssConfigGpsLock lock) {
+    // mask NI(NFW bit) since from XTRA's standpoint GPS is enabled if
+    // MO(AFW bit) is enabled and disabled when MO is disabled
+    mGpsLock = lock & ~GNSS_CONFIG_GPS_LOCK_NI;
+
+    if (!mReqStatusReceived) {
+        return true;
+    }
+
+    stringstream ss;
+    ss <<  "gpslock";
+    ss << " " << mGpsLock;
+    string s = ss.str();
+    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+bool XtraSystemStatusObserver::updateConnections(uint64_t allConnections,
+        NetworkInfoType* networkHandleInfo) {
+    mIsConnectivityStatusKnown = true;
+    mConnections = allConnections;
+
+    LOC_LOGd("updateConnections mConnections:%" PRIx64, mConnections);
+    for (uint8_t i = 0; i < MAX_NETWORK_HANDLES; ++i) {
+        mNetworkHandle[i] = networkHandleInfo[i];
+        LOC_LOGd("updateConnections [%d] networkHandle:%" PRIx64 " networkType:%u",
+            i, mNetworkHandle[i].networkHandle, mNetworkHandle[i].networkType);
+    }
+
+    if (!mReqStatusReceived) {
+        return true;
+    }
+
+    stringstream ss;
+    ss << "connection" << endl << mConnections << endl
+            << mNetworkHandle[0].toString() << endl
+            << mNetworkHandle[1].toString() << endl
+            << mNetworkHandle[2].toString() << endl
+            << mNetworkHandle[3].toString() << endl
+            << mNetworkHandle[4].toString() << endl
+            << mNetworkHandle[5].toString() << endl
+            << mNetworkHandle[6].toString() << endl
+            << mNetworkHandle[7].toString() << endl
+            << mNetworkHandle[8].toString() << endl
+            << mNetworkHandle[MAX_NETWORK_HANDLES-1].toString();
+    string s = ss.str();
+    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+bool XtraSystemStatusObserver::updateTac(const string& tac) {
+    mTac = tac;
+
+    if (!mReqStatusReceived) {
+        return true;
+    }
+
+    stringstream ss;
+    ss <<  "tac";
+    ss << " " << tac.c_str();
+    string s = ss.str();
+    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+bool XtraSystemStatusObserver::updateMccMnc(const string& mccmnc) {
+    mMccmnc = mccmnc;
+
+    if (!mReqStatusReceived) {
+        return true;
+    }
+
+    stringstream ss;
+    ss <<  "mncmcc";
+    ss << " " << mccmnc.c_str();
+    string s = ss.str();
+    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+bool XtraSystemStatusObserver::updateXtraThrottle(const bool enabled) {
+    mXtraThrottle = enabled;
+
+    if (!mReqStatusReceived) {
+        return true;
+    }
+
+    stringstream ss;
+    ss <<  "xtrathrottle";
+    ss << " " << (enabled ? 1 : 0);
+    string s = ss.str();
+    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+inline bool XtraSystemStatusObserver::onStatusRequested(int32_t xtraStatusUpdated) {
+    mReqStatusReceived = true;
+
+    if (xtraStatusUpdated) {
+        return true;
+    }
+
+    stringstream ss;
+
+    ss << "respondStatus" << endl;
+    (mGpsLock == -1 ? ss : ss << mGpsLock) << endl;
+    (mConnections == (uint64_t)~0 ? ss : ss << mConnections) << endl
+            << mNetworkHandle[0].toString() << endl
+            << mNetworkHandle[1].toString() << endl
+            << mNetworkHandle[2].toString() << endl
+            << mNetworkHandle[3].toString() << endl
+            << mNetworkHandle[4].toString() << endl
+            << mNetworkHandle[5].toString() << endl
+            << mNetworkHandle[6].toString() << endl
+            << mNetworkHandle[7].toString() << endl
+            << mNetworkHandle[8].toString() << endl
+            << mNetworkHandle[MAX_NETWORK_HANDLES-1].toString() << endl
+            << mTac << endl << mMccmnc << endl << mIsConnectivityStatusKnown;
+
+    string s = ss.str();
+    return ( LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size()) );
+}
+
+void XtraSystemStatusObserver::startDgnssSource(const StartDgnssNtripParams& params) {
+    stringstream ss;
+    const GnssNtripConnectionParams* ntripParams = &(params.ntripParams);
+
+    ss <<  "startDgnssSource" << endl;
+    ss << ntripParams->useSSL << endl;
+    ss << ntripParams->hostNameOrIp.data() << endl;
+    ss << ntripParams->port << endl;
+    ss << ntripParams->mountPoint.data() << endl;
+    ss << ntripParams->username.data() << endl;
+    ss << ntripParams->password.data() << endl;
+    if (ntripParams->requiresNmeaLocation && !params.nmea.empty()) {
+        ss << params.nmea.data() << endl;
+    }
+    string s = ss.str();
+
+    LOC_LOGd("%s", s.data());
+    LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size());
+    // make a local copy of the string for SSR
+    mNtripParamsString.assign(std::move(s));
+}
+
+void XtraSystemStatusObserver::restartDgnssSource() {
+    if (!mNtripParamsString.empty()) {
+        LocIpc::send(*mSender,
+            (const uint8_t*)mNtripParamsString.data(), mNtripParamsString.size());
+        LOC_LOGv("Xtra SSR %s", mNtripParamsString.data());
+    }
+}
+
+void XtraSystemStatusObserver::stopDgnssSource() {
+    LOC_LOGv();
+    mNtripParamsString.clear();
+
+    const char s[] = "stopDgnssSource";
+    LocIpc::send(*mSender, (const uint8_t*)s, strlen(s));
+}
+
+void XtraSystemStatusObserver::updateNmeaToDgnssServer(const string& nmea)
+{
+    stringstream ss;
+    ss <<  "updateDgnssServerNmea" << endl;
+    ss << nmea.data() << endl;
+
+    string s = ss.str();
+    LOC_LOGd("%s", s.data());
+    LocIpc::send(*mSender, (const uint8_t*)s.data(), s.size());
+}
+
+void XtraSystemStatusObserver::subscribe(bool yes)
+{
+    // Subscription data list
+    list<DataItemId> subItemIdList;
+    subItemIdList.push_back(NETWORKINFO_DATA_ITEM_ID);
+    subItemIdList.push_back(MCCMNC_DATA_ITEM_ID);
+
+    if (yes) {
+        mSystemStatusObsrvr->subscribe(subItemIdList, this);
+
+        list<DataItemId> reqItemIdList;
+        reqItemIdList.push_back(TAC_DATA_ITEM_ID);
+
+        mSystemStatusObsrvr->requestData(reqItemIdList, this);
+
+    } else {
+        mSystemStatusObsrvr->unsubscribe(subItemIdList, this);
+    }
+}
+
+// IDataItemObserver overrides
+void XtraSystemStatusObserver::getName(string& name)
+{
+    name = "XtraSystemStatusObserver";
+}
+
+void XtraSystemStatusObserver::notify(const list<IDataItemCore*>& dlist)
+{
+    struct HandleOsObserverUpdateMsg : public LocMsg {
+        XtraSystemStatusObserver* mXtraSysStatObj;
+        list <IDataItemCore*> mDataItemList;
+
+        inline HandleOsObserverUpdateMsg(XtraSystemStatusObserver* xtraSysStatObs,
+                const list<IDataItemCore*>& dataItemList) :
+                mXtraSysStatObj(xtraSysStatObs) {
+            for (auto eachItem : dataItemList) {
+                IDataItemCore* dataitem = DataItemsFactoryProxy::createNewDataItem(
+                        eachItem->getId());
+                if (NULL == dataitem) {
+                    break;
+                }
+                // Copy the contents of the data item
+                dataitem->copy(eachItem);
+
+                mDataItemList.push_back(dataitem);
+            }
+        }
+
+        inline ~HandleOsObserverUpdateMsg() {
+            for (auto itor = mDataItemList.begin(); itor != mDataItemList.end(); ++itor) {
+                if (*itor != nullptr) {
+                    delete *itor;
+                    *itor = nullptr;
+                }
+            }
+        }
+
+        inline void proc() const {
+            for (auto each : mDataItemList) {
+                switch (each->getId())
+                {
+                    case NETWORKINFO_DATA_ITEM_ID:
+                    {
+                        NetworkInfoDataItemBase* networkInfo =
+                                static_cast<NetworkInfoDataItemBase*>(each);
+                        NetworkInfoType* networkHandleInfo =
+                                static_cast<NetworkInfoType*>(networkInfo->getNetworkHandle());
+                        mXtraSysStatObj->updateConnections(networkInfo->getAllTypes(),
+                                networkHandleInfo);
+                    }
+                    break;
+
+                    case TAC_DATA_ITEM_ID:
+                    {
+                        TacDataItemBase* tac =
+                                 static_cast<TacDataItemBase*>(each);
+                        mXtraSysStatObj->updateTac(tac->mValue);
+                    }
+                    break;
+
+                    case MCCMNC_DATA_ITEM_ID:
+                    {
+                        MccmncDataItemBase* mccmnc =
+                                static_cast<MccmncDataItemBase*>(each);
+                        mXtraSysStatObj->updateMccMnc(mccmnc->mValue);
+                    }
+                    break;
+
+                    default:
+                    break;
+                }
+            }
+        }
+    };
+    mMsgTask->sendMsg(new (nothrow) HandleOsObserverUpdateMsg(this, dlist));
+}
diff --git a/gps/gnss/XtraSystemStatusObserver.h b/gps/gnss/XtraSystemStatusObserver.h
new file mode 100644
index 0000000..56a3a9c
--- /dev/null
+++ b/gps/gnss/XtraSystemStatusObserver.h
@@ -0,0 +1,112 @@
+/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef XTRA_SYSTEM_STATUS_OBS_H
+#define XTRA_SYSTEM_STATUS_OBS_H
+
+#include <cinttypes>
+#include <MsgTask.h>
+#include <LocIpc.h>
+#include <LocTimer.h>
+#include <stdlib.h>
+
+using namespace std;
+using namespace loc_util;
+using loc_core::IOsObserver;
+using loc_core::IDataItemObserver;
+using loc_core::IDataItemCore;
+
+struct StartDgnssNtripParams {
+    GnssNtripConnectionParams ntripParams;
+    string                    nmea;
+
+    void clear() {
+        ntripParams.hostNameOrIp.clear();
+        ntripParams.mountPoint.clear();
+        ntripParams.username.clear();
+        ntripParams.password.clear();
+        ntripParams.port = 0;
+        ntripParams.useSSL = false;
+        ntripParams.requiresNmeaLocation = false;
+        nmea.clear();
+    }
+};
+
+class XtraSystemStatusObserver : public IDataItemObserver {
+public :
+    // constructor & destructor
+    XtraSystemStatusObserver(IOsObserver* sysStatObs, const MsgTask* msgTask);
+    inline virtual ~XtraSystemStatusObserver() {
+        subscribe(false);
+        mIpc.stopNonBlockingListening();
+    }
+
+    // IDataItemObserver overrides
+    inline virtual void getName(string& name);
+    virtual void notify(const list<IDataItemCore*>& dlist);
+
+    bool updateLockStatus(GnssConfigGpsLock lock);
+    bool updateConnections(uint64_t allConnections,
+            loc_core::NetworkInfoType* networkHandleInfo);
+    bool updateTac(const string& tac);
+    bool updateMccMnc(const string& mccmnc);
+    bool updateXtraThrottle(const bool enabled);
+    inline const MsgTask* getMsgTask() { return mMsgTask; }
+    void subscribe(bool yes);
+    bool onStatusRequested(int32_t xtraStatusUpdated);
+    void startDgnssSource(const StartDgnssNtripParams& params);
+    void restartDgnssSource();
+    void stopDgnssSource();
+    void updateNmeaToDgnssServer(const string& nmea);
+
+private:
+    IOsObserver*    mSystemStatusObsrvr;
+    const MsgTask* mMsgTask;
+    GnssConfigGpsLock mGpsLock;
+    LocIpc mIpc;
+    uint64_t mConnections;
+    loc_core::NetworkInfoType mNetworkHandle[MAX_NETWORK_HANDLES];
+    string mTac;
+    string mMccmnc;
+    bool mXtraThrottle;
+    bool mReqStatusReceived;
+    bool mIsConnectivityStatusKnown;
+    shared_ptr<LocIpcSender> mSender;
+    string mNtripParamsString;
+
+    class DelayLocTimer : public LocTimer {
+        LocIpcSender& mSender;
+    public:
+        DelayLocTimer(LocIpcSender& sender) : mSender(sender) {}
+        void timeOutCallback() override {
+            LocIpc::send(mSender, (const uint8_t*)"halinit", sizeof("halinit"));
+        }
+    } mDelayLocTimer;
+};
+
+#endif
diff --git a/gps/gnss/location_gnss.cpp b/gps/gnss/location_gnss.cpp
new file mode 100644
index 0000000..8f67369
--- /dev/null
+++ b/gps/gnss/location_gnss.cpp
@@ -0,0 +1,593 @@
+/* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "GnssAdapter.h"
+#include "location_interface.h"
+
+static GnssAdapter* gGnssAdapter = NULL;
+
+static void initialize();
+static void deinitialize();
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks);
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+static void requestCapabilities(LocationAPI* client);
+
+static uint32_t startTracking(LocationAPI* client, TrackingOptions&);
+static void updateTrackingOptions(LocationAPI* client, uint32_t id, TrackingOptions&);
+static void stopTracking(LocationAPI* client, uint32_t id);
+
+static void gnssNiResponse(LocationAPI* client, uint32_t id, GnssNiResponse response);
+static uint32_t gnssDeleteAidingData(GnssAidingData& data);
+static void gnssUpdateXtraThrottle(const bool enabled);
+
+static void setControlCallbacks(LocationControlCallbacks& controlCallbacks);
+static uint32_t enable(LocationTechnologyType techType);
+static void disable(uint32_t id);
+static uint32_t* gnssUpdateConfig(const 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 injectLocationExt(const GnssLocationInfoNotification &locationInfo);
+static void injectTime(int64_t time, int64_t timeReference, int32_t uncertainty);
+
+static void agpsInit(const AgpsCbInfo& cbInfo);
+static void agpsDataConnOpen(AGpsExtType agpsType, const char* apnName, int apnLen, int ipType);
+static void agpsDataConnClosed(AGpsExtType agpsType);
+static void agpsDataConnFailed(AGpsExtType agpsType);
+static void getDebugReport(GnssDebugReport& report);
+static void updateConnectionStatus(bool connected, int8_t type, bool roaming,
+                                   NetworkHandle networkHandle, string& apn);
+static void getGnssEnergyConsumed(GnssEnergyConsumedCallback energyConsumedCb);
+static void enableNfwLocationAccess(bool enable);
+static void nfwInit(const NfwCbInfo& cbInfo);
+static void getPowerStateChanges(std::function<void(bool)> powerStateCb);
+
+static void odcpiInit(const OdcpiRequestCallback& callback, OdcpiPrioritytype priority);
+static void odcpiInject(const Location& location);
+
+static void blockCPI(double latitude, double longitude, float accuracy,
+                     int blockDurationMsec, double latLonDiffThreshold);
+static void updateBatteryStatus(bool charging);
+static void updateSystemPowerState(PowerStateType systemPowerState);
+static uint32_t setConstrainedTunc (bool enable, float tuncConstraint,
+                                    uint32_t energyBudget);
+static uint32_t setPositionAssistedClockEstimator(bool enable);
+static uint32_t gnssUpdateSvConfig(const GnssSvTypeConfig& constellationEnablementConfig,
+                                   const GnssSvIdConfig& blacklistSvConfig);
+static uint32_t gnssResetSvConfig();
+static uint32_t configLeverArm(const LeverArmConfigInfo& configInfo);
+static uint32_t configRobustLocation(bool enable, bool enableForE911);
+static uint32_t configMinGpsWeek(uint16_t minGpsWeek);
+static uint32_t configDeadReckoningEngineParams(const DeadReckoningEngineConfig& dreConfig);
+static uint32_t gnssUpdateSecondaryBandConfig(const GnssSvTypeConfig& secondaryBandConfig);
+static uint32_t gnssGetSecondaryBandConfig();
+static void resetNetworkInfo();
+
+static void updateNTRIPGGAConsent(bool consentAccepted);
+static void enablePPENtripStream(const GnssNtripConnectionParams& params, bool enableRTKEngine);
+static void disablePPENtripStream();
+
+static bool measCorrInit(const measCorrSetCapabilitiesCb setCapabilitiesCb);
+static bool measCorrSetCorrections(const GnssMeasurementCorrections gnssMeasCorr);
+static void measCorrClose();
+static uint32_t antennaInfoInit(const antennaInfoCb antennaInfoCallback);
+static void antennaInfoClose();
+static uint32_t configEngineRunState(PositioningEngineMask engType, LocEngineRunState engState);
+
+static const GnssInterface gGnssInterface = {
+    sizeof(GnssInterface),
+    initialize,
+    deinitialize,
+    addClient,
+    removeClient,
+    requestCapabilities,
+    startTracking,
+    updateTrackingOptions,
+    stopTracking,
+    gnssNiResponse,
+    setControlCallbacks,
+    enable,
+    disable,
+    gnssUpdateConfig,
+    gnssGetConfig,
+    gnssUpdateSvTypeConfig,
+    gnssGetSvTypeConfig,
+    gnssResetSvTypeConfig,
+    gnssDeleteAidingData,
+    gnssUpdateXtraThrottle,
+    injectLocation,
+    injectTime,
+    agpsInit,
+    agpsDataConnOpen,
+    agpsDataConnClosed,
+    agpsDataConnFailed,
+    getDebugReport,
+    updateConnectionStatus,
+    odcpiInit,
+    odcpiInject,
+    blockCPI,
+    getGnssEnergyConsumed,
+    enableNfwLocationAccess,
+    nfwInit,
+    getPowerStateChanges,
+    injectLocationExt,
+    updateBatteryStatus,
+    updateSystemPowerState,
+    setConstrainedTunc,
+    setPositionAssistedClockEstimator,
+    gnssUpdateSvConfig,
+    configLeverArm,
+    measCorrInit,
+    measCorrSetCorrections,
+    measCorrClose,
+    antennaInfoInit,
+    antennaInfoClose,
+    configRobustLocation,
+    configMinGpsWeek,
+    configDeadReckoningEngineParams,
+    updateNTRIPGGAConsent,
+    enablePPENtripStream,
+    disablePPENtripStream,
+    gnssUpdateSecondaryBandConfig,
+    gnssGetSecondaryBandConfig,
+    resetNetworkInfo,
+    configEngineRunState
+};
+
+#ifndef DEBUG_X86
+extern "C" const GnssInterface* getGnssInterface()
+#else
+const GnssInterface* getGnssInterface()
+#endif // DEBUG_X86
+{
+   gGnssInterface.initialize();
+   return &gGnssInterface;
+}
+
+static void initialize()
+{
+    if (NULL == gGnssAdapter) {
+        gGnssAdapter = new GnssAdapter();
+    }
+}
+
+static void deinitialize()
+{
+    if (NULL != gGnssAdapter) {
+        delete gGnssAdapter;
+        gGnssAdapter = NULL;
+    }
+}
+
+static void addClient(LocationAPI* client, const LocationCallbacks& callbacks)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->addClientCommand(client, callbacks);
+    }
+}
+
+static void removeClient(LocationAPI* client, removeClientCompleteCallback rmClientCb)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->removeClientCommand(client, rmClientCb);
+    }
+}
+
+static void requestCapabilities(LocationAPI* client)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->requestCapabilitiesCommand(client);
+    }
+}
+
+static uint32_t startTracking(
+        LocationAPI* client, TrackingOptions& trackingOptions)
+{
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->startTrackingCommand(client, trackingOptions);
+    } else {
+        return 0;
+    }
+}
+
+static void updateTrackingOptions(
+        LocationAPI* client, uint32_t id, TrackingOptions& trackingOptions)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->updateTrackingOptionsCommand(
+                client, id, trackingOptions);
+    }
+}
+
+static void stopTracking(LocationAPI* client, uint32_t id)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->stopTrackingCommand(client, id);
+    }
+}
+
+static void gnssNiResponse(LocationAPI* client, uint32_t id, GnssNiResponse response)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->gnssNiResponseCommand(client, id, response);
+    }
+}
+
+static void setControlCallbacks(LocationControlCallbacks& controlCallbacks)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->setControlCallbacksCommand(controlCallbacks);
+    }
+}
+
+static uint32_t enable(LocationTechnologyType techType)
+{
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->enableCommand(techType);
+    } else {
+        return 0;
+    }
+}
+
+static void disable(uint32_t id)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->disableCommand(id);
+    }
+}
+
+static uint32_t* gnssUpdateConfig(const GnssConfig& config)
+{
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->gnssUpdateConfigCommand(config);
+    } else {
+        return NULL;
+    }
+}
+
+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) {
+        return gGnssAdapter->gnssDeleteAidingDataCommand(data);
+    } else {
+        return 0;
+    }
+}
+
+static void gnssUpdateXtraThrottle(const bool enabled)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->gnssUpdateXtraThrottleCommand(enabled);
+    }
+}
+
+static void injectLocation(double latitude, double longitude, float accuracy)
+{
+   if (NULL != gGnssAdapter) {
+       gGnssAdapter->injectLocationCommand(latitude, longitude, accuracy);
+   }
+}
+
+static void injectTime(int64_t time, int64_t timeReference, int32_t uncertainty)
+{
+   if (NULL != gGnssAdapter) {
+       gGnssAdapter->injectTimeCommand(time, timeReference, uncertainty);
+   }
+}
+
+static void agpsInit(const AgpsCbInfo& cbInfo) {
+
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->initAgpsCommand(cbInfo);
+    }
+}
+static void agpsDataConnOpen(
+        AGpsExtType agpsType, const char* apnName, int apnLen, int ipType) {
+
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->dataConnOpenCommand(
+                agpsType, apnName, apnLen, (AGpsBearerType)ipType);
+    }
+}
+static void agpsDataConnClosed(AGpsExtType agpsType) {
+
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->dataConnClosedCommand(agpsType);
+    }
+}
+static void agpsDataConnFailed(AGpsExtType agpsType) {
+
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->dataConnFailedCommand(agpsType);
+    }
+}
+
+static void getDebugReport(GnssDebugReport& report) {
+
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->getDebugReport(report);
+    }
+}
+
+static void updateConnectionStatus(bool connected, int8_t type,
+                                   bool roaming, NetworkHandle networkHandle,
+                                   string& apn) {
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->getSystemStatus()->eventConnectionStatus(
+                connected, type, roaming, networkHandle, apn);
+    }
+}
+
+static void odcpiInit(const OdcpiRequestCallback& callback, OdcpiPrioritytype priority)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->initOdcpiCommand(callback, priority);
+    }
+}
+
+static void odcpiInject(const Location& location)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->injectOdcpiCommand(location);
+    }
+}
+
+static void blockCPI(double latitude, double longitude, float accuracy,
+                     int blockDurationMsec, double latLonDiffThreshold) {
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->blockCPICommand(latitude, longitude, accuracy,
+                                      blockDurationMsec, latLonDiffThreshold);
+    }
+}
+
+static void getGnssEnergyConsumed(GnssEnergyConsumedCallback energyConsumedCb) {
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->getGnssEnergyConsumedCommand(energyConsumedCb);
+    }
+}
+
+static void enableNfwLocationAccess(bool enable) {
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->nfwControlCommand(enable);
+    }
+}
+
+static void nfwInit(const NfwCbInfo& cbInfo) {
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->initNfwCommand(cbInfo);
+    }
+}
+
+static void getPowerStateChanges(std::function<void(bool)> powerStateCb)
+{
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->getPowerStateChangesCommand(powerStateCb);
+    }
+}
+
+static void injectLocationExt(const GnssLocationInfoNotification &locationInfo)
+{
+   if (NULL != gGnssAdapter) {
+       gGnssAdapter->injectLocationExtCommand(locationInfo);
+   }
+}
+
+static void updateBatteryStatus(bool charging) {
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->getSystemStatus()->updatePowerConnectState(charging);
+    }
+}
+
+static void resetNetworkInfo() {
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->getSystemStatus()->resetNetworkInfo();
+    }
+}
+
+static void updateSystemPowerState(PowerStateType systemPowerState) {
+   if (NULL != gGnssAdapter) {
+       gGnssAdapter->updateSystemPowerStateCommand(systemPowerState);
+   }
+}
+
+static uint32_t setConstrainedTunc (bool enable, float tuncConstraint, uint32_t energyBudget) {
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->setConstrainedTuncCommand(enable, tuncConstraint, energyBudget);
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t setPositionAssistedClockEstimator(bool enable) {
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->setPositionAssistedClockEstimatorCommand(enable);
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t gnssUpdateSvConfig(
+        const GnssSvTypeConfig& constellationEnablementConfig,
+        const GnssSvIdConfig&   blacklistSvConfig) {
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->gnssUpdateSvConfigCommand(
+                constellationEnablementConfig, blacklistSvConfig);
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t configLeverArm(const LeverArmConfigInfo& configInfo){
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->configLeverArmCommand(configInfo);
+    } else {
+        return 0;
+    }
+}
+
+static bool measCorrInit(const measCorrSetCapabilitiesCb setCapabilitiesCb) {
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->openMeasCorrCommand(setCapabilitiesCb);
+    } else {
+        return false;
+    }
+}
+
+static bool measCorrSetCorrections(const GnssMeasurementCorrections gnssMeasCorr) {
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->measCorrSetCorrectionsCommand(gnssMeasCorr);
+    } else {
+        return false;
+    }
+}
+
+static void measCorrClose() {
+    if (NULL != gGnssAdapter) {
+        gGnssAdapter->closeMeasCorrCommand();
+    }
+}
+
+static uint32_t antennaInfoInit(const antennaInfoCb antennaInfoCallback) {
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->antennaInfoInitCommand(antennaInfoCallback);
+    } else {
+        return ANTENNA_INFO_ERROR_GENERIC;
+    }
+}
+
+static void antennaInfoClose() {
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->antennaInfoCloseCommand();
+    }
+}
+
+static uint32_t configRobustLocation(bool enable, bool enableForE911){
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->configRobustLocationCommand(enable, enableForE911);
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t configMinGpsWeek(uint16_t minGpsWeek){
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->configMinGpsWeekCommand(minGpsWeek);
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t configDeadReckoningEngineParams(const DeadReckoningEngineConfig& dreConfig){
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->configDeadReckoningEngineParamsCommand(dreConfig);
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t gnssUpdateSecondaryBandConfig(
+        const GnssSvTypeConfig& secondaryBandConfig) {
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->gnssUpdateSecondaryBandConfigCommand(secondaryBandConfig);
+    } else {
+        return 0;
+    }
+}
+
+static uint32_t gnssGetSecondaryBandConfig(){
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->gnssGetSecondaryBandConfigCommand();
+    } else {
+        return 0;
+    }
+}
+
+static void updateNTRIPGGAConsent(bool consentAccepted){
+    if (NULL != gGnssAdapter) {
+        // Call will be enabled once GnssAdapter impl. is ready.
+        gGnssAdapter->updateNTRIPGGAConsentCommand(consentAccepted);
+    }
+}
+
+static void enablePPENtripStream(const GnssNtripConnectionParams& params, bool enableRTKEngine){
+    if (NULL != gGnssAdapter) {
+        // Call will be enabled once GnssAdapter impl. is ready.
+        gGnssAdapter->enablePPENtripStreamCommand(params, enableRTKEngine);
+    }
+}
+
+static void disablePPENtripStream(){
+    if (NULL != gGnssAdapter) {
+        // Call will be enabled once GnssAdapter impl. is ready.
+        gGnssAdapter->disablePPENtripStreamCommand();
+    }
+}
+
+static uint32_t configEngineRunState(PositioningEngineMask engType, LocEngineRunState engState) {
+    if (NULL != gGnssAdapter) {
+        return gGnssAdapter->configEngineRunStateCommand(engType, engState);
+    } else {
+        return 0;
+    }
+}
diff --git a/gps/gps_vendor_board.mk b/gps/gps_vendor_board.mk
new file mode 100644
index 0000000..e1915ea
--- /dev/null
+++ b/gps/gps_vendor_board.mk
@@ -0,0 +1,7 @@
+# Flags from BoardConfigVendor.mk
+ifneq ($(TARGET_USES_QMAA),true)
+BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE := default
+else ifneq ($(TARGET_USES_QMAA_OVERRIDE_GPS),false)
+BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE := default
+endif
+
diff --git a/gps/gps_vendor_product.mk b/gps/gps_vendor_product.mk
new file mode 100644
index 0000000..cd35684
--- /dev/null
+++ b/gps/gps_vendor_product.mk
@@ -0,0 +1,48 @@
+# HAL packages
+ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
+
+# GPS-HIDL
+LOC_BOARD_PLATFORM_LIST += msm8937
+LOC_BOARD_PLATFORM_LIST += msm8953
+LOC_BOARD_PLATFORM_LIST += msm8998
+LOC_BOARD_PLATFORM_LIST += apq8098_latv
+LOC_BOARD_PLATFORM_LIST += sdm710
+LOC_BOARD_PLATFORM_LIST += qcs605
+LOC_BOARD_PLATFORM_LIST += sdm845
+LOC_BOARD_PLATFORM_LIST += sdm660
+LOC_BOARD_PLATFORM_LIST += msmnile
+LOC_BOARD_PLATFORM_LIST += sdmshrike
+LOC_BOARD_PLATFORM_LIST += $(MSMSTEPPE)
+LOC_BOARD_PLATFORM_LIST += $(TRINKET)
+LOC_BOARD_PLATFORM_LIST += kona
+LOC_BOARD_PLATFORM_LIST += atoll
+LOC_BOARD_PLATFORM_LIST += lito
+LOC_BOARD_PLATFORM_LIST += bengal
+LOC_BOARD_PLATFORM_LIST += lahaina
+LOC_BOARD_PLATFORM_LIST += holi
+
+# Add product packages
+ifneq (,$(filter $(LOC_BOARD_PLATFORM_LIST),$(TARGET_BOARD_PLATFORM)))
+
+PRODUCT_PACKAGES += gps.conf
+PRODUCT_PACKAGES += flp.conf
+PRODUCT_PACKAGES += gnss_antenna_info.conf
+PRODUCT_PACKAGES += gnss@2.0-base.policy
+PRODUCT_PACKAGES += gnss@2.0-xtra-daemon.policy
+PRODUCT_PACKAGES += gnss@2.0-xtwifi-client.policy
+PRODUCT_PACKAGES += gnss@2.0-xtwifi-inet-agent.policy
+PRODUCT_PACKAGES += libloc_pla_headers
+PRODUCT_PACKAGES += liblocation_api_headers
+PRODUCT_PACKAGES += libgps.utils_headers
+PRODUCT_PACKAGES += liblocation_api
+PRODUCT_PACKAGES += libgps.utils
+PRODUCT_PACKAGES += libbatching
+PRODUCT_PACKAGES += libgeofencing
+PRODUCT_PACKAGES += libloc_core
+PRODUCT_PACKAGES += libgnss
+
+PRODUCT_PACKAGES += android.hardware.gnss@2.1-impl-qti
+PRODUCT_PACKAGES += android.hardware.gnss@2.1-service-qti
+
+endif # ifneq (,$(filter $(LOC_BOARD_PLATFORM_LIST),$(TARGET_BOARD_PLATFORM)))
+endif # ifneq ($(BOARD_VENDOR_QCOM_GPS_LOC_API_HARDWARE),)
diff --git a/gps/loc-hal.pc.in b/gps/loc-hal.pc.in
new file mode 100644
index 0000000..22d174b
--- /dev/null
+++ b/gps/loc-hal.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: loc-hal
+Description: QTI GPS Loc HAL
+Version: @VERSION
+Libs: -L${libdir} -lgnss
+Cflags: -I${includedir} -I${includedir}/utils -I${includedir}/core -I${includedir}/loc-hal
diff --git a/gps/location/Android.bp b/gps/location/Android.bp
new file mode 100644
index 0000000..fb4af2d
--- /dev/null
+++ b/gps/location/Android.bp
@@ -0,0 +1,36 @@
+
+cc_library_shared {
+
+    name: "liblocation_api",
+    vendor: true,
+
+
+
+    shared_libs: [
+        "libutils",
+        "libcutils",
+        "libgps.utils",
+        "libdl",
+        "liblog",
+    ],
+
+    srcs: [
+        "LocationAPI.cpp",
+        "LocationAPIClientBase.cpp",
+    ],
+
+    cflags: ["-fno-short-enums"] + GNSS_CFLAGS,
+
+    header_libs: [
+        "libloc_pla_headers",
+        "libgps.utils_headers",
+    ],
+
+}
+
+cc_library_headers {
+
+    name: "liblocation_api_headers",
+    export_include_dirs: ["."],
+    vendor: true,
+}
diff --git a/gps/location/ILocationAPI.h b/gps/location/ILocationAPI.h
new file mode 100644
index 0000000..29846ac
--- /dev/null
+++ b/gps/location/ILocationAPI.h
@@ -0,0 +1,406 @@
+/* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ILOCATIONAPI_H
+#define ILOCATIONAPI_H
+
+#include "LocationDataTypes.h"
+
+class ILocationAPI
+{
+public:
+    virtual ~ILocationAPI(){};
+
+    /** @brief Updates/changes the callbacks that will be called.
+        mandatory callbacks must be present for callbacks to be successfully updated
+        no return value */
+    virtual void updateCallbacks(LocationCallbacks&) = 0;
+
+    /* ================================== TRACKING ================================== */
+
+    /** @brief Starts a tracking session, which returns a session id that will be
+       used by the other tracking APIs and also in the responseCallback to match command
+       with response. locations are reported on the registered trackingCallback
+       periodically according to LocationOptions.
+       @return session id
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successfully started
+                LOCATION_ERROR_ALREADY_STARTED if a startTracking session is already in progress
+                LOCATION_ERROR_CALLBACK_MISSING if no trackingCallback was passed
+                LOCATION_ERROR_INVALID_PARAMETER if LocationOptions parameter is invalid */
+    virtual uint32_t startTracking(TrackingOptions&) = 0;
+
+    /** @brief Stops a tracking session associated with id parameter.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a tracking session */
+    virtual void stopTracking(uint32_t id) = 0;
+
+    /** @brief Changes the LocationOptions of a tracking session associated with id.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if LocationOptions parameters are invalid
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a tracking session */
+    virtual void updateTrackingOptions(uint32_t id, TrackingOptions&) = 0;
+
+    /* ================================== BATCHING ================================== */
+
+    /** @brief starts a batching session, which returns a session id that will be
+       used by the other batching APIs and also in the responseCallback to match command
+       with response. locations are reported on the batchingCallback passed in createInstance
+       periodically according to LocationOptions. A batching session starts tracking on
+       the low power processor and delivers them in batches by the batchingCallback when
+       the batch is full or when getBatchedLocations is called. This allows for the processor
+       that calls this API to sleep when the low power processor can batch locations in the
+       backgroup and wake up the processor calling the API only when the batch is full, thus
+       saving power.
+       @return session id
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successful
+                LOCATION_ERROR_ALREADY_STARTED if a startBatching session is already in progress
+                LOCATION_ERROR_CALLBACK_MISSING if no batchingCallback
+                LOCATION_ERROR_INVALID_PARAMETER if a parameter is invalid
+                LOCATION_ERROR_NOT_SUPPORTED if batching is not supported */
+    virtual uint32_t startBatching(BatchingOptions&) = 0;
+
+    /** @brief Stops a batching session associated with id parameter.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with batching session */
+    virtual void stopBatching(uint32_t id) = 0;
+
+    /** @brief Changes the LocationOptions of a batching session associated with id.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if LocationOptions parameters are invalid
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a batching session */
+    virtual void updateBatchingOptions(uint32_t id, BatchingOptions&) = 0;
+
+    /** @brief Gets a number of locations that are currently stored/batched
+       on the low power processor, delivered by the batchingCallback passed in createInstance.
+       Location are then deleted from the batch stored on the low power processor.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful, will be followed by batchingCallback call
+                LOCATION_ERROR_CALLBACK_MISSING if no batchingCallback
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a batching session */
+    virtual void getBatchedLocations(uint32_t id, size_t count) = 0;
+
+    /* ================================== GEOFENCE ================================== */
+
+    /** @brief Adds any number of geofences and returns an array of geofence ids that
+       will be used by the other geofence APIs and also in the collectiveResponseCallback to
+       match command with response. The geofenceBreachCallback will deliver the status of each
+       geofence according to the GeofenceOption for each. The geofence id array returned will
+       be valid until the collectiveResponseCallback is called and has returned.
+       @return id array
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successful
+                LOCATION_ERROR_CALLBACK_MISSING if no geofenceBreachCallback
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+                LOCATION_ERROR_NOT_SUPPORTED if geofence is not supported */
+    virtual uint32_t* addGeofences(size_t count, GeofenceOption*, GeofenceInfo*) = 0;
+
+    /** @brief Removes any number of geofences. Caller should delete ids array after
+       removeGeofences returneds.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session */
+    virtual void removeGeofences(size_t count, uint32_t* ids) = 0;
+
+    /** @brief Modifies any number of geofences. Caller should delete ids array after
+       modifyGeofences returns.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid */
+    virtual void modifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options) = 0;
+
+    /** @brief Pauses any number of geofences, which is similar to removeGeofences,
+       only that they can be resumed at any time. Caller should delete ids array after
+       pauseGeofences returns.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session */
+    virtual void pauseGeofences(size_t count, uint32_t* ids) = 0;
+
+    /** @brief Resumes any number of geofences that are currently paused. Caller should
+       delete ids array after resumeGeofences returns.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session */
+    virtual void resumeGeofences(size_t count, uint32_t* ids) = 0;
+
+    /* ================================== GNSS ====================================== */
+
+     /** @brief gnssNiResponse is called in response to a gnssNiCallback.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters in GnssNiResponse are invalid
+                LOCATION_ERROR_ID_UNKNOWN if id does not match a gnssNiCallback */
+    virtual void gnssNiResponse(uint32_t id, GnssNiResponse response) = 0;
+};
+
+class ILocationControlAPI
+{
+public:
+    virtual ~ILocationControlAPI(){};
+
+    /** @brief Updates the gnss specific configuration, which returns a session id array
+       with an id for each of the bits set in GnssConfig.flags, order from low bits to high bits.
+       The response for each config that is set will be returned in collectiveResponseCallback.
+       The session id array returned will be valid until the collectiveResponseCallback is called
+       and has returned. This effect is global for all clients of ILocationAPI.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successful
+                LOCATION_ERROR_INVALID_PARAMETER if any other parameters are invalid
+                LOCATION_ERROR_GENERAL_FAILURE if failure for any other reason */
+    virtual uint32_t* gnssUpdateConfig(const GnssConfig& config) = 0;
+
+    /** @brief 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 ILocationAPI.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+                LOCATION_ERROR_NOT_SUPPORTED if build is not userdebug */
+    virtual uint32_t gnssDeleteAidingData(GnssAidingData& data) = 0;
+
+    /** @brief
+        Configure the constellation and SVs to be used by the GNSS engine on
+        modem.
+
+        @param
+        constellationEnablementConfig: configuration to enable/disable SV
+        constellation to be used by SPE engine. When size in
+        constellationEnablementConfig is set to 0, this indicates to reset SV
+        constellation configuration to modem NV default.
+
+        blacklistSvConfig: configuration to blacklist or unblacklist SVs
+        used by SPE engine
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configConstellations(
+            const GnssSvTypeConfig& constellationEnablementConfig,
+            const GnssSvIdConfig&   blacklistSvConfig) = 0;
+
+    /** @brief
+        Configure the secondary band of constellations to be used by
+        the GNSS engine on modem.
+
+        @param
+        secondaryBandConfig: configuration the secondary band usage
+        for SPE engine
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configConstellationSecondaryBand(
+            const GnssSvTypeConfig& secondaryBandConfig) = 0;
+
+    /** @brief
+        Enable or disable the constrained time uncertainty feature.
+
+        @param
+        enable: true to enable the constrained time uncertainty
+        feature and false to disable the constrainted time
+        uncertainty feature.
+
+        @param
+        tuncThreshold: this specifies the time uncertainty threshold
+        that gps engine need to maintain, in units of milli-seconds.
+        Default is 0.0 meaning that modem default value of time
+        uncertainty threshold will be used. This parameter is
+        ignored when requesting to disable this feature.
+
+        @param
+        energyBudget: this specifies the power budget that gps
+        engine is allowed to spend to maintain the time uncertainty.
+        Default is 0 meaning that GPS engine is not constained by
+        power budget and can spend as much power as needed. The
+        parameter need to be specified in units of 0.1 milli watt
+        second. This parameter is ignored requesting to disable this
+        feature.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters
+                are invalid
+    */
+    virtual uint32_t configConstrainedTimeUncertainty(
+            bool enable, float tuncThreshold = 0.0,
+            uint32_t energyBudget = 0) = 0;
+
+    /** @brief
+        Enable or disable position assisted clock estimator feature.
+
+        @param
+        enable: true to enable position assisted clock estimator and
+        false to disable the position assisted clock estimator
+        feature.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configPositionAssistedClockEstimator(bool enable) = 0;
+
+    /** @brief
+        Sets the lever arm parameters for the vehicle.
+
+        @param
+        configInfo: lever arm configuration info regarding below two
+        types of lever arm info:
+        a: GNSS Antenna w.r.t the origin at the IMU e.g.: inertial
+        measurement unit.
+        b: lever arm parameters regarding the OPF (output frame)
+        w.r.t the origin (at the GPS Antenna). Vehicle manufacturers
+        prefer the position output to be tied to a specific point in
+        the vehicle rather than where the antenna is placed
+        (midpoint of the rear axle is typical).
+
+        Caller can choose types of lever arm info to configure via the
+        leverMarkTypeMask.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configLeverArm(const LeverArmConfigInfo& configInfo) = 0;
+
+    /** @brief
+        Configure the robust location setting.
+
+        @param
+        enable: true to enable robust location and false to disable
+        robust location.
+
+        @param
+        enableForE911: true to enable robust location when device is on
+        E911 session and false to disable on E911 session.
+        This parameter is only valid if robust location is enabled.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configRobustLocation(bool enable, bool enableForE911) = 0;
+
+    /** @brief
+        Config the minimum GPS week used by modem GNSS engine.
+
+        @param
+        minGpsWeek: minimum GPS week to be used by modem GNSS engine.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configMinGpsWeek(uint16_t minGpsWeek) = 0;
+
+    /** @brief
+        Configure the vehicle body-to-Sensor mount parameters and
+        other parameters for dead reckoning position engine.
+
+        @param
+        dreConfig: vehicle body-to-Sensor mount angles and other
+        parameters.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configDeadReckoningEngineParams(const DeadReckoningEngineConfig& dreConfig)=0;
+
+    /** @brief
+        This API is used to instruct the specified engine to be in
+        the pause/resume state. <br/>
+
+        When the engine is placed in paused state, the engine will
+        stop. If there is an on-going session, engine will no longer
+        produce fixes. In the paused state, calling API to delete
+        aiding data from the paused engine may not have effect.
+        Request to delete Aiding data shall be issued after
+        engine resume. <br/>
+
+        Currently, only DRE engine will support pause/resume
+        request. responseCb() will return not supported when request
+        is made to pause/resume none-DRE engine. <br/>
+
+        Request to pause/resume DRE engine can be made with or
+        without an on-going session. With QDR engine, on resume,
+        GNSS position & heading re-acquisition is needed for DR
+        engine to engage. If DR engine is already in the requested
+        state, the request will be no-op.  <br/>
+
+        @param
+        engType: the engine that is instructed to change its run
+        state. <br/>
+
+        engState: the new engine run state that the engine is
+        instructed to be in. <br/>
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configEngineRunState(PositioningEngineMask engType,
+                                          LocEngineRunState engState) = 0;
+};
+
+#endif /* ILOCATIONAPI_H */
diff --git a/gps/location/LocationAPI.cpp b/gps/location/LocationAPI.cpp
new file mode 100644
index 0000000..3a50c46
--- /dev/null
+++ b/gps/location/LocationAPI.cpp
@@ -0,0 +1,976 @@
+/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_LocationAPI"
+
+#include <location_interface.h>
+#include <dlfcn.h>
+#include <loc_pla.h>
+#include <log_util.h>
+#include <pthread.h>
+#include <map>
+#include <loc_misc_utils.h>
+
+typedef const GnssInterface* (getGnssInterface)();
+typedef const GeofenceInterface* (getGeofenceInterface)();
+typedef const BatchingInterface* (getBatchingInterface)();
+typedef void (createOSFramework)();
+typedef void (destroyOSFramework)();
+
+// GTP services
+typedef uint32_t (setOptInStatusGetter)(bool userConsent, responseCallback* callback);
+typedef void (enableProviderGetter)();
+typedef void (disableProviderGetter)();
+typedef void (getSingleNetworkLocationGetter)(trackingCallback* callback);
+typedef void (stopNetworkLocationGetter)(trackingCallback* callback);
+
+typedef struct {
+    // bit mask of the adpaters that we need to wait for the removeClientCompleteCallback
+    // before we invoke the registered locationApiDestroyCompleteCallback
+    LocationAdapterTypeMask waitAdapterMask;
+    locationApiDestroyCompleteCallback destroyCompleteCb;
+} LocationAPIDestroyCbData;
+
+// This is the map for the client that has requested destroy with
+// destroy callback provided.
+typedef std::map<LocationAPI*, LocationAPIDestroyCbData>
+    LocationClientDestroyCbMap;
+
+typedef std::map<LocationAPI*, LocationCallbacks> LocationClientMap;
+typedef struct {
+    LocationClientMap clientData;
+    LocationClientDestroyCbMap destroyClientData;
+    LocationControlAPI* controlAPI;
+    LocationControlCallbacks controlCallbacks;
+    GnssInterface* gnssInterface;
+    GeofenceInterface* geofenceInterface;
+    BatchingInterface* batchingInterface;
+} LocationAPIData;
+
+static LocationAPIData gData = {};
+static pthread_mutex_t gDataMutex = PTHREAD_MUTEX_INITIALIZER;
+static bool gGnssLoadFailed = false;
+static bool gBatchingLoadFailed = false;
+static bool gGeofenceLoadFailed = false;
+static uint32_t gOSFrameworkRefCount = 0;
+
+template <typename T1, typename T2>
+static const T1* loadLocationInterface(const char* library, const char* name) {
+    void* libhandle = nullptr;
+    T2* getter = (T2*)dlGetSymFromLib(libhandle, library, name);
+    if (nullptr == getter) {
+        return (const T1*) getter;
+    }else {
+        return (*getter)();
+    }
+}
+
+static void createOSFrameworkInstance() {
+    void* libHandle = nullptr;
+    createOSFramework* getter = (createOSFramework*)dlGetSymFromLib(libHandle,
+            "liblocationservice_glue.so", "createOSFramework");
+    if (getter != nullptr) {
+        (*getter)();
+    } else {
+        LOC_LOGe("dlGetSymFromLib failed for liblocationservice_glue.so");
+    }
+}
+
+static void destroyOSFrameworkInstance() {
+    void* libHandle = nullptr;
+    destroyOSFramework* getter = (destroyOSFramework*)dlGetSymFromLib(libHandle,
+            "liblocationservice_glue.so", "destroyOSFramework");
+    if (getter != nullptr) {
+        (*getter)();
+    } else {
+        LOC_LOGe("dlGetSymFromLib failed for liblocationservice_glue.so");
+    }
+}
+
+static bool needsGnssTrackingInfo(LocationCallbacks& locationCallbacks)
+{
+    return (locationCallbacks.gnssLocationInfoCb != nullptr ||
+            locationCallbacks.engineLocationsInfoCb != nullptr ||
+            locationCallbacks.gnssSvCb != nullptr ||
+            locationCallbacks.gnssNmeaCb != nullptr ||
+            locationCallbacks.gnssDataCb != nullptr ||
+            locationCallbacks.gnssMeasurementsCb != nullptr);
+}
+
+static bool isGnssClient(LocationCallbacks& locationCallbacks)
+{
+    return (locationCallbacks.gnssNiCb != nullptr ||
+            locationCallbacks.trackingCb != nullptr ||
+            locationCallbacks.gnssLocationInfoCb != nullptr ||
+            locationCallbacks.engineLocationsInfoCb != nullptr ||
+            locationCallbacks.gnssSvCb != nullptr ||
+            locationCallbacks.gnssNmeaCb != nullptr ||
+            locationCallbacks.gnssDataCb != nullptr ||
+            locationCallbacks.gnssMeasurementsCb != nullptr ||
+            locationCallbacks.locationSystemInfoCb != nullptr);
+}
+
+static bool isBatchingClient(LocationCallbacks& locationCallbacks)
+{
+    return (locationCallbacks.batchingCb != nullptr);
+}
+
+static bool isGeofenceClient(LocationCallbacks& locationCallbacks)
+{
+    return (locationCallbacks.geofenceBreachCb != nullptr ||
+            locationCallbacks.geofenceStatusCb != nullptr);
+}
+
+
+void LocationAPI::onRemoveClientCompleteCb (LocationAdapterTypeMask adapterType)
+{
+    bool invokeCallback = false;
+    locationApiDestroyCompleteCallback destroyCompleteCb;
+    LOC_LOGd("adatper type %x", adapterType);
+    pthread_mutex_lock(&gDataMutex);
+    auto it = gData.destroyClientData.find(this);
+    if (it != gData.destroyClientData.end()) {
+        it->second.waitAdapterMask &= ~adapterType;
+        if (it->second.waitAdapterMask == 0) {
+            invokeCallback = true;
+            destroyCompleteCb = it->second.destroyCompleteCb;
+            gData.destroyClientData.erase(it);
+        }
+    }
+    pthread_mutex_unlock(&gDataMutex);
+
+    if (invokeCallback) {
+        LOC_LOGd("invoke client destroy cb");
+        if (!destroyCompleteCb) {
+            (destroyCompleteCb) ();
+        }
+
+        delete this;
+    }
+}
+
+void onGnssRemoveClientCompleteCb (LocationAPI* client)
+{
+    client->onRemoveClientCompleteCb (LOCATION_ADAPTER_GNSS_TYPE_BIT);
+}
+
+void onBatchingRemoveClientCompleteCb (LocationAPI* client)
+{
+    client->onRemoveClientCompleteCb (LOCATION_ADAPTER_BATCHING_TYPE_BIT);
+}
+
+void onGeofenceRemoveClientCompleteCb (LocationAPI* client)
+{
+    client->onRemoveClientCompleteCb (LOCATION_ADAPTER_GEOFENCE_TYPE_BIT);
+}
+
+LocationAPI*
+LocationAPI::createInstance (LocationCallbacks& locationCallbacks)
+{
+    if (nullptr == locationCallbacks.capabilitiesCb ||
+        nullptr == locationCallbacks.responseCb ||
+        nullptr == locationCallbacks.collectiveResponseCb) {
+        LOC_LOGe("missing mandatory callback, return null");
+        return NULL;
+    }
+
+    LocationAPI* newLocationAPI = new LocationAPI();
+    bool requestedCapabilities = false;
+
+    pthread_mutex_lock(&gDataMutex);
+
+    gOSFrameworkRefCount++;
+    if (1 == gOSFrameworkRefCount) {
+        createOSFrameworkInstance();
+    }
+
+    if (isGnssClient(locationCallbacks)) {
+        if (NULL == gData.gnssInterface && !gGnssLoadFailed) {
+            gData.gnssInterface =
+                (GnssInterface*)loadLocationInterface<GnssInterface,
+                    getGnssInterface>("libgnss.so", "getGnssInterface");
+            if (NULL == gData.gnssInterface) {
+                gGnssLoadFailed = true;
+                LOC_LOGW("%s:%d]: No gnss interface available", __func__, __LINE__);
+            } else {
+                gData.gnssInterface->initialize();
+            }
+        }
+        if (NULL != gData.gnssInterface) {
+            gData.gnssInterface->addClient(newLocationAPI, locationCallbacks);
+            if (!requestedCapabilities) {
+                gData.gnssInterface->requestCapabilities(newLocationAPI);
+                requestedCapabilities = true;
+            }
+        }
+    }
+
+    if (isBatchingClient(locationCallbacks)) {
+        if (NULL == gData.batchingInterface && !gBatchingLoadFailed) {
+            gData.batchingInterface =
+                (BatchingInterface*)loadLocationInterface<BatchingInterface,
+                 getBatchingInterface>("libbatching.so", "getBatchingInterface");
+            if (NULL == gData.batchingInterface) {
+                gBatchingLoadFailed = true;
+                LOC_LOGW("%s:%d]: No batching interface available", __func__, __LINE__);
+            } else {
+                gData.batchingInterface->initialize();
+            }
+        }
+        if (NULL != gData.batchingInterface) {
+            gData.batchingInterface->addClient(newLocationAPI, locationCallbacks);
+            if (!requestedCapabilities) {
+                gData.batchingInterface->requestCapabilities(newLocationAPI);
+                requestedCapabilities = true;
+            }
+        }
+    }
+
+    if (isGeofenceClient(locationCallbacks)) {
+        if (NULL == gData.geofenceInterface && !gGeofenceLoadFailed) {
+            gData.geofenceInterface =
+               (GeofenceInterface*)loadLocationInterface<GeofenceInterface,
+               getGeofenceInterface>("libgeofencing.so", "getGeofenceInterface");
+            if (NULL == gData.geofenceInterface) {
+                gGeofenceLoadFailed = true;
+                LOC_LOGW("%s:%d]: No geofence interface available", __func__, __LINE__);
+            } else {
+                gData.geofenceInterface->initialize();
+            }
+        }
+        if (NULL != gData.geofenceInterface) {
+            gData.geofenceInterface->addClient(newLocationAPI, locationCallbacks);
+            if (!requestedCapabilities) {
+                gData.geofenceInterface->requestCapabilities(newLocationAPI);
+                requestedCapabilities = true;
+            }
+        }
+    }
+
+    gData.clientData[newLocationAPI] = locationCallbacks;
+
+    pthread_mutex_unlock(&gDataMutex);
+
+    return newLocationAPI;
+}
+
+void
+LocationAPI::destroy(locationApiDestroyCompleteCallback destroyCompleteCb)
+{
+    bool invokeDestroyCb = false;
+
+    pthread_mutex_lock(&gDataMutex);
+    auto it = gData.clientData.find(this);
+    if (it != gData.clientData.end()) {
+        bool removeFromGnssInf = (NULL != gData.gnssInterface);
+        bool removeFromBatchingInf = (NULL != gData.batchingInterface);
+        bool removeFromGeofenceInf = (NULL != gData.geofenceInterface);
+        bool needToWait = (removeFromGnssInf || removeFromBatchingInf || removeFromGeofenceInf);
+        LOC_LOGe("removeFromGnssInf: %d, removeFromBatchingInf: %d, removeFromGeofenceInf: %d,"
+                 "needToWait: %d", removeFromGnssInf, removeFromBatchingInf, removeFromGeofenceInf,
+                 needToWait);
+
+        if ((NULL != destroyCompleteCb) && (true == needToWait)) {
+            LocationAPIDestroyCbData destroyCbData = {};
+            destroyCbData.destroyCompleteCb = destroyCompleteCb;
+            // record down from which adapter we need to wait for the destroy complete callback
+            // only when we have received all the needed callbacks from all the associated stacks,
+            // we shall notify the client.
+            destroyCbData.waitAdapterMask =
+                    (removeFromGnssInf ? LOCATION_ADAPTER_GNSS_TYPE_BIT : 0);
+            destroyCbData.waitAdapterMask |=
+                    (removeFromBatchingInf ? LOCATION_ADAPTER_BATCHING_TYPE_BIT : 0);
+            destroyCbData.waitAdapterMask |=
+                    (removeFromGeofenceInf ? LOCATION_ADAPTER_GEOFENCE_TYPE_BIT : 0);
+            gData.destroyClientData[this] = destroyCbData;
+            LOC_LOGi("destroy data stored in the map: 0x%x", destroyCbData.waitAdapterMask);
+        }
+
+        if (removeFromGnssInf) {
+            gData.gnssInterface->removeClient(it->first,
+                                              onGnssRemoveClientCompleteCb);
+        }
+        if (removeFromBatchingInf) {
+            gData.batchingInterface->removeClient(it->first,
+                                             onBatchingRemoveClientCompleteCb);
+        }
+        if (removeFromGeofenceInf) {
+            gData.geofenceInterface->removeClient(it->first,
+                                                  onGeofenceRemoveClientCompleteCb);
+        }
+
+        gData.clientData.erase(it);
+
+        if (!needToWait) {
+            invokeDestroyCb = true;
+        }
+    } else {
+        LOC_LOGE("%s:%d]: Location API client %p not found in client data",
+                 __func__, __LINE__, this);
+    }
+
+    if (1 == gOSFrameworkRefCount) {
+        destroyOSFrameworkInstance();
+    }
+    gOSFrameworkRefCount--;
+
+    pthread_mutex_unlock(&gDataMutex);
+    if (invokeDestroyCb) {
+        if (!destroyCompleteCb) {
+            (destroyCompleteCb) ();
+        }
+        delete this;
+    }
+}
+
+LocationAPI::LocationAPI()
+{
+    LOC_LOGD("LOCATION API CONSTRUCTOR");
+}
+
+// private destructor
+LocationAPI::~LocationAPI()
+{
+    LOC_LOGD("LOCATION API DESTRUCTOR");
+}
+
+void
+LocationAPI::updateCallbacks(LocationCallbacks& locationCallbacks)
+{
+    if (nullptr == locationCallbacks.capabilitiesCb ||
+        nullptr == locationCallbacks.responseCb ||
+        nullptr == locationCallbacks.collectiveResponseCb) {
+        return;
+    }
+
+    pthread_mutex_lock(&gDataMutex);
+
+    if (isGnssClient(locationCallbacks)) {
+        if (NULL == gData.gnssInterface && !gGnssLoadFailed) {
+            gData.gnssInterface =
+                (GnssInterface*)loadLocationInterface<GnssInterface,
+                    getGnssInterface>("libgnss.so", "getGnssInterface");
+            if (NULL == gData.gnssInterface) {
+                gGnssLoadFailed = true;
+                LOC_LOGW("%s:%d]: No gnss interface available", __func__, __LINE__);
+            } else {
+                gData.gnssInterface->initialize();
+            }
+        }
+        if (NULL != gData.gnssInterface) {
+            // either adds new Client or updates existing Client
+            gData.gnssInterface->addClient(this, locationCallbacks);
+        }
+    }
+
+    if (isBatchingClient(locationCallbacks)) {
+        if (NULL == gData.batchingInterface && !gBatchingLoadFailed) {
+            gData.batchingInterface =
+                (BatchingInterface*)loadLocationInterface<BatchingInterface,
+                 getBatchingInterface>("libbatching.so", "getBatchingInterface");
+            if (NULL == gData.batchingInterface) {
+                gBatchingLoadFailed = true;
+                LOC_LOGW("%s:%d]: No batching interface available", __func__, __LINE__);
+            } else {
+                gData.batchingInterface->initialize();
+            }
+        }
+        if (NULL != gData.batchingInterface) {
+            // either adds new Client or updates existing Client
+            gData.batchingInterface->addClient(this, locationCallbacks);
+        }
+    }
+
+    if (isGeofenceClient(locationCallbacks)) {
+        if (NULL == gData.geofenceInterface && !gGeofenceLoadFailed) {
+            gData.geofenceInterface =
+                (GeofenceInterface*)loadLocationInterface<GeofenceInterface,
+                 getGeofenceInterface>("libgeofencing.so", "getGeofenceInterface");
+            if (NULL == gData.geofenceInterface) {
+                gGeofenceLoadFailed = true;
+                LOC_LOGW("%s:%d]: No geofence interface available", __func__, __LINE__);
+            } else {
+                gData.geofenceInterface->initialize();
+            }
+        }
+        if (NULL != gData.geofenceInterface) {
+            // either adds new Client or updates existing Client
+            gData.geofenceInterface->addClient(this, locationCallbacks);
+        }
+    }
+
+    gData.clientData[this] = locationCallbacks;
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+uint32_t
+LocationAPI::startTracking(TrackingOptions& trackingOptions)
+{
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    auto it = gData.clientData.find(this);
+    if (it != gData.clientData.end()) {
+        if (NULL != gData.gnssInterface) {
+            id = gData.gnssInterface->startTracking(this, trackingOptions);
+        } else {
+            LOC_LOGE("%s:%d]: No gnss interface available for Location API client %p ",
+                     __func__, __LINE__, this);
+        }
+    } else {
+        LOC_LOGE("%s:%d]: Location API client %p not found in client data",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+void
+LocationAPI::stopTracking(uint32_t id)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    auto it = gData.clientData.find(this);
+    if (it != gData.clientData.end()) {
+        if (gData.gnssInterface != NULL) {
+            gData.gnssInterface->stopTracking(this, id);
+        } else {
+            LOC_LOGE("%s:%d]: No gnss interface available for Location API client %p ",
+                     __func__, __LINE__, this);
+        }
+    } else {
+        LOC_LOGE("%s:%d]: Location API client %p not found in client data",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+void
+LocationAPI::updateTrackingOptions(
+        uint32_t id, TrackingOptions& trackingOptions)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    auto it = gData.clientData.find(this);
+    if (it != gData.clientData.end()) {
+        if (gData.gnssInterface != NULL) {
+            gData.gnssInterface->updateTrackingOptions(this, id, trackingOptions);
+        } else {
+            LOC_LOGE("%s:%d]: No gnss interface available for Location API client %p ",
+                     __func__, __LINE__, this);
+        }
+    } else {
+        LOC_LOGE("%s:%d]: Location API client %p not found in client data",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+uint32_t
+LocationAPI::startBatching(BatchingOptions &batchingOptions)
+{
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (NULL != gData.batchingInterface) {
+        id = gData.batchingInterface->startBatching(this, batchingOptions);
+    } else {
+        LOC_LOGE("%s:%d]: No batching interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+void
+LocationAPI::stopBatching(uint32_t id)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    if (NULL != gData.batchingInterface) {
+        gData.batchingInterface->stopBatching(this, id);
+    } else {
+        LOC_LOGE("%s:%d]: No batching interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+void
+LocationAPI::updateBatchingOptions(uint32_t id, BatchingOptions& batchOptions)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    if (NULL != gData.batchingInterface) {
+        gData.batchingInterface->updateBatchingOptions(this, id, batchOptions);
+    } else {
+        LOC_LOGE("%s:%d]: No batching interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+void
+LocationAPI::getBatchedLocations(uint32_t id, size_t count)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.batchingInterface != NULL) {
+        gData.batchingInterface->getBatchedLocations(this, id, count);
+    } else {
+        LOC_LOGE("%s:%d]: No batching interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+uint32_t*
+LocationAPI::addGeofences(size_t count, GeofenceOption* options, GeofenceInfo* info)
+{
+    uint32_t* ids = NULL;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.geofenceInterface != NULL) {
+        ids = gData.geofenceInterface->addGeofences(this, count, options, info);
+    } else {
+        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return ids;
+}
+
+void
+LocationAPI::removeGeofences(size_t count, uint32_t* ids)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.geofenceInterface != NULL) {
+        gData.geofenceInterface->removeGeofences(this, count, ids);
+    } else {
+        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+void
+LocationAPI::modifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.geofenceInterface != NULL) {
+        gData.geofenceInterface->modifyGeofences(this, count, ids, options);
+    } else {
+        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+void
+LocationAPI::pauseGeofences(size_t count, uint32_t* ids)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.geofenceInterface != NULL) {
+        gData.geofenceInterface->pauseGeofences(this, count, ids);
+    } else {
+        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+void
+LocationAPI::resumeGeofences(size_t count, uint32_t* ids)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.geofenceInterface != NULL) {
+        gData.geofenceInterface->resumeGeofences(this, count, ids);
+    } else {
+        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+void
+LocationAPI::gnssNiResponse(uint32_t id, GnssNiResponse response)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        gData.gnssInterface->gnssNiResponse(this, id, response);
+    } else {
+        LOC_LOGE("%s:%d]: No gnss interface available for Location API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+void LocationAPI::enableNetworkProvider() {
+    void* libHandle = nullptr;
+    enableProviderGetter* setter = (enableProviderGetter*)dlGetSymFromLib(libHandle,
+            "liblocationservice_glue.so", "enableNetworkProvider");
+    if (setter != nullptr) {
+        (*setter)();
+    } else {
+        LOC_LOGe("dlGetSymFromLib failed for liblocationservice_glue.so");
+    }
+}
+
+void LocationAPI::disableNetworkProvider() {
+    void* libHandle = nullptr;
+    disableProviderGetter* setter = (disableProviderGetter*)dlGetSymFromLib(libHandle,
+            "liblocationservice_glue.so", "disableNetworkProvider");
+    if (setter != nullptr) {
+        (*setter)();
+    } else {
+        LOC_LOGe("dlGetSymFromLib failed for liblocationservice_glue.so");
+    }
+}
+
+void LocationAPI::startNetworkLocation(trackingCallback* callback) {
+    void* libHandle = nullptr;
+    getSingleNetworkLocationGetter* setter =
+            (getSingleNetworkLocationGetter*)dlGetSymFromLib(libHandle,
+            "liblocationservice_glue.so", "startNetworkLocation");
+    if (setter != nullptr) {
+        (*setter)(callback);
+    } else {
+        LOC_LOGe("dlGetSymFromLib failed for liblocationservice_glue.so");
+    }
+}
+
+void LocationAPI::stopNetworkLocation(trackingCallback* callback) {
+    void* libHandle = nullptr;
+    stopNetworkLocationGetter* setter = (stopNetworkLocationGetter*)dlGetSymFromLib(libHandle,
+            "liblocationservice_glue.so", "stopNetworkLocation");
+    if (setter != nullptr) {
+        LOC_LOGe("called");
+        (*setter)(callback);
+    } else {
+        LOC_LOGe("dlGetSymFromLib failed for liblocationservice_glue.so");
+    }
+}
+
+LocationControlAPI*
+LocationControlAPI::createInstance(LocationControlCallbacks& locationControlCallbacks)
+{
+    LocationControlAPI* controlAPI = NULL;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (nullptr != locationControlCallbacks.responseCb && NULL == gData.controlAPI) {
+        if (NULL == gData.gnssInterface && !gGnssLoadFailed) {
+            gData.gnssInterface =
+                (GnssInterface*)loadLocationInterface<GnssInterface,
+                    getGnssInterface>("libgnss.so", "getGnssInterface");
+            if (NULL == gData.gnssInterface) {
+                gGnssLoadFailed = true;
+                LOC_LOGW("%s:%d]: No gnss interface available", __func__, __LINE__);
+            } else {
+                gData.gnssInterface->initialize();
+            }
+        }
+        if (NULL != gData.gnssInterface) {
+            gData.controlAPI = new LocationControlAPI();
+            gData.controlCallbacks = locationControlCallbacks;
+            gData.gnssInterface->setControlCallbacks(locationControlCallbacks);
+            controlAPI = gData.controlAPI;
+        }
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return controlAPI;
+}
+
+void
+LocationControlAPI::destroy()
+{
+    delete this;
+}
+
+LocationControlAPI::LocationControlAPI()
+{
+    LOC_LOGD("LOCATION CONTROL API CONSTRUCTOR");
+}
+
+LocationControlAPI::~LocationControlAPI()
+{
+    LOC_LOGD("LOCATION CONTROL API DESTRUCTOR");
+    pthread_mutex_lock(&gDataMutex);
+
+    gData.controlAPI = NULL;
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+uint32_t
+LocationControlAPI::enable(LocationTechnologyType techType)
+{
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->enable(techType);
+    } else {
+        LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+void
+LocationControlAPI::disable(uint32_t id)
+{
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        gData.gnssInterface->disable(id);
+    } else {
+        LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+}
+
+uint32_t*
+LocationControlAPI::gnssUpdateConfig(const GnssConfig& config)
+{
+    uint32_t* ids = NULL;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        ids = gData.gnssInterface->gnssUpdateConfig(config);
+    } else {
+        LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    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)
+{
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->gnssDeleteAidingData(data);
+    } else {
+        LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ",
+                 __func__, __LINE__, this);
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::configConstellations(
+        const GnssSvTypeConfig& constellationEnablementConfig,
+        const GnssSvIdConfig&   blacklistSvConfig) {
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->gnssUpdateSvConfig(
+                constellationEnablementConfig, blacklistSvConfig);
+    } else {
+        LOC_LOGe("No gnss interface available for Location Control API");
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::configConstellationSecondaryBand(
+        const GnssSvTypeConfig& secondaryBandConfig) {
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->gnssUpdateSecondaryBandConfig(secondaryBandConfig);
+    } else {
+        LOC_LOGe("No gnss interface available for Location Control API");
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::configConstrainedTimeUncertainty(
+            bool enable, float tuncThreshold, uint32_t energyBudget) {
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->setConstrainedTunc(enable,
+                                                     tuncThreshold,
+                                                     energyBudget);
+    } else {
+        LOC_LOGe("No gnss interface available for Location Control API");
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::configPositionAssistedClockEstimator(bool enable) {
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->setPositionAssistedClockEstimator(enable);
+    } else {
+        LOC_LOGe("No gnss interface available for Location Control API");
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::configLeverArm(const LeverArmConfigInfo& configInfo) {
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->configLeverArm(configInfo);
+    } else {
+        LOC_LOGe("No gnss interface available for Location Control API");
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::configRobustLocation(bool enable, bool enableForE911) {
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->configRobustLocation(enable, enableForE911);
+    } else {
+        LOC_LOGe("No gnss interface available for Location Control API");
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::configMinGpsWeek(uint16_t minGpsWeek) {
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->configMinGpsWeek(minGpsWeek);
+    } else {
+        LOC_LOGe("No gnss interface available for Location Control API");
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::configDeadReckoningEngineParams(
+        const DeadReckoningEngineConfig& dreConfig) {
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->configDeadReckoningEngineParams(dreConfig);
+    } else {
+        LOC_LOGe("No gnss interface available for Location Control API");
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::configEngineRunState(
+        PositioningEngineMask engType, LocEngineRunState engState) {
+    uint32_t id = 0;
+    pthread_mutex_lock(&gDataMutex);
+
+    if (gData.gnssInterface != NULL) {
+        id = gData.gnssInterface->configEngineRunState(engType, engState);
+    } else {
+        LOC_LOGe("No gnss interface available for Location Control API");
+    }
+
+    pthread_mutex_unlock(&gDataMutex);
+    return id;
+}
+
+uint32_t LocationControlAPI::setOptInStatus(bool userConsent) {
+    void* libHandle = nullptr;
+    uint32_t sessionId = 0;
+    setOptInStatusGetter* setter = (setOptInStatusGetter*)dlGetSymFromLib(libHandle,
+            "liblocationservice_glue.so", "setOptInStatus");
+    if (setter != nullptr) {
+        sessionId = (*setter)(userConsent, &gData.controlCallbacks.responseCb);
+    } else {
+        LOC_LOGe("dlGetSymFromLib failed for liblocationservice_glue.so");
+    }
+    return sessionId;
+}
diff --git a/gps/location/LocationAPI.h b/gps/location/LocationAPI.h
new file mode 100644
index 0000000..7c70506
--- /dev/null
+++ b/gps/location/LocationAPI.h
@@ -0,0 +1,512 @@
+/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LOCATIONAPI_H
+#define LOCATIONAPI_H
+
+#include "ILocationAPI.h"
+
+class LocationAPI : public ILocationAPI
+{
+private:
+    LocationAPI();
+    ~LocationAPI();
+
+public:
+    /* creates an instance to LocationAPI object.
+       Will return NULL if mandatory parameters are invalid or if the maximum number
+       of instances have been reached */
+    static LocationAPI* createInstance(LocationCallbacks&);
+
+    /* destroy/cleans up the instance, which should be called when LocationControlAPI object is
+       no longer needed. LocationControlAPI* returned from createInstance will no longer valid
+       after destroy is called.
+       If the caller allocates the memory for LocationControlCallbacks used in
+       LocationControlAPI::createInstance, then the caller must ensure that the memory still remains
+       valid until destroyCompleteCb is invoked.
+    */
+    void destroy(locationApiDestroyCompleteCallback destroyCompleteCb=nullptr);
+
+    void onRemoveClientCompleteCb (LocationAdapterTypeMask adapterType);
+
+    /* updates/changes the callbacks that will be called.
+        mandatory callbacks must be present for callbacks to be successfully updated
+        no return value */
+    virtual void updateCallbacks(LocationCallbacks&) override;
+
+    /* ================================== TRACKING ================================== */
+
+    /* startTracking starts a tracking session, which returns a session id that will be
+       used by the other tracking APIs and also in the responseCallback to match command
+       with response. locations are reported on the trackingCallback passed in createInstance
+       periodically according to LocationOptions.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successfully started
+                LOCATION_ERROR_ALREADY_STARTED if a startTracking session is already in progress
+                LOCATION_ERROR_CALLBACK_MISSING if no trackingCallback was passed in createInstance
+                LOCATION_ERROR_INVALID_PARAMETER if TrackingOptions parameter is invalid */
+    virtual uint32_t startTracking(TrackingOptions&) override;
+
+    /* stopTracking stops a tracking session associated with id parameter.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a tracking session */
+    virtual void stopTracking(uint32_t id) override;
+
+    /* updateTrackingOptions changes the TrackingOptions of a tracking session associated with id
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if TrackingOptions parameters are invalid
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a tracking session */
+    virtual void updateTrackingOptions(uint32_t id, TrackingOptions&) override;
+
+    /* ================================== BATCHING ================================== */
+
+    /* startBatching starts a batching session, which returns a session id that will be
+       used by the other batching APIs and also in the responseCallback to match command
+       with response. locations are reported on the batchingCallback passed in createInstance
+       periodically according to LocationOptions. A batching session starts tracking on
+       the low power processor and delivers them in batches by the batchingCallback when
+       the batch is full or when getBatchedLocations is called. This allows for the processor
+       that calls this API to sleep when the low power processor can batch locations in the
+       backgroup and wake up the processor calling the API only when the batch is full, thus
+       saving power
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successful
+                LOCATION_ERROR_ALREADY_STARTED if a startBatching session is already in progress
+                LOCATION_ERROR_CALLBACK_MISSING if no batchingCallback was passed in createInstance
+                LOCATION_ERROR_INVALID_PARAMETER if a parameter is invalid
+                LOCATION_ERROR_NOT_SUPPORTED if batching is not supported */
+    virtual uint32_t startBatching(BatchingOptions&) override;
+
+    /* stopBatching stops a batching session associated with id parameter.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with batching session */
+    virtual void stopBatching(uint32_t id) override;
+
+    /* updateBatchingOptions changes the BatchingOptions of a batching session associated with id
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if BatchingOptions parameters are invalid
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a batching session */
+    virtual void updateBatchingOptions(uint32_t id, BatchingOptions&) override;
+
+    /* getBatchedLocations gets a number of locations that are currently stored/batched
+       on the low power processor, delivered by the batchingCallback passed in createInstance.
+       Location are then deleted from the batch stored on the low power processor.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful, will be followed by batchingCallback call
+                LOCATION_ERROR_CALLBACK_MISSING if no batchingCallback was passed in createInstance
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a batching session */
+    virtual void getBatchedLocations(uint32_t id, size_t count) override;
+
+    /* ================================== GEOFENCE ================================== */
+
+    /* addGeofences adds any number of geofences and returns an array of geofence ids that
+       will be used by the other geofence APIs and also in the collectiveResponseCallback to
+       match command with response. The geofenceBreachCallback will deliver the status of each
+       geofence according to the GeofenceOption for each. The geofence id array returned will
+       be valid until the collectiveResponseCallback is called and has returned.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successful
+                LOCATION_ERROR_CALLBACK_MISSING if no geofenceBreachCallback
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+                LOCATION_ERROR_NOT_SUPPORTED if geofence is not supported */
+    virtual uint32_t* addGeofences(size_t count, GeofenceOption*, GeofenceInfo*) override;
+
+    /* removeGeofences removes any number of geofences. Caller should delete ids array after
+       removeGeofences returneds.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session */
+    virtual void removeGeofences(size_t count, uint32_t* ids) override;
+
+    /* modifyGeofences modifies any number of geofences. Caller should delete ids array after
+       modifyGeofences returns.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid */
+    virtual void modifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options) override;
+
+    /* pauseGeofences pauses any number of geofences, which is similar to removeGeofences,
+       only that they can be resumed at any time. Caller should delete ids array after
+       pauseGeofences returns.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session */
+    virtual void pauseGeofences(size_t count, uint32_t* ids) override;
+
+    /* resumeGeofences resumes any number of geofences that are currently paused. Caller should
+       delete ids array after resumeGeofences returns.
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id is not associated with a geofence session */
+    virtual void resumeGeofences(size_t count, uint32_t* ids) override;
+
+    /* ================================== GNSS ====================================== */
+
+     /* gnssNiResponse is called in response to a gnssNiCallback.
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters in GnssNiResponse are invalid
+                LOCATION_ERROR_ID_UNKNOWN if id does not match a gnssNiCallback */
+    virtual void gnssNiResponse(uint32_t id, GnssNiResponse response) override;
+
+    /* ================================== NETWORK PROVIDER =========================== */
+
+    /* enableNetworkProvider enables Network Provider */
+    virtual void enableNetworkProvider();
+
+    /* disableNetworkProvider disables Network Provider */
+    virtual void disableNetworkProvider();
+
+    /* startNetworkLocation start a single shot network location request */
+    virtual void startNetworkLocation(trackingCallback* callback);
+
+    /* stopNetworkLocation stop any ongoing network location request */
+    virtual void stopNetworkLocation(trackingCallback* callback);
+};
+
+typedef struct {
+    size_t size; // set to sizeof(LocationControlCallbacks)
+    responseCallback responseCb;                     // mandatory
+    collectiveResponseCallback collectiveResponseCb; // mandatory
+    gnssConfigCallback gnssConfigCb;                 // optional
+} LocationControlCallbacks;
+
+class LocationControlAPI : public ILocationControlAPI
+{
+private:
+    LocationControlAPI();
+    ~LocationControlAPI();
+
+public:
+    /* creates an instance to LocationControlAPI object.
+       Will return NULL if mandatory parameters are invalid or if the maximum number
+       of instances have been reached. Only once instance allowed */
+    static LocationControlAPI* createInstance(LocationControlCallbacks&);
+
+    /* destroy/cleans up the instance, which should be called when LocationControlAPI object is
+       no longer needed. LocationControlAPI* returned from createInstance will no longer valid
+       after destroy is called */
+    void destroy();
+
+    /* enable will enable specific location technology to be used for calculation locations and
+       will effectively start a control session if call is successful, which returns a session id
+       that will be returned in responseCallback to match command with response. The session id is
+       also needed to call the disable command.
+       This effect is global for all clients of LocationAPI
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ALREADY_STARTED if an enable was already called for this techType
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+                LOCATION_ERROR_GENERAL_FAILURE if failure for any other reason */
+    uint32_t enable(LocationTechnologyType techType);
+
+    /* disable will disable specific location technology to be used for calculation locations and
+       effectively ends the control session if call is successful.
+       id parameter is the session id that was returned in enable responseCallback for techType.
+       The session id is no longer valid after disable's responseCallback returns success.
+       This effect is global for all clients of LocationAPI
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_ID_UNKNOWN if id was not returned from responseCallback from enable
+                LOCATION_ERROR_GENERAL_FAILURE if failure for any other reason */
+    void disable(uint32_t id);
+
+    /* gnssUpdateConfig updates the gnss specific configuration, which returns a session id array
+       with an id for each of the bits set in GnssConfig.flags, order from low bits to high bits.
+       The response for each config that is set will be returned in collectiveResponseCallback.
+       The session id array returned will be valid until the collectiveResponseCallback is called
+       and has returned. This effect is global for all clients of LocationAPI
+        collectiveResponseCallback returns:
+                LOCATION_ERROR_SUCCESS if session was successful
+                LOCATION_ERROR_INVALID_PARAMETER if any other parameters are invalid
+                LOCATION_ERROR_GENERAL_FAILURE if failure for any other reason
+
+      PLEASE NOTE: It is caller's resposibility to FREE the memory of the return value.
+                   The memory must be freed by delete [].*/
+    virtual uint32_t* gnssUpdateConfig(const GnssConfig& config) override;
+
+    /* 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
+
+      PLEASE NOTE: It is caller's resposibility to FREE the memory of the return value.
+                   The memory must be freed by delete [].*/
+    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
+        responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+                LOCATION_ERROR_NOT_SUPPORTED if build is not userdebug */
+    virtual uint32_t gnssDeleteAidingData(GnssAidingData& data) override;
+
+    /** @brief
+        Configure the constellation and SVs to be used by the GNSS engine on
+        modem.
+
+        @param
+        constellationEnablementConfig: configuration to enable/disable SV
+        constellation to be used by SPE engine. When size in
+        constellationEnablementConfig is set to 0, this indicates to reset SV
+        constellation configuration to modem NV default.
+
+        blacklistSvConfig: configuration to blacklist or unblacklist SVs
+        used by SPE engine
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configConstellations(
+            const GnssSvTypeConfig& constellationEnablementConfig,
+            const GnssSvIdConfig&   blacklistSvConfig) override;
+
+    /** @brief
+        Configure the secondary band of constellations to be used by
+        the GNSS engine on modem.
+
+        @param
+        secondaryBandConfig: configuration the secondary band usage
+        for SPE engine
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configConstellationSecondaryBand(
+            const GnssSvTypeConfig& secondaryBandConfig) override;
+
+    /** @brief
+        Enable or disable the constrained time uncertainty feature.
+
+        @param
+        enable: true to enable the constrained time uncertainty
+        feature and false to disable the constrainted time
+        uncertainty feature.
+
+        @param
+        tuncThreshold: this specifies the time uncertainty threshold
+        that gps engine need to maintain, in units of milli-seconds.
+        Default is 0.0 meaning that modem default value of time
+        uncertainty threshold will be used. This parameter is
+        ignored when requesting to disable this feature.
+
+        @param
+        energyBudget: this specifies the power budget that gps
+        engine is allowed to spend to maintain the time uncertainty.
+        Default is 0 meaning that GPS engine is not constained by
+        power budget and can spend as much power as needed. The
+        parameter need to be specified in units of 0.1 milli watt
+        second. This parameter is ignored requesting to disable this
+        feature.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters
+                are invalid
+    */
+    virtual uint32_t configConstrainedTimeUncertainty(
+            bool enable, float tuncThreshold = 0.0,
+            uint32_t energyBudget = 0) override;
+
+    /** @brief
+        Enable or disable position assisted clock estimator feature.
+
+        @param
+        enable: true to enable position assisted clock estimator and
+        false to disable the position assisted clock estimator
+        feature.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configPositionAssistedClockEstimator(bool enable) override;
+
+        /** @brief
+        Sets the lever arm parameters for the vehicle.
+
+        @param
+        configInfo: lever arm configuration info regarding below two
+        types of lever arm info:
+        a: GNSS Antenna w.r.t the origin at the IMU e.g.: inertial
+        measurement unit.
+        b: lever arm parameters regarding the OPF (output frame)
+        w.r.t the origin (at the GPS Antenna). Vehicle manufacturers
+        prefer the position output to be tied to a specific point in
+        the vehicle rather than where the antenna is placed
+        (midpoint of the rear axle is typical).
+
+        Caller can choose types of lever arm info to configure via the
+        leverMarkTypeMask.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configLeverArm(const LeverArmConfigInfo& configInfo) override;
+
+    /** @brief
+        Configure the robust location setting.
+
+        @param
+        enable: true to enable robust location and false to disable
+        robust location.
+
+        @param
+        enableForE911: true to enable robust location when device is
+        on E911 session and false to disable on E911 session.
+        This parameter is only valid if robust location is enabled.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configRobustLocation(bool enable, bool enableForE911) override;
+
+    /** @brief
+        Config the minimal GPS week used by modem GNSS engine.
+
+        @param
+        minGpsWeek: minimal GPS week to be used by modem GNSS engine.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configMinGpsWeek(uint16_t minGpsWeek) override;
+
+    /** @brief
+        Configure the vehicle body-to-Sensor mount parameters and
+        other parameters for dead reckoning position engine.
+
+        @param
+        dreConfig: vehicle body-to-Sensor mount angles and other
+        parameters.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configDeadReckoningEngineParams(
+            const DeadReckoningEngineConfig& dreConfig) override;
+
+        /** @brief
+        This API is used to instruct the specified engine to be in
+        the pause/resume state. <br/>
+
+        When the engine is placed in paused state, the engine will
+        stop. If there is an on-going session, engine will no longer
+        produce fixes. In the paused state, calling API to delete
+        aiding data from the paused engine may not have effect.
+        Request to delete Aiding data shall be issued after
+        engine resume. <br/>
+
+        Currently, only DRE engine will support pause/resume
+        request. responseCb() will return not supported when request
+        is made to pause/resume none-DRE engine. <br/>
+
+        Request to pause/resume DRE engine can be made with or
+        without an on-going session. With QDR engine, on resume, GNSS
+        position & heading re-acquisition is needed for DR engine to
+        engage. If DR engine is already in the requested state, the
+        request will be no-op.  <br/>
+
+        @param
+        engType: the engine that is instructed to change its run
+        state. <br/>
+
+        engState: the new engine run state that the engine is
+        instructed to be in. <br/>
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response. This effect is global for all
+        clients of LocationAPI responseCallback returns:
+                LOCATION_ERROR_SUCCESS if successful
+                LOCATION_ERROR_INVALID_PARAMETER if any parameters are invalid
+    */
+    virtual uint32_t configEngineRunState(PositioningEngineMask engType,
+                                          LocEngineRunState engState) override;
+
+      /** @brief
+        Set the EULA opt-in status from system user. This is used as consent to
+        use network-based positioning.
+
+        @param
+        userConsnt: user agrees to use GTP service or not.
+
+        @return
+        A session id that will be returned in responseCallback to
+        match command with response.
+    */
+    virtual uint32_t setOptInStatus(bool userConsent);
+};
+
+#endif /* LOCATIONAPI_H */
diff --git a/gps/location/LocationAPIClientBase.cpp b/gps/location/LocationAPIClientBase.cpp
new file mode 100644
index 0000000..ea15a76
--- /dev/null
+++ b/gps/location/LocationAPIClientBase.cpp
@@ -0,0 +1,977 @@
+/* Copyright (c) 2017, 2020-2021 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_APIClientBase"
+
+#include <loc_pla.h>
+#include <log_util.h>
+#include <inttypes.h>
+#include <loc_cfg.h>
+#include "LocationAPIClientBase.h"
+
+#define GEOFENCE_SESSION_ID 0xFFFFFFFF
+#define CONFIG_SESSION_ID 0xFFFFFFFF
+
+// LocationAPIControlClient
+LocationAPIControlClient::LocationAPIControlClient() :
+    mEnabled(false)
+{
+    pthread_mutex_init(&mMutex, nullptr);
+
+    for (int i = 0; i < CTRL_REQUEST_MAX; i++) {
+        mRequestQueues[i].reset((uint32_t)0);
+    }
+
+    memset(&mConfig, 0, sizeof(GnssConfig));
+
+    LocationControlCallbacks locationControlCallbacks;
+    locationControlCallbacks.size = sizeof(LocationControlCallbacks);
+
+    locationControlCallbacks.responseCb =
+        [this](LocationError error, uint32_t id) {
+            onCtrlResponseCb(error, id);
+        };
+    locationControlCallbacks.collectiveResponseCb =
+        [this](size_t count, LocationError* errors, uint32_t* ids) {
+            onCtrlCollectiveResponseCb(count, errors, ids);
+        };
+
+    mLocationControlAPI = LocationControlAPI::createInstance(locationControlCallbacks);
+}
+
+LocationAPIControlClient::~LocationAPIControlClient()
+{
+    pthread_mutex_lock(&mMutex);
+
+    if (mLocationControlAPI) {
+        mLocationControlAPI->destroy();
+        mLocationControlAPI = nullptr;
+    }
+
+    for (int i = 0; i < CTRL_REQUEST_MAX; i++) {
+        mRequestQueues[i].reset((uint32_t)0);
+    }
+
+    pthread_mutex_unlock(&mMutex);
+
+    pthread_mutex_destroy(&mMutex);
+}
+
+uint32_t LocationAPIControlClient::locAPIGnssDeleteAidingData(GnssAidingData& data)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+    pthread_mutex_lock(&mMutex);
+    if (mLocationControlAPI) {
+        uint32_t session = mLocationControlAPI->gnssDeleteAidingData(data);
+        LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
+        mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].reset(session);
+        mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].push(new GnssDeleteAidingDataRequest(*this));
+
+        retVal = LOCATION_ERROR_SUCCESS;
+    }
+    pthread_mutex_unlock(&mMutex);
+
+    return retVal;
+}
+
+uint32_t LocationAPIControlClient::locAPIEnable(LocationTechnologyType techType)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+    pthread_mutex_lock(&mMutex);
+    if (mEnabled) {
+        // just return success if already enabled
+        retVal = LOCATION_ERROR_SUCCESS;
+    } else if (mLocationControlAPI) {
+        uint32_t session = mLocationControlAPI->enable(techType);
+        LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
+        mRequestQueues[CTRL_REQUEST_CONTROL].reset(session);
+        mRequestQueues[CTRL_REQUEST_CONTROL].push(new EnableRequest(*this));
+        retVal = LOCATION_ERROR_SUCCESS;
+        mEnabled = true;
+    } else {
+        LOC_LOGE("%s:%d] failed.", __FUNCTION__, __LINE__);
+    }
+    pthread_mutex_unlock(&mMutex);
+
+    return retVal;
+}
+
+void LocationAPIControlClient::locAPIDisable()
+{
+    pthread_mutex_lock(&mMutex);
+    if (mEnabled && mLocationControlAPI) {
+        uint32_t session = 0;
+        session = mRequestQueues[CTRL_REQUEST_CONTROL].getSession();
+        if (session > 0) {
+            mRequestQueues[CTRL_REQUEST_CONTROL].push(new DisableRequest(*this));
+            mLocationControlAPI->disable(session);
+            mEnabled = false;
+        } else {
+            LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
+        }
+    }
+    pthread_mutex_unlock(&mMutex);
+}
+
+uint32_t LocationAPIControlClient::locAPIGnssUpdateConfig(GnssConfig config)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+
+    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;
+                delete [] idArray;
+            }
+        }
+    }
+    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) {
+
+        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_GET].push(new GnssGetConfigRequest(*this));
+            retVal = LOCATION_ERROR_SUCCESS;
+            delete [] idArray;
+        }
+    }
+    pthread_mutex_unlock(&mMutex);
+    return retVal;
+}
+
+void LocationAPIControlClient::onCtrlResponseCb(LocationError error, uint32_t id)
+{
+    if (error != LOCATION_ERROR_SUCCESS) {
+        LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
+    } else {
+        LOC_LOGV("%s:%d] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, error, id);
+    }
+    LocationAPIRequest* request = getRequestBySession(id);
+    if (request) {
+        request->onResponse(error, id);
+        delete request;
+    }
+}
+
+void LocationAPIControlClient::onCtrlCollectiveResponseCb(
+        size_t count, LocationError* errors, uint32_t* ids)
+{
+    for (size_t i = 0; i < count; i++) {
+        if (errors[i] != LOCATION_ERROR_SUCCESS) {
+            LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
+        } else {
+            LOC_LOGV("%s:%d] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
+        }
+    }
+    LocationAPIRequest* request = getRequestBySessionArrayPtr(ids);
+    if (request) {
+        request->onCollectiveResponse(count, errors, ids);
+        delete request;
+    }
+}
+
+LocationAPIRequest* LocationAPIControlClient::getRequestBySession(uint32_t session)
+{
+    pthread_mutex_lock(&mMutex);
+    LocationAPIRequest* request = nullptr;
+
+    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;
+}
+
+// LocationAPIClientBase
+LocationAPIClientBase::LocationAPIClientBase() :
+    mGeofenceBreachCallback(nullptr),
+    mBatchingStatusCallback(nullptr),
+    mLocationAPI(nullptr),
+    mBatchSize(-1),
+    mTracking(false)
+{
+
+    // use recursive mutex, in case callback come from the same thread
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&mMutex, &attr);
+
+    for (int i = 0; i < REQUEST_MAX; i++) {
+        mRequestQueues[i].reset((uint32_t)0);
+    }
+}
+
+void LocationAPIClientBase::locAPISetCallbacks(LocationCallbacks& locationCallbacks)
+{
+    pthread_mutex_lock(&mMutex);
+
+    if (locationCallbacks.geofenceBreachCb != nullptr) {
+        mGeofenceBreachCallback = locationCallbacks.geofenceBreachCb;
+        locationCallbacks.geofenceBreachCb =
+            [this](GeofenceBreachNotification geofenceBreachNotification) {
+                beforeGeofenceBreachCb(geofenceBreachNotification);
+            };
+    }
+
+    locationCallbacks.capabilitiesCb =
+        [this](LocationCapabilitiesMask capabilitiesMask) {
+            onCapabilitiesCb(capabilitiesMask);
+        };
+    locationCallbacks.responseCb = [this](LocationError error, uint32_t id) {
+        onResponseCb(error, id);
+    };
+    locationCallbacks.collectiveResponseCb =
+        [this](size_t count, LocationError* errors, uint32_t* ids) {
+            onCollectiveResponseCb(count, errors, ids);
+        };
+
+    if (locationCallbacks.batchingStatusCb != nullptr) {
+        mBatchingStatusCallback = locationCallbacks.batchingStatusCb;
+        locationCallbacks.batchingStatusCb =
+            [this](BatchingStatusInfo batchStatus, std::list<uint32_t> & tripCompletedList) {
+            beforeBatchingStatusCb(batchStatus, tripCompletedList);
+        };
+    }
+
+    if (mLocationAPI == nullptr ) {
+        mLocationAPI = LocationAPI::createInstance(locationCallbacks);
+    } else {
+        mLocationAPI->updateCallbacks(locationCallbacks);
+    }
+
+    pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::destroy()
+{
+    LOC_LOGD("LocationAPIClientBase::destroy()");
+
+    pthread_mutex_lock(&mMutex);
+
+    mGeofenceBreachCallback = nullptr;
+
+    for (int i = 0; i < REQUEST_MAX; i++) {
+        mRequestQueues[i].reset((uint32_t)0);
+    }
+
+    LocationAPI* localHandle = nullptr;
+    if (nullptr != mLocationAPI) {
+        localHandle = mLocationAPI;
+        mLocationAPI = nullptr;
+    }
+
+    pthread_mutex_unlock(&mMutex);
+
+    // Invoking destroy has the possibility of destroy complete callback
+    // being invoked right away in the same context, hence no instance
+    // member must be accessed after the destroy call.
+    if (nullptr != localHandle) {
+        localHandle->destroy([this]() {onLocationApiDestroyCompleteCb();});
+    }
+}
+
+LocationAPIClientBase::~LocationAPIClientBase()
+{
+    pthread_mutex_destroy(&mMutex);
+}
+
+void LocationAPIClientBase::onLocationApiDestroyCompleteCb()
+{
+    LOC_LOGD("LocationAPIClientBase::onLocationApiDestroyCompleteCb()");
+    delete this;
+}
+
+uint32_t LocationAPIClientBase::locAPIStartTracking(TrackingOptions& options)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        if (mTracking) {
+            LOC_LOGW("%s:%d] Existing tracking session present", __FUNCTION__, __LINE__);
+        } else {
+            uint32_t session = mLocationAPI->startTracking(options);
+            LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
+            // onResponseCb might be called from other thread immediately after
+            // startTracking returns, so we are not going to unlock mutex
+            // until StartTrackingRequest is pushed into mRequestQueues[REQUEST_TRACKING]
+            mRequestQueues[REQUEST_TRACKING].reset(session);
+            mRequestQueues[REQUEST_TRACKING].push(new StartTrackingRequest(*this));
+            mTracking = true;
+        }
+
+        retVal = LOCATION_ERROR_SUCCESS;
+    }
+    pthread_mutex_unlock(&mMutex);
+
+    return retVal;
+}
+
+void LocationAPIClientBase::locAPIStopTracking()
+{
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        uint32_t session = 0;
+        session = mRequestQueues[REQUEST_TRACKING].getSession();
+        if (session > 0) {
+            mRequestQueues[REQUEST_TRACKING].push(new StopTrackingRequest(*this));
+            mLocationAPI->stopTracking(session);
+            mTracking = false;
+        } else {
+            LOC_LOGD("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
+        }
+    }
+    pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIUpdateTrackingOptions(TrackingOptions& options)
+{
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        uint32_t session = 0;
+        session = mRequestQueues[REQUEST_TRACKING].getSession();
+        if (session > 0) {
+            mRequestQueues[REQUEST_TRACKING].push(new UpdateTrackingOptionsRequest(*this));
+            mLocationAPI->updateTrackingOptions(session, options);
+        } else {
+            LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
+        }
+    }
+    pthread_mutex_unlock(&mMutex);
+}
+
+int32_t LocationAPIClientBase::locAPIGetBatchSize()
+{
+    if (mBatchSize == -1) {
+        const loc_param_s_type flp_conf_param_table[] =
+        {
+            {"BATCH_SIZE", &mBatchSize, nullptr, 'n'},
+        };
+        UTIL_READ_CONF(LOC_PATH_FLP_CONF, flp_conf_param_table);
+        if (mBatchSize < 0) {
+            // set mBatchSize to 0 if we got an illegal value from config file
+            mBatchSize = 0;
+        }
+    }
+    return mBatchSize;
+}
+
+uint32_t LocationAPIClientBase::locAPIStartSession(
+        uint32_t id, uint32_t sessionMode, TrackingOptions&& options)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+
+        if (mSessionBiDict.hasId(id)) {
+            LOC_LOGE("%s:%d] session %d has already started.", __FUNCTION__, __LINE__, id);
+            retVal = LOCATION_ERROR_ALREADY_STARTED;
+        } else {
+            uint32_t trackingSession = 0;
+            uint32_t batchingSession = 0;
+
+            if (sessionMode == SESSION_MODE_ON_FIX) {
+                trackingSession = mLocationAPI->startTracking(options);
+                LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, trackingSession);
+                mRequestQueues[REQUEST_SESSION].push(new StartTrackingRequest(*this));
+            } else {
+                // Fill in the batch mode
+                BatchingOptions batchOptions = {};
+                batchOptions.size = sizeof(BatchingOptions);
+                switch (sessionMode) {
+                case SESSION_MODE_ON_FULL:
+                    batchOptions.batchingMode = BATCHING_MODE_ROUTINE;
+                    break;
+                case SESSION_MODE_ON_TRIP_COMPLETED:
+                    batchOptions.batchingMode = BATCHING_MODE_TRIP;
+                    break;
+                default:
+                    batchOptions.batchingMode = BATCHING_MODE_NO_AUTO_REPORT;
+                    break;
+                }
+
+                // Populate location option values
+                batchOptions.minDistance = options.minDistance;
+                batchOptions.minInterval = options.minInterval;
+                batchOptions.mode = options.mode;
+
+                batchingSession = mLocationAPI->startBatching(batchOptions);
+                LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, batchingSession);
+                mRequestQueues[REQUEST_SESSION].setSession(batchingSession);
+                mRequestQueues[REQUEST_SESSION].push(new StartBatchingRequest(*this));
+            }
+
+            uint32_t session = ((sessionMode != SESSION_MODE_ON_FIX) ?
+                    batchingSession : trackingSession);
+
+            SessionEntity entity;
+            entity.id = id;
+            entity.trackingSession = trackingSession;
+            entity.batchingSession = batchingSession;
+            entity.sessionMode = sessionMode;
+            mSessionBiDict.set(id, session, entity);
+
+            retVal = LOCATION_ERROR_SUCCESS;
+        }
+
+    }
+    pthread_mutex_unlock(&mMutex);
+
+    return retVal;
+}
+
+uint32_t LocationAPIClientBase::locAPIStopSession(uint32_t id)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+
+        if (mSessionBiDict.hasId(id)) {
+            SessionEntity entity = mSessionBiDict.getExtById(id);
+
+            uint32_t trackingSession = entity.trackingSession;
+            uint32_t batchingSession = entity.batchingSession;
+            uint32_t sMode = entity.sessionMode;
+
+            if (sMode == SESSION_MODE_ON_FIX) {
+                mRequestQueues[REQUEST_SESSION].push(new StopTrackingRequest(*this));
+                mLocationAPI->stopTracking(trackingSession);
+            } else {
+                mRequestQueues[REQUEST_SESSION].push(new StopBatchingRequest(*this));
+                mLocationAPI->stopBatching(batchingSession);
+            }
+
+            retVal = LOCATION_ERROR_SUCCESS;
+        } else {
+            retVal = LOCATION_ERROR_ID_UNKNOWN;
+            LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
+        }
+
+    }
+    pthread_mutex_unlock(&mMutex);
+    return retVal;
+}
+
+uint32_t LocationAPIClientBase::locAPIUpdateSessionOptions(
+        uint32_t id, uint32_t sessionMode, TrackingOptions&& options)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+
+        if (mSessionBiDict.hasId(id)) {
+            SessionEntity entity = mSessionBiDict.getExtById(id);
+
+            uint32_t trackingSession = entity.trackingSession;
+            uint32_t batchingSession = entity.batchingSession;
+            uint32_t sMode = entity.sessionMode;
+
+            if (sessionMode == SESSION_MODE_ON_FIX) {
+                // we only add an UpdateTrackingOptionsRequest to mRequestQueues[REQUEST_SESSION],
+                // even if this update request will stop batching and then start tracking.
+                mRequestQueues[REQUEST_SESSION].push(new UpdateTrackingOptionsRequest(*this));
+                if (sMode == SESSION_MODE_ON_FIX) {
+                    mLocationAPI->updateTrackingOptions(trackingSession, options);
+                } else  {
+                    // stop batching
+                    // batchingSession will be removed from mSessionBiDict soon,
+                    // so we don't need to add a new request to mRequestQueues[REQUEST_SESSION].
+                    mLocationAPI->stopBatching(batchingSession);
+                    batchingSession = 0;
+                    mRequestQueues[REQUEST_SESSION].setSession(batchingSession);
+
+                    // start tracking
+                    trackingSession = mLocationAPI->startTracking(options);
+                    LOC_LOGI("%s:%d] start new session: %d",
+                            __FUNCTION__, __LINE__, trackingSession);
+                }
+            } else {
+                // we only add an UpdateBatchingOptionsRequest to mRequestQueues[REQUEST_SESSION],
+                // even if this update request will stop tracking and then start batching.
+                mRequestQueues[REQUEST_SESSION].push(new UpdateBatchingOptionsRequest(*this));
+                BatchingOptions batchOptions = {};
+                batchOptions.size = sizeof(BatchingOptions);
+                switch (sessionMode) {
+                case SESSION_MODE_ON_FULL:
+                    batchOptions.batchingMode = BATCHING_MODE_ROUTINE;
+                    break;
+                case SESSION_MODE_ON_TRIP_COMPLETED:
+                    batchOptions.batchingMode = BATCHING_MODE_TRIP;
+                    break;
+                default:
+                    batchOptions.batchingMode = BATCHING_MODE_NO_AUTO_REPORT;
+                    break;
+                }
+
+                if (sMode == SESSION_MODE_ON_FIX) {
+                    // stop tracking
+                    // trackingSession will be removed from mSessionBiDict soon,
+                    // so we don't need to add a new request to mRequestQueues[REQUEST_SESSION].
+                    mLocationAPI->stopTracking(trackingSession);
+                    trackingSession = 0;
+
+                    // Populate location option values
+                    batchOptions.minDistance = options.minDistance;
+                    batchOptions.minInterval = options.minInterval;
+                    batchOptions.mode = options.mode;
+
+                    // start batching
+                    batchingSession = mLocationAPI->startBatching(batchOptions);
+                    LOC_LOGI("%s:%d] start new session: %d",
+                            __FUNCTION__, __LINE__, batchingSession);
+                    mRequestQueues[REQUEST_SESSION].setSession(batchingSession);
+                } else {
+                    mLocationAPI->updateBatchingOptions(batchingSession, batchOptions);
+                }
+
+            }
+
+            uint32_t session = ((sessionMode != SESSION_MODE_ON_FIX) ?
+                    batchingSession : trackingSession);
+
+            entity.trackingSession = trackingSession;
+            entity.batchingSession = batchingSession;
+            entity.sessionMode = sessionMode;
+            // remove the old values from mSessionBiDict before we add a new one.
+            mSessionBiDict.rmById(id);
+            mSessionBiDict.set(id, session, entity);
+
+            retVal = LOCATION_ERROR_SUCCESS;
+        } else {
+            retVal = LOCATION_ERROR_ID_UNKNOWN;
+            LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
+        }
+    }
+    pthread_mutex_unlock(&mMutex);
+    return retVal;
+}
+
+uint32_t LocationAPIClientBase::locAPIGetBatchedLocations(uint32_t id, size_t count)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        if (mSessionBiDict.hasId(id)) {
+            SessionEntity entity = mSessionBiDict.getExtById(id);
+            if (entity.sessionMode != SESSION_MODE_ON_FIX) {
+                uint32_t batchingSession = entity.batchingSession;
+                mRequestQueues[REQUEST_SESSION].push(new GetBatchedLocationsRequest(*this));
+                mLocationAPI->getBatchedLocations(batchingSession, count);
+                retVal = LOCATION_ERROR_SUCCESS;
+            }  else {
+                LOC_LOGE("%s:%d] Unsupported for session id: %d, mode is SESSION_MODE_ON_FIX",
+                            __FUNCTION__, __LINE__, id);
+                retVal = LOCATION_ERROR_NOT_SUPPORTED;
+            }
+        }  else {
+            retVal = LOCATION_ERROR_ID_UNKNOWN;
+            LOC_LOGd("unknown session id: %d, might flush() a stopped session",  id);
+        }
+    }
+    pthread_mutex_unlock(&mMutex);
+
+    return retVal;
+}
+
+uint32_t LocationAPIClientBase::locAPIAddGeofences(
+        size_t count, uint32_t* ids, GeofenceOption* options, GeofenceInfo* data)
+{
+    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        if (mRequestQueues[REQUEST_GEOFENCE].getSession() != GEOFENCE_SESSION_ID) {
+            mRequestQueues[REQUEST_GEOFENCE].reset(GEOFENCE_SESSION_ID);
+        }
+        uint32_t* sessions = mLocationAPI->addGeofences(count, options, data);
+        if (sessions) {
+            LOC_LOGI("%s:%d] start new sessions: %p", __FUNCTION__, __LINE__, sessions);
+            mRequestQueues[REQUEST_GEOFENCE].push(new AddGeofencesRequest(*this));
+
+            for (size_t i = 0; i < count; i++) {
+                mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask);
+            }
+            retVal = LOCATION_ERROR_SUCCESS;
+        }
+    }
+    pthread_mutex_unlock(&mMutex);
+
+    return retVal;
+}
+
+void LocationAPIClientBase::locAPIRemoveGeofences(size_t count, uint32_t* ids)
+{
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
+        if (sessions == NULL) {
+            LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
+                    __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
+            pthread_mutex_unlock(&mMutex);
+            return;
+        }
+
+        if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+            BiDict<GeofenceBreachTypeMask>* removedGeofenceBiDict =
+                    new BiDict<GeofenceBreachTypeMask>();
+            size_t j = 0;
+            for (size_t i = 0; i < count; i++) {
+                sessions[j] = mGeofenceBiDict.getSession(ids[i]);
+                if (sessions[j] > 0) {
+                    GeofenceBreachTypeMask type = mGeofenceBiDict.getExtBySession(sessions[j]);
+                    mGeofenceBiDict.rmBySession(sessions[j]);
+                    removedGeofenceBiDict->set(ids[i], sessions[j], type);
+                    j++;
+                }
+            }
+            if (j > 0) {
+                mRequestQueues[REQUEST_GEOFENCE].push(new RemoveGeofencesRequest(*this,
+                        removedGeofenceBiDict));
+                mLocationAPI->removeGeofences(j, sessions);
+            } else {
+                delete(removedGeofenceBiDict);
+            }
+        } else {
+            LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
+                    mRequestQueues[REQUEST_GEOFENCE].getSession());
+        }
+
+        free(sessions);
+    }
+    pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIModifyGeofences(
+        size_t count, uint32_t* ids, GeofenceOption* options)
+{
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
+        if (sessions == NULL) {
+            LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
+                    __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
+            pthread_mutex_unlock(&mMutex);
+            return;
+        }
+
+        if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+            size_t j = 0;
+            for (size_t i = 0; i < count; i++) {
+                sessions[j] = mGeofenceBiDict.getSession(ids[i]);
+                if (sessions[j] > 0) {
+                    mGeofenceBiDict.set(ids[i], sessions[j], options[i].breachTypeMask);
+                    j++;
+                }
+            }
+            if (j > 0) {
+                mRequestQueues[REQUEST_GEOFENCE].push(new ModifyGeofencesRequest(*this));
+                mLocationAPI->modifyGeofences(j, sessions, options);
+            }
+        } else {
+            LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
+                    mRequestQueues[REQUEST_GEOFENCE].getSession());
+        }
+
+        free(sessions);
+    }
+    pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIPauseGeofences(size_t count, uint32_t* ids)
+{
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
+        if (sessions == NULL) {
+            LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
+                    __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
+            pthread_mutex_unlock(&mMutex);
+            return;
+        }
+
+        if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+            size_t j = 0;
+            for (size_t i = 0; i < count; i++) {
+                sessions[j] = mGeofenceBiDict.getSession(ids[i]);
+                if (sessions[j] > 0) {
+                    j++;
+                }
+            }
+            if (j > 0) {
+                mRequestQueues[REQUEST_GEOFENCE].push(new PauseGeofencesRequest(*this));
+                mLocationAPI->pauseGeofences(j, sessions);
+            }
+        } else {
+            LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
+                    mRequestQueues[REQUEST_GEOFENCE].getSession());
+        }
+
+        free(sessions);
+    }
+    pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIResumeGeofences(
+        size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask)
+{
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
+        if (sessions == NULL) {
+            LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
+                    __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
+            pthread_mutex_unlock(&mMutex);
+            return;
+        }
+
+        if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+            size_t j = 0;
+            for (size_t i = 0; i < count; i++) {
+                sessions[j] = mGeofenceBiDict.getSession(ids[i]);
+                if (sessions[j] > 0) {
+                    if (mask) {
+                        mGeofenceBiDict.set(ids[i], sessions[j], mask[i]);
+                    }
+                    j++;
+                }
+            }
+            if (j > 0) {
+                mRequestQueues[REQUEST_GEOFENCE].push(new ResumeGeofencesRequest(*this));
+                mLocationAPI->resumeGeofences(j, sessions);
+            }
+        } else {
+            LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
+                    mRequestQueues[REQUEST_GEOFENCE].getSession());
+        }
+
+        free(sessions);
+    }
+    pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::locAPIRemoveAllGeofences()
+{
+    std::vector<uint32_t> sessionsVec = mGeofenceBiDict.getAllSessions();
+    if (sessionsVec.size() > 0) {
+        locAPIRemoveGeofences(sessionsVec.size(), &sessionsVec[0]);
+    }
+}
+
+void LocationAPIClientBase::locAPIGnssNiResponse(uint32_t id, GnssNiResponse response)
+{
+    pthread_mutex_lock(&mMutex);
+    if (mLocationAPI) {
+        uint32_t session = id;
+        mLocationAPI->gnssNiResponse(id, response);
+        LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
+        mRequestQueues[REQUEST_NIRESPONSE].reset(session);
+        mRequestQueues[REQUEST_NIRESPONSE].push(new GnssNiResponseRequest(*this));
+    }
+    pthread_mutex_unlock(&mMutex);
+}
+
+void LocationAPIClientBase::beforeGeofenceBreachCb(
+        GeofenceBreachNotification geofenceBreachNotification)
+{
+    uint32_t* ids = (uint32_t*)malloc(sizeof(uint32_t) * geofenceBreachNotification.count);
+    uint32_t* backup = geofenceBreachNotification.ids;
+    size_t n = geofenceBreachNotification.count;
+    geofenceBreachCallback genfenceCallback = nullptr;
+
+    if (ids == NULL) {
+        LOC_LOGE("%s:%d] Failed to alloc %zu bytes",
+                __FUNCTION__, __LINE__,
+                sizeof(uint32_t) * geofenceBreachNotification.count);
+        return;
+    }
+
+    pthread_mutex_lock(&mMutex);
+    if (mGeofenceBreachCallback != nullptr) {
+        size_t count = 0;
+        for (size_t i = 0; i < n; i++) {
+            uint32_t id = mGeofenceBiDict.getId(geofenceBreachNotification.ids[i]);
+            GeofenceBreachTypeMask type =
+                mGeofenceBiDict.getExtBySession(geofenceBreachNotification.ids[i]);
+            // if type == 0, we will not head into the fllowing block anyway.
+            // so we don't need to check id and type
+            if ((geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER &&
+                        (type & GEOFENCE_BREACH_ENTER_BIT)) ||
+                    (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT &&
+                     (type & GEOFENCE_BREACH_EXIT_BIT))
+               ) {
+                ids[count] = id;
+                count++;
+            }
+        }
+        geofenceBreachNotification.count = count;
+        geofenceBreachNotification.ids = ids;
+
+        genfenceCallback = mGeofenceBreachCallback;
+    }
+    pthread_mutex_unlock(&mMutex);
+
+    if (genfenceCallback != nullptr) {
+        genfenceCallback(geofenceBreachNotification);
+    }
+
+    // restore ids
+    geofenceBreachNotification.ids = backup;
+    geofenceBreachNotification.count = n;
+    free(ids);
+}
+
+void LocationAPIClientBase::beforeBatchingStatusCb(BatchingStatusInfo batchStatus,
+        std::list<uint32_t> & tripCompletedList) {
+
+    // map the trip ids to the client ids
+    std::list<uint32_t> tripCompletedClientIdList;
+    tripCompletedClientIdList.clear();
+
+    if (batchStatus.batchingStatus == BATCHING_STATUS_TRIP_COMPLETED) {
+        for (auto itt = tripCompletedList.begin(); itt != tripCompletedList.end(); itt++) {
+            if (mSessionBiDict.hasSession(*itt)) {
+                SessionEntity sessEntity = mSessionBiDict.getExtBySession(*itt);
+
+                if (sessEntity.sessionMode == SESSION_MODE_ON_TRIP_COMPLETED) {
+                    tripCompletedClientIdList.push_back(sessEntity.id);
+                    mSessionBiDict.rmBySession(*itt);
+                }
+            }
+        }
+    }
+
+    mBatchingStatusCallback(batchStatus, tripCompletedClientIdList);
+}
+
+void LocationAPIClientBase::onResponseCb(LocationError error, uint32_t id)
+{
+    if (error != LOCATION_ERROR_SUCCESS) {
+        LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
+    } else {
+        LOC_LOGV("%s:%d] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, error, id);
+    }
+    LocationAPIRequest* request = getRequestBySession(id);
+    if (request) {
+        request->onResponse(error, id);
+        delete request;
+    }
+}
+
+void LocationAPIClientBase::onCollectiveResponseCb(
+        size_t count, LocationError* errors, uint32_t* ids)
+{
+    for (size_t i = 0; i < count; i++) {
+        if (errors[i] != LOCATION_ERROR_SUCCESS) {
+            LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
+        } else {
+            LOC_LOGV("%s:%d] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
+        }
+    }
+    LocationAPIRequest* request = nullptr;
+    pthread_mutex_lock(&mMutex);
+    if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
+        request = mRequestQueues[REQUEST_GEOFENCE].pop();
+    }
+    pthread_mutex_unlock(&mMutex);
+    if (request) {
+        request->onCollectiveResponse(count, errors, ids);
+        delete request;
+    }
+}
+
+void LocationAPIClientBase::removeSession(uint32_t session) {
+    if (mSessionBiDict.hasSession(session)) {
+        mSessionBiDict.rmBySession(session);
+    }
+}
+
+LocationAPIRequest* LocationAPIClientBase::getRequestBySession(uint32_t session)
+{
+    pthread_mutex_lock(&mMutex);
+    LocationAPIRequest* request = nullptr;
+    for (int i = 0; i < REQUEST_MAX; i++) {
+        if (i != REQUEST_GEOFENCE &&
+                i != REQUEST_SESSION &&
+                mRequestQueues[i].getSession() == session) {
+            request = mRequestQueues[i].pop();
+            break;
+        }
+    }
+    if (request == nullptr) {
+        // Can't find a request with correct session,
+        // try to find it from mSessionBiDict
+        if (mSessionBiDict.hasSession(session)) {
+            request = mRequestQueues[REQUEST_SESSION].pop();
+        }
+    }
+    pthread_mutex_unlock(&mMutex);
+    return request;
+}
diff --git a/gps/location/LocationAPIClientBase.h b/gps/location/LocationAPIClientBase.h
new file mode 100644
index 0000000..ac1ebe6
--- /dev/null
+++ b/gps/location/LocationAPIClientBase.h
@@ -0,0 +1,592 @@
+/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LOCATION_API_CLINET_BASE_H
+#define LOCATION_API_CLINET_BASE_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <queue>
+#include <map>
+
+#include "LocationAPI.h"
+#include <loc_pla.h>
+#include <log_util.h>
+
+enum SESSION_MODE {
+    SESSION_MODE_NONE = 0,
+    SESSION_MODE_ON_FULL,
+    SESSION_MODE_ON_FIX,
+    SESSION_MODE_ON_TRIP_COMPLETED
+};
+
+enum REQUEST_TYPE {
+    REQUEST_TRACKING = 0,
+    REQUEST_SESSION,
+    REQUEST_GEOFENCE,
+    REQUEST_NIRESPONSE,
+    REQUEST_MAX,
+};
+
+enum CTRL_REQUEST_TYPE {
+    CTRL_REQUEST_DELETEAIDINGDATA = 0,
+    CTRL_REQUEST_CONTROL,
+    CTRL_REQUEST_CONFIG_UPDATE,
+    CTRL_REQUEST_CONFIG_GET,
+    CTRL_REQUEST_MAX,
+};
+
+class LocationAPIClientBase;
+
+class LocationAPIRequest {
+public:
+    LocationAPIRequest() {}
+    virtual ~LocationAPIRequest() {}
+    virtual void onResponse(LocationError /*error*/, uint32_t /*id*/) {}
+    virtual void onCollectiveResponse(
+            size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
+};
+
+class RequestQueue {
+public:
+    RequestQueue(): mSession(0), mSessionArrayPtr(nullptr) {
+    }
+    virtual ~RequestQueue() {
+        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()) {
+            request = mQueue.front();
+            mQueue.pop();
+            delete request;
+        }
+        mSession = session;
+    }
+    void reset(uint32_t* sessionArrayPtr) {
+        reset((uint32_t)0);
+        mSessionArrayPtr = sessionArrayPtr;
+    }
+    void push(LocationAPIRequest* request) {
+        mQueue.push(request);
+    }
+    LocationAPIRequest* pop() {
+        LocationAPIRequest* request = nullptr;
+        if (!mQueue.empty()) {
+            request = mQueue.front();
+            mQueue.pop();
+        }
+        return request;
+    }
+    uint32_t getSession() { return mSession; }
+    uint32_t* getSessionArrayPtr() { return mSessionArrayPtr; }
+private:
+    uint32_t mSession;
+    uint32_t* mSessionArrayPtr;
+    std::queue<LocationAPIRequest*> mQueue;
+};
+
+class LocationAPIControlClient {
+public:
+    LocationAPIControlClient();
+    virtual ~LocationAPIControlClient();
+    LocationAPIControlClient(const LocationAPIControlClient&) = delete;
+    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);
+    void onCtrlCollectiveResponseCb(size_t count, LocationError* errors, uint32_t* ids);
+
+    inline virtual void onGnssDeleteAidingDataCb(LocationError /*error*/) {}
+    inline virtual void onEnableCb(LocationError /*error*/) {}
+    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:
+        GnssDeleteAidingDataRequest(LocationAPIControlClient& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t /*id*/) {
+            mAPI.onGnssDeleteAidingDataCb(error);
+        }
+        LocationAPIControlClient& mAPI;
+    };
+
+    class EnableRequest : public LocationAPIRequest {
+    public:
+        EnableRequest(LocationAPIControlClient& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t /*id*/) {
+            mAPI.onEnableCb(error);
+        }
+        LocationAPIControlClient& mAPI;
+    };
+
+    class DisableRequest : public LocationAPIRequest {
+    public:
+        DisableRequest(LocationAPIControlClient& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t /*id*/) {
+            mAPI.onDisableCb(error);
+        }
+        LocationAPIControlClient& mAPI;
+    };
+
+    class GnssUpdateConfigRequest : public LocationAPIRequest {
+    public:
+        GnssUpdateConfigRequest(LocationAPIControlClient& API) : mAPI(API) {}
+        inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* ids) {
+            mAPI.onGnssUpdateConfigCb(count, errors, ids);
+        }
+        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;
+    RequestQueue mRequestQueues[CTRL_REQUEST_MAX];
+    bool mEnabled;
+    GnssConfig mConfig;
+};
+
+class LocationAPIClientBase {
+public:
+    LocationAPIClientBase();
+    LocationAPIClientBase(const LocationAPIClientBase&) = delete;
+    LocationAPIClientBase& operator=(const LocationAPIClientBase&) = delete;
+
+    void destroy();
+    void onLocationApiDestroyCompleteCb();
+
+    void locAPISetCallbacks(LocationCallbacks& locationCallbacks);
+    void removeSession(uint32_t session);
+    LocationAPIRequest* getRequestBySession(uint32_t session);
+
+    // LocationAPI
+    uint32_t locAPIStartTracking(TrackingOptions& trackingOptions);
+    void locAPIStopTracking();
+    void locAPIUpdateTrackingOptions(TrackingOptions& trackingOptions);
+
+    int32_t locAPIGetBatchSize();
+    uint32_t locAPIStartSession(
+            uint32_t id, uint32_t sessionMode, TrackingOptions&& trackingOptions);
+    uint32_t locAPIStopSession(uint32_t id);
+    uint32_t locAPIUpdateSessionOptions(
+            uint32_t id, uint32_t sessionMode, TrackingOptions&& trackingOptions);
+    uint32_t locAPIGetBatchedLocations(uint32_t id, size_t count);
+
+    uint32_t locAPIAddGeofences(size_t count, uint32_t* ids,
+            GeofenceOption* options, GeofenceInfo* data);
+    void locAPIRemoveGeofences(size_t count, uint32_t* ids);
+    void locAPIModifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options);
+    void locAPIPauseGeofences(size_t count, uint32_t* ids);
+    void locAPIResumeGeofences(size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask);
+    void locAPIRemoveAllGeofences();
+
+    void locAPIGnssNiResponse(uint32_t id, GnssNiResponse response);
+
+    // callbacks
+    void onResponseCb(LocationError error, uint32_t id);
+    void onCollectiveResponseCb(size_t count, LocationError* errors, uint32_t* ids);
+
+    void beforeGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification);
+
+    inline virtual void onCapabilitiesCb(LocationCapabilitiesMask /*capabilitiesMask*/) {}
+    inline virtual void onGnssNmeaCb(GnssNmeaNotification /*gnssNmeaNotification*/) {}
+    inline virtual void onGnssDataCb(GnssDataNotification /*gnssDataNotification*/) {}
+    inline virtual void onGnssMeasurementsCb(
+            GnssMeasurementsNotification /*gnssMeasurementsNotification*/) {}
+
+    inline virtual void onTrackingCb(Location /*location*/) {}
+    inline virtual void onGnssSvCb(GnssSvNotification /*gnssSvNotification*/) {}
+    inline virtual void onStartTrackingCb(LocationError /*error*/) {}
+    inline virtual void onStopTrackingCb(LocationError /*error*/) {}
+    inline virtual void onUpdateTrackingOptionsCb(LocationError /*error*/) {}
+
+    inline virtual void onGnssLocationInfoCb(
+            GnssLocationInfoNotification /*gnssLocationInfoNotification*/) {}
+
+    inline virtual void onBatchingCb(size_t /*count*/, Location* /*location*/,
+            BatchingOptions /*batchingOptions*/) {}
+    inline virtual void onBatchingStatusCb(BatchingStatusInfo /*batchingStatus*/,
+            std::list<uint32_t> &/*listOfCompletedTrips*/) {}
+    void beforeBatchingStatusCb(BatchingStatusInfo batchStatus,
+            std::list<uint32_t> & tripCompletedList);
+    inline virtual void onStartBatchingCb(LocationError /*error*/) {}
+    inline virtual void onStopBatchingCb(LocationError /*error*/) {}
+    inline virtual void onUpdateBatchingOptionsCb(LocationError /*error*/) {}
+    inline virtual void onGetBatchedLocationsCb(LocationError /*error*/) {}
+
+    inline virtual void onGeofenceBreachCb(
+            GeofenceBreachNotification /*geofenceBreachNotification*/) {}
+    inline virtual void onGeofenceStatusCb(
+            GeofenceStatusNotification /*geofenceStatusNotification*/) {}
+    inline virtual void onAddGeofencesCb(
+            size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
+    inline virtual void onRemoveGeofencesCb(
+            size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
+    inline virtual void onModifyGeofencesCb(
+            size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
+    inline virtual void onPauseGeofencesCb(
+            size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
+    inline virtual void onResumeGeofencesCb(
+            size_t /*count*/, LocationError* /*errors*/, uint32_t* /*ids*/) {}
+
+    inline virtual void onGnssNiCb(uint32_t /*id*/, GnssNiNotification /*gnssNiNotification*/) {}
+    inline virtual void onGnssNiResponseCb(LocationError /*error*/) {}
+
+    inline virtual void onLocationSystemInfoCb(LocationSystemInfo /*locationSystemInfo*/) {}
+
+protected:
+    virtual ~LocationAPIClientBase();
+
+private:
+    // private inner classes
+    typedef struct {
+        uint32_t id;
+        uint32_t trackingSession;
+        uint32_t batchingSession;
+        uint32_t sessionMode;
+    } SessionEntity;
+
+    template<typename T>
+    class BiDict {
+    public:
+        BiDict() {
+            pthread_mutex_init(&mBiDictMutex, nullptr);
+        }
+        virtual ~BiDict() {
+            pthread_mutex_destroy(&mBiDictMutex);
+        }
+        bool hasId(uint32_t id) {
+            pthread_mutex_lock(&mBiDictMutex);
+            bool ret = (mForwardMap.find(id) != mForwardMap.end());
+            pthread_mutex_unlock(&mBiDictMutex);
+            return ret;
+        }
+        bool hasSession(uint32_t session) {
+            pthread_mutex_lock(&mBiDictMutex);
+            bool ret = (mBackwardMap.find(session) != mBackwardMap.end());
+            pthread_mutex_unlock(&mBiDictMutex);
+            return ret;
+        }
+        void set(uint32_t id, uint32_t session, T& ext) {
+            pthread_mutex_lock(&mBiDictMutex);
+            mForwardMap[id] = session;
+            mBackwardMap[session] = id;
+            mExtMap[session] = ext;
+            pthread_mutex_unlock(&mBiDictMutex);
+        }
+        void clear() {
+            pthread_mutex_lock(&mBiDictMutex);
+            mForwardMap.clear();
+            mBackwardMap.clear();
+            mExtMap.clear();
+            pthread_mutex_unlock(&mBiDictMutex);
+        }
+        void rmById(uint32_t id) {
+            pthread_mutex_lock(&mBiDictMutex);
+            mBackwardMap.erase(mForwardMap[id]);
+            mExtMap.erase(mForwardMap[id]);
+            mForwardMap.erase(id);
+            pthread_mutex_unlock(&mBiDictMutex);
+        }
+        void rmBySession(uint32_t session) {
+            pthread_mutex_lock(&mBiDictMutex);
+            mForwardMap.erase(mBackwardMap[session]);
+            mBackwardMap.erase(session);
+            mExtMap.erase(session);
+            pthread_mutex_unlock(&mBiDictMutex);
+        }
+        uint32_t getId(uint32_t session) {
+            pthread_mutex_lock(&mBiDictMutex);
+            uint32_t ret = 0;
+            auto it = mBackwardMap.find(session);
+            if (it != mBackwardMap.end()) {
+                ret = it->second;
+            }
+            pthread_mutex_unlock(&mBiDictMutex);
+            return ret;
+        }
+        uint32_t getSession(uint32_t id) {
+            pthread_mutex_lock(&mBiDictMutex);
+            uint32_t ret = 0;
+            auto it = mForwardMap.find(id);
+            if (it != mForwardMap.end()) {
+                ret = it->second;
+            }
+            pthread_mutex_unlock(&mBiDictMutex);
+            return ret;
+        }
+        T getExtById(uint32_t id) {
+            pthread_mutex_lock(&mBiDictMutex);
+            T ret;
+            memset(&ret, 0, sizeof(T));
+            uint32_t session = mForwardMap[id];
+            if (session > 0) {
+                auto it = mExtMap.find(session);
+                if (it != mExtMap.end()) {
+                    ret = it->second;
+                }
+            }
+            pthread_mutex_unlock(&mBiDictMutex);
+            return ret;
+        }
+        T getExtBySession(uint32_t session) {
+            pthread_mutex_lock(&mBiDictMutex);
+            T ret;
+            memset(&ret, 0, sizeof(T));
+            auto it = mExtMap.find(session);
+            if (it != mExtMap.end()) {
+                ret = it->second;
+            }
+            pthread_mutex_unlock(&mBiDictMutex);
+            return ret;
+        }
+        std::vector<uint32_t> getAllSessions() {
+            std::vector<uint32_t> ret;
+            pthread_mutex_lock(&mBiDictMutex);
+            for (auto it = mBackwardMap.begin(); it != mBackwardMap.end(); it++) {
+                ret.push_back(it->first);
+            }
+            pthread_mutex_unlock(&mBiDictMutex);
+            return ret;
+        }
+    private:
+        pthread_mutex_t mBiDictMutex;
+        // mForwarMap mapping id->session
+        std::map<uint32_t, uint32_t> mForwardMap;
+        // mBackwardMap mapping session->id
+        std::map<uint32_t, uint32_t> mBackwardMap;
+        // mExtMap mapping session->ext
+        std::map<uint32_t, T> mExtMap;
+    };
+
+    class StartTrackingRequest : public LocationAPIRequest {
+    public:
+        StartTrackingRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t id) {
+            if (error != LOCATION_ERROR_SUCCESS) {
+                mAPI.removeSession(id);
+            }
+            mAPI.onStartTrackingCb(error);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class StopTrackingRequest : public LocationAPIRequest {
+    public:
+        StopTrackingRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t id) {
+            mAPI.onStopTrackingCb(error);
+            if (error == LOCATION_ERROR_SUCCESS) {
+                mAPI.removeSession(id);
+            }
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class UpdateTrackingOptionsRequest : public LocationAPIRequest {
+    public:
+        UpdateTrackingOptionsRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t /*id*/) {
+            mAPI.onUpdateTrackingOptionsCb(error);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class StartBatchingRequest : public LocationAPIRequest {
+    public:
+        StartBatchingRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t id) {
+            if (error != LOCATION_ERROR_SUCCESS) {
+                mAPI.removeSession(id);
+            }
+            mAPI.onStartBatchingCb(error);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class StopBatchingRequest : public LocationAPIRequest {
+    public:
+        StopBatchingRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t id) {
+            mAPI.onStopBatchingCb(error);
+            if (error == LOCATION_ERROR_SUCCESS) {
+                mAPI.removeSession(id);
+            }
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class UpdateBatchingOptionsRequest : public LocationAPIRequest {
+    public:
+        UpdateBatchingOptionsRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t /*id*/) {
+            mAPI.onUpdateBatchingOptionsCb(error);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class GetBatchedLocationsRequest : public LocationAPIRequest {
+    public:
+        GetBatchedLocationsRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t /*id*/) {
+            mAPI.onGetBatchedLocationsCb(error);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class AddGeofencesRequest : public LocationAPIRequest {
+    public:
+        AddGeofencesRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) {
+            uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count);
+            for (size_t i = 0; i < count; i++) {
+                ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]);
+            }
+            LOC_LOGD("%s:]Returned geofence-id: %d in add geofence", __FUNCTION__, *ids);
+            mAPI.onAddGeofencesCb(count, errors, ids);
+            free(ids);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class RemoveGeofencesRequest : public LocationAPIRequest {
+    public:
+        RemoveGeofencesRequest(LocationAPIClientBase& API,
+                               BiDict<GeofenceBreachTypeMask>* removedGeofenceBiDict) :
+                               mAPI(API), mRemovedGeofenceBiDict(removedGeofenceBiDict) {}
+        inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) {
+            if (nullptr != mRemovedGeofenceBiDict) {
+                uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count);
+                for (size_t i = 0; i < count; i++) {
+                    ids[i] = mRemovedGeofenceBiDict->getId(sessions[i]);
+                }
+                LOC_LOGD("%s:]Returned geofence-id: %d in remove geofence", __FUNCTION__, *ids);
+                mAPI.onRemoveGeofencesCb(count, errors, ids);
+                free(ids);
+                delete(mRemovedGeofenceBiDict);
+            } else {
+                LOC_LOGE("%s:%d] Unable to access removed geofences data.", __FUNCTION__, __LINE__);
+            }
+        }
+        LocationAPIClientBase& mAPI;
+        BiDict<GeofenceBreachTypeMask>* mRemovedGeofenceBiDict;
+    };
+
+    class ModifyGeofencesRequest : public LocationAPIRequest {
+    public:
+        ModifyGeofencesRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) {
+            uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count);
+            for (size_t i = 0; i < count; i++) {
+                ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]);
+            }
+            mAPI.onModifyGeofencesCb(count, errors, ids);
+            free(ids);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class PauseGeofencesRequest : public LocationAPIRequest {
+    public:
+        PauseGeofencesRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) {
+            uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count);
+            for (size_t i = 0; i < count; i++) {
+                ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]);
+            }
+            mAPI.onPauseGeofencesCb(count, errors, ids);
+            free(ids);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class ResumeGeofencesRequest : public LocationAPIRequest {
+    public:
+        ResumeGeofencesRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onCollectiveResponse(size_t count, LocationError* errors, uint32_t* sessions) {
+            uint32_t *ids = (uint32_t*)malloc(sizeof(uint32_t) * count);
+            for (size_t i = 0; i < count; i++) {
+                ids[i] = mAPI.mGeofenceBiDict.getId(sessions[i]);
+            }
+            mAPI.onResumeGeofencesCb(count, errors, ids);
+            free(ids);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+    class GnssNiResponseRequest : public LocationAPIRequest {
+    public:
+        GnssNiResponseRequest(LocationAPIClientBase& API) : mAPI(API) {}
+        inline void onResponse(LocationError error, uint32_t /*id*/) {
+            mAPI.onGnssNiResponseCb(error);
+        }
+        LocationAPIClientBase& mAPI;
+    };
+
+private:
+    pthread_mutex_t mMutex;
+
+    geofenceBreachCallback mGeofenceBreachCallback;
+    batchingStatusCallback mBatchingStatusCallback;
+
+    LocationAPI* mLocationAPI;
+
+    RequestQueue mRequestQueues[REQUEST_MAX];
+    BiDict<GeofenceBreachTypeMask> mGeofenceBiDict;
+    BiDict<SessionEntity> mSessionBiDict;
+    int32_t mBatchSize;
+    bool mTracking;
+};
+
+#endif /* LOCATION_API_CLINET_BASE_H */
diff --git a/gps/location/LocationDataTypes.h b/gps/location/LocationDataTypes.h
new file mode 100644
index 0000000..b85464a
--- /dev/null
+++ b/gps/location/LocationDataTypes.h
@@ -0,0 +1,2070 @@
+/* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LOCATIONDATATYPES_H
+#define LOCATIONDATATYPES_H
+
+#include <vector>
+#include <stdint.h>
+#include <functional>
+#include <list>
+#include <string.h>
+#include <string>
+
+#define GNSS_NI_REQUESTOR_MAX  (256)
+#define GNSS_NI_MESSAGE_ID_MAX (2048)
+#define GNSS_SV_MAX            (128)
+#define GNSS_MEASUREMENTS_MAX  (128)
+#define GNSS_UTC_TIME_OFFSET   (3657)
+
+#define GNSS_BUGREPORT_GPS_MIN    (1)
+#define GNSS_BUGREPORT_SBAS_MIN   (120)
+#define GNSS_BUGREPORT_GLO_MIN    (1)
+#define GNSS_BUGREPORT_QZSS_MIN   (193)
+#define GNSS_BUGREPORT_BDS_MIN    (1)
+#define GNSS_BUGREPORT_GAL_MIN    (1)
+#define GNSS_BUGREPORT_NAVIC_MIN  (1)
+
+#define GNSS_MAX_NAME_LENGTH    (8)
+
+typedef enum {
+    LOCATION_ERROR_SUCCESS = 0,
+    LOCATION_ERROR_GENERAL_FAILURE,
+    LOCATION_ERROR_CALLBACK_MISSING,
+    LOCATION_ERROR_INVALID_PARAMETER,
+    LOCATION_ERROR_ID_EXISTS,
+    LOCATION_ERROR_ID_UNKNOWN,
+    LOCATION_ERROR_ALREADY_STARTED,
+    LOCATION_ERROR_GEOFENCES_AT_MAX,
+    LOCATION_ERROR_NOT_SUPPORTED,
+    LOCATION_ERROR_TIMEOUT,
+} LocationError;
+
+// Flags to indicate which values are valid in a Location
+typedef uint16_t LocationFlagsMask;
+typedef enum {
+    LOCATION_HAS_LAT_LONG_BIT          = (1<<0), // location has valid latitude and longitude
+    LOCATION_HAS_ALTITUDE_BIT          = (1<<1), // location has valid altitude
+    LOCATION_HAS_SPEED_BIT             = (1<<2), // location has valid speed
+    LOCATION_HAS_BEARING_BIT           = (1<<3), // location has valid bearing
+    LOCATION_HAS_ACCURACY_BIT          = (1<<4), // location has valid accuracy
+    LOCATION_HAS_VERTICAL_ACCURACY_BIT = (1<<5), // location has valid vertical accuracy
+    LOCATION_HAS_SPEED_ACCURACY_BIT    = (1<<6), // location has valid speed accuracy
+    LOCATION_HAS_BEARING_ACCURACY_BIT  = (1<<7), // location has valid bearing accuracy
+    LOCATION_HAS_SPOOF_MASK            = (1<<8), // location has valid spoof mask
+    LOCATION_HAS_ELAPSED_REAL_TIME     = (1<<9), // location has valid elapsed real time
+    LOCATION_HAS_CONFORMITY_INDEX_BIT  = (1<<10), // location has valid conformity index
+} LocationFlagsBits;
+
+typedef uint16_t LocationTechnologyMask;
+// mask indicating location calculations including...
+typedef enum {
+    LOCATION_TECHNOLOGY_GNSS_BIT                     = (1<<0), // using GNSS
+    LOCATION_TECHNOLOGY_CELL_BIT                     = (1<<1), // using Cell
+    LOCATION_TECHNOLOGY_WIFI_BIT                     = (1<<2), // using WiFi
+    LOCATION_TECHNOLOGY_SENSORS_BIT                  = (1<<3), // using Sensors
+    LOCATION_TECHNOLOGY_REFERENCE_LOCATION_BIT       = (1<<4), // using reference location
+    LOCATION_TECHNOLOGY_INJECTED_COARSE_POSITION_BIT = (1<<5), // using CPI
+    LOCATION_TECHNOLOGY_AFLT_BIT                     = (1<<6), // AFLT
+    LOCATION_TECHNOLOGY_HYBRID_BIT                   = (1<<7), // HYBRID
+    LOCATION_TECHNOLOGY_PPE_BIT                      = (1<<8), // PPE
+    LOCATION_TECHNOLOGY_VEH_BIT                      = (1<<9), // using vehicular data
+    LOCATION_TECHNOLOGY_VIS_BIT                      = (1<<10), // using visual data
+    LOCATION_TECHNOLOGY_DGNSS_BIT                    = (1<<11),  // DGNSS
+} LocationTechnologyBits;
+
+typedef uint32_t LocationSpoofMask;
+typedef enum {
+    LOCATION_POSTION_SPOOFED             = (1<<0), // location position spoofed
+    LOCATION_TIME_SPOOFED                = (1<<1), // location time spoofed
+    LOCATION_NAVIGATION_DATA_SPOOFED     = (1<<2), // location navigation data spoofed
+} LocationSpoofBits;
+
+typedef enum {
+    LOCATION_RELIABILITY_NOT_SET = 0,
+    LOCATION_RELIABILITY_VERY_LOW,
+    LOCATION_RELIABILITY_LOW,
+    LOCATION_RELIABILITY_MEDIUM,
+    LOCATION_RELIABILITY_HIGH,
+} LocationReliability;
+
+typedef uint32_t GnssLocationNavSolutionMask;
+typedef enum {
+    // SBAS ionospheric correction is used
+    LOCATION_SBAS_CORRECTION_IONO_BIT  = (1<<0),
+    // SBAS fast correction is used
+    LOCATION_SBAS_CORRECTION_FAST_BIT  = (1<<1),
+    // SBAS long-tem correction is used
+    LOCATION_SBAS_CORRECTION_LONG_BIT  = (1<<2),
+    // SBAS integrity information is used
+    LOCATION_SBAS_INTEGRITY_BIT        = (1<<3),
+    // Position Report is DGNSS corrected
+    LOCATION_NAV_CORRECTION_DGNSS_BIT  = (1<<4),
+     // Position Report is RTK corrected
+    LOCATION_NAV_CORRECTION_RTK_BIT    = (1<<5),
+    // Position Report is PPP corrected
+    LOCATION_NAV_CORRECTION_PPP_BIT    = (1<<6),
+    // Posiiton Report is RTF fixed corrected
+    LOCATION_NAV_CORRECTION_RTK_FIXED_BIT  = (1<<7),
+    // Position report is computed with only SBAS corrected SVs.
+    LOCATION_NAV_CORRECTION_ONLY_SBAS_CORRECTED_SV_USED_BIT = (1<<8)
+} GnssLocationNavSolutionBits;
+
+typedef uint32_t GnssLocationPosDataMask;
+typedef enum {
+    LOCATION_NAV_DATA_HAS_LONG_ACCEL_BIT  = (1<<0), // Navigation data has Forward Acceleration
+    LOCATION_NAV_DATA_HAS_LAT_ACCEL_BIT   = (1<<1), // Navigation data has Sideward Acceleration
+    LOCATION_NAV_DATA_HAS_VERT_ACCEL_BIT  = (1<<2), // Navigation data has Vertical Acceleration
+    LOCATION_NAV_DATA_HAS_YAW_RATE_BIT    = (1<<3), // Navigation data has Heading Rate
+    LOCATION_NAV_DATA_HAS_PITCH_BIT       = (1<<4),  // Navigation data has Body pitch
+    // Navigation data has Forward Acceleration uncertainty
+    LOCATION_NAV_DATA_HAS_LONG_ACCEL_UNC_BIT = (1<<5),
+    // Navigation data has Sideward Acceleration uncertainty
+    LOCATION_NAV_DATA_HAS_LAT_ACCEL_UNC_BIT  = (1<<6),
+    // Navigation data has Vertical Acceleration uncertainty
+    LOCATION_NAV_DATA_HAS_VERT_ACCEL_UNC_BIT = (1<<7),
+    // Navigation data has Heading Rate uncertainty
+    LOCATION_NAV_DATA_HAS_YAW_RATE_UNC_BIT   = (1<<8),
+    // Navigation data has Body pitch uncertainty
+    LOCATION_NAV_DATA_HAS_PITCH_UNC_BIT      = (1<<9)
+} GnssLocationPosDataBits;
+
+typedef uint32_t GnssLocationPosDataMaskExt;
+typedef enum {
+    // Navigation data has pitch rate
+    LOCATION_NAV_DATA_HAS_PITCH_RATE_BIT     = (1<<0),
+    // Navigation data has body pitch rate uncertainty
+    LOCATION_NAV_DATA_HAS_PITCH_RATE_UNC_BIT = (1<<1),
+    // Navigation data has body roll
+    LOCATION_NAV_DATA_HAS_ROLL_BIT           = (1<<2),
+    // Navigation data has body roll uncertainty
+    LOCATION_NAV_DATA_HAS_ROLL_UNC_BIT       = (1<<3),
+    // Navigation data has body rate roll
+    LOCATION_NAV_DATA_HAS_ROLL_RATE_BIT      = (1<<4),
+    // Navigation data has body roll rate uncertainty
+    LOCATION_NAV_DATA_HAS_ROLL_RATE_UNC_BIT  = (1<<5),
+    // Navigation data has body yaw
+    LOCATION_NAV_DATA_HAS_YAW_BIT            = (1<<6),
+    // Navigation data has body roll uncertainty
+    LOCATION_NAV_DATA_HAS_YAW_UNC_BIT        = (1<<7)
+} GnssLocationPosDataBitsExt;
+
+typedef uint64_t GnssLocationInfoFlagMask;
+typedef enum {
+    GNSS_LOCATION_INFO_ALTITUDE_MEAN_SEA_LEVEL_BIT      = (1<<0),  // altitude mean sea level
+    GNSS_LOCATION_INFO_DOP_BIT                          = (1<<1),  // pdop, hdop, and vdop
+    GNSS_LOCATION_INFO_MAGNETIC_DEVIATION_BIT           = (1<<2),  // magnetic deviation
+    GNSS_LOCATION_INFO_HOR_RELIABILITY_BIT              = (1<<3),  // horizontal reliability
+    GNSS_LOCATION_INFO_VER_RELIABILITY_BIT              = (1<<4),  // vertical reliability
+    GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MAJOR_BIT = (1<<5),  // elipsode semi major
+    GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_SEMI_MINOR_BIT = (1<<6),  // elipsode semi minor
+    GNSS_LOCATION_INFO_HOR_ACCURACY_ELIP_AZIMUTH_BIT    = (1<<7),  // accuracy elipsode azimuth
+    GNSS_LOCATION_INFO_GNSS_SV_USED_DATA_BIT            = (1<<8),  // svUsedInPosition,
+                                                                   //       numOfMeasReceived
+                                                                   //       and measUsageInfo
+    GNSS_LOCATION_INFO_NAV_SOLUTION_MASK_BIT            = (1<<9),  // navSolutionMask
+    GNSS_LOCATION_INFO_SV_SOURCE_INFO_BIT               = (1<<10), // LocSvInfoSource
+    GNSS_LOCATION_INFO_POS_DYNAMICS_DATA_BIT            = (1<<11), // position dynamics data &
+                                                                   //       Position Dynamics Ext
+    GNSS_LOCATION_INFO_EXT_DOP_BIT                      = (1<<12), // gdop, tdop
+    GNSS_LOCATION_INFO_NORTH_STD_DEV_BIT                = (1<<13), // North standard deviation
+    GNSS_LOCATION_INFO_EAST_STD_DEV_BIT                 = (1<<14), // East standard deviation
+    GNSS_LOCATION_INFO_NORTH_VEL_BIT                    = (1<<15), // North Velocity
+    GNSS_LOCATION_INFO_EAST_VEL_BIT                     = (1<<16), // East Velocity
+    GNSS_LOCATION_INFO_UP_VEL_BIT                       = (1<<17), // Up Velocity
+    GNSS_LOCATION_INFO_NORTH_VEL_UNC_BIT                = (1<<18), // North Velocity Uncertainty
+    GNSS_LOCATION_INFO_EAST_VEL_UNC_BIT                 = (1<<19), // East Velocity Uncertainty
+    GNSS_LOCATION_INFO_UP_VEL_UNC_BIT                   = (1<<20), // Up Velocity Uncertainty
+    GNSS_LOCATION_INFO_LEAP_SECONDS_BIT                 = (1<<21), // leap seconds
+    GNSS_LOCATION_INFO_TIME_UNC_BIT                     = (1<<22), // time uncertainty
+    GNSS_LOCATION_INFO_NUM_SV_USED_IN_POSITION_BIT      = (1<<23), // number of SV used in position
+    GNSS_LOCATION_INFO_CALIBRATION_CONFIDENCE_BIT       = (1<<24), // sensor cal confidence
+    GNSS_LOCATION_INFO_CALIBRATION_STATUS_BIT           = (1<<25), // sensor cal status
+    GNSS_LOCATION_INFO_OUTPUT_ENG_TYPE_BIT              = (1<<26), // output engine type
+    GNSS_LOCATION_INFO_OUTPUT_ENG_MASK_BIT              = (1<<27), // output engine mask
+    GNSS_LOCATION_INFO_CONFORMITY_INDEX_BIT             = (1<<28), // conformity index
+    GNSS_LOCATION_INFO_LLA_VRP_BASED_BIT                = (1<<29), // VRP-based lat/long/alt
+    GNSS_LOCATION_INFO_ENU_VELOCITY_VRP_BASED_BIT       = (1<<30), // VRP-based east/north/up vel
+    GNSS_LOCATION_INFO_DR_SOLUTION_STATUS_MASK_BIT      = (1ULL<<31), // Valid DR solution status
+    GNSS_LOCATION_INFO_ALTITUDE_ASSUMED_BIT             = (1ULL<<32), // Valid altitude assumed
+    GNSS_LOCATION_INFO_SESSION_STATUS_BIT               = (1ULL<<33), // session status
+} GnssLocationInfoFlagBits;
+
+typedef enum {
+    GEOFENCE_BREACH_ENTER = 0,
+    GEOFENCE_BREACH_EXIT,
+    GEOFENCE_BREACH_DWELL_IN,
+    GEOFENCE_BREACH_DWELL_OUT,
+    GEOFENCE_BREACH_UNKNOWN,
+} GeofenceBreachType;
+
+typedef uint16_t GeofenceBreachTypeMask;
+typedef enum {
+    GEOFENCE_BREACH_ENTER_BIT     = (1<<0),
+    GEOFENCE_BREACH_EXIT_BIT      = (1<<1),
+    GEOFENCE_BREACH_DWELL_IN_BIT  = (1<<2),
+    GEOFENCE_BREACH_DWELL_OUT_BIT = (1<<3),
+} GeofenceBreachTypeBits;
+
+typedef enum {
+    GEOFENCE_STATUS_AVAILABILE_NO = 0,
+    GEOFENCE_STATUS_AVAILABILE_YES,
+} GeofenceStatusAvailable;
+
+// Set of masks for Modem and QWES capabilities.
+typedef uint64_t LocationCapabilitiesMask;
+typedef enum {
+    // supports startTracking API with minInterval param
+    LOCATION_CAPABILITIES_TIME_BASED_TRACKING_BIT           = (1<<0),
+    // supports startBatching API with minInterval param
+    LOCATION_CAPABILITIES_TIME_BASED_BATCHING_BIT           = (1<<1),
+    // supports startTracking API with minDistance param
+    LOCATION_CAPABILITIES_DISTANCE_BASED_TRACKING_BIT       = (1<<2),
+    // supports startBatching API with minDistance param
+    LOCATION_CAPABILITIES_DISTANCE_BASED_BATCHING_BIT       = (1<<3),
+    // supports addGeofences API
+    LOCATION_CAPABILITIES_GEOFENCE_BIT                      = (1<<4),
+    // supports GnssMeasurementsCallback
+    LOCATION_CAPABILITIES_GNSS_MEASUREMENTS_BIT             = (1<<5),
+    // supports startTracking/startBatching API with LocationOptions.mode of MSB (Ms Based)
+    LOCATION_CAPABILITIES_GNSS_MSB_BIT                      = (1<<6),
+    // supports startTracking/startBatching API with LocationOptions.mode of MSA (MS Assisted)
+    LOCATION_CAPABILITIES_GNSS_MSA_BIT                      = (1<<7),
+    // supports debug nmea sentences in the debugNmeaCallback
+    LOCATION_CAPABILITIES_DEBUG_NMEA_BIT                    = (1<<8),
+    // support outdoor trip batching
+    LOCATION_CAPABILITIES_OUTDOOR_TRIP_BATCHING_BIT         = (1<<9),
+    // support constellation enablement
+    LOCATION_CAPABILITIES_CONSTELLATION_ENABLEMENT_BIT      = (1<<10),
+    // support agpm
+    LOCATION_CAPABILITIES_AGPM_BIT                          = (1<<11),
+    // support location privacy
+    LOCATION_CAPABILITIES_PRIVACY_BIT                       = (1<<12),
+    // support measurement corrections
+    LOCATION_CAPABILITIES_MEASUREMENTS_CORRECTION_BIT       = (1<<13),
+    // support Robust Location
+    LOCATION_CAPABILITIES_CONFORMITY_INDEX_BIT               = (1<<14),
+    // support precise location edgnss
+    LOCATION_CAPABILITIES_EDGNSS_BIT                        = (1<<15),
+    // Modem supports Carrier Phase for Precise Positioning
+    // Measurement Engine (PPME).
+    LOCATION_CAPABILITIES_QWES_CARRIER_PHASE_BIT            = (1<<16),
+    // Modem supports SV Polynomial for tightly coupled external
+    // DR support. This is a Standalone Feature.
+    LOCATION_CAPABILITIES_QWES_SV_POLYNOMIAL_BIT            = (1<<17),
+    // Modem supports SV Ephemeris for tightly coupled external
+    // PPE engines. This is a Standalone Feature.
+    LOCATION_CAPABILITIES_QWES_SV_EPHEMERIS_BIT            = (1<<18),
+    // Modem supports GNSS Single Frequency feature. This is a
+    // Standalone Feature.
+    LOCATION_CAPABILITIES_QWES_GNSS_SINGLE_FREQUENCY        = (1<<19),
+    // Modem supports GNSS Multi Frequency feature. Multi Frequency
+    // enables Single frequency also.
+    LOCATION_CAPABILITIES_QWES_GNSS_MULTI_FREQUENCY         = (1<<20),
+    // This mask indicates VPe license bundle is enabled. VEPP
+    // bundle include Carrier Phase and SV Polynomial features.
+    LOCATION_CAPABILITIES_QWES_VPE                          = (1<<21),
+    // This mask indicates support for CV2X Location basic features.
+    // This bundle includes features for GTS Time & Freq, C-TUNC
+    // (Constrained Time uncertainity.
+    LOCATION_CAPABILITIES_QWES_CV2X_LOCATION_BASIC          = (1<<22),
+    // This mask indicates support for CV2X Location premium features.
+    // This bundle includes features for CV2X Location Basic features,
+    // QDR3 feature, and PACE. (Position Assisted Clock Estimator.
+    LOCATION_CAPABILITIES_QWES_CV2X_LOCATION_PREMIUM         = (1<<23),
+    // This mask indicates that PPE (Precise Positioning Engine)
+    // library is enabled or Precise Positioning Framework (PPF)
+    // is available. This bundle includes features for Carrier
+    // Phase and SV Ephermeris.
+    LOCATION_CAPABILITIES_QWES_PPE                          = (1<<24),
+    // This mask indicates QDR2_C license bundle is enabled. This
+    // bundle includes features for SV Polynomial.
+    LOCATION_CAPABILITIES_QWES_QDR2                         = (1<<25),
+    // This mask indicates QDR3_C license bundle is enabled. This
+    // bundle includes features for SV Polynomial.
+    LOCATION_CAPABILITIES_QWES_QDR3                         = (1<<26),
+} LocationCapabilitiesBits;
+
+typedef uint8_t LocationQwesFeatureType;
+typedef enum {
+    // Modem supports Carrier Phase for Precise Positioning
+    // Measurement Engine (PPME).
+    LOCATION_QWES_FEATURE_TYPE_CARRIER_PHASE                 = 1,
+    // Modem supports SV Polynomial for tightly coupled external
+    // DR support. This is a Standalone Feature.
+    LOCATION_QWES_FEATURE_TYPE_SV_POLYNOMIAL,
+    // Modem supports SV Ephemeris for tightly coupled external
+    // PPE support. This is a Standalone Feature.
+    LOCATION_QWES_FEATURE_TYPE_SV_EPH,
+    // Modem supports GNSS Single Frequency feature. This is a
+    // Standalone Feature.
+    LOCATION_QWES_FEATURE_TYPE_GNSS_SINGLE_FREQUENCY,
+    // Modem supports GNSS Multi Frequency feature. Multi Frequency
+    // enables Single frequency also.
+    LOCATION_QWES_FEATURE_TYPE_GNSS_MULTI_FREQUENCY,
+    // This indicates Time and Frequency status.
+    LOCATION_QWES_FEATURE_TYPE_TIME_FREQUENCY,
+    // This indicates Time Uncertainty  status.
+    LOCATION_QWES_FEATURE_TYPE_TIME_UNCERTAINTY,
+    // This indicates Clock Estimate status.
+    LOCATION_QWES_FEATURE_TYPE_CLOCK_ESTIMATE,
+    // This mask indicates that PPE (Precise Positioning Engine)
+    // library is enabled or Precise Positioning Framework (PPF)
+    // is available. This bundle includes features for Carrier
+    // Phase and SV Ephermeris.
+    LOCATION_QWES_FEATURE_TYPE_PPE,
+    // This indicates QDR2_C license bundle is enabled. This
+    // bundle includes features for SV Polynomial.
+    LOCATION_QWES_FEATURE_TYPE_QDR2,
+    // This indicates QDR3_C license bundle is enabled. This
+    // bundle includes features for SV Polynomial.
+    LOCATION_QWES_FEATURE_TYPE_QDR3,
+    // This indicates VEPP license bundle is enabled. VEPP
+    // bundle include Carrier Phase and SV Polynomial features.
+    LOCATION_QWES_FEATURE_TYPE_VPE,
+    // Max value
+    LOCATION_QWES_FEATURE_TYPE_MAX
+} LocationQwesFeatureTypes;
+
+typedef enum {
+    LOCATION_TECHNOLOGY_TYPE_GNSS = 0,
+} LocationTechnologyType;
+
+// Configures how GPS is locked when GPS is disabled (through GnssDisable)
+enum {
+    GNSS_CONFIG_GPS_LOCK_NONE = 0, // gps is not locked when GPS is disabled (GnssDisable)
+    GNSS_CONFIG_GPS_LOCK_MO,       // gps mobile originated (MO) is locked when GPS is disabled
+    GNSS_CONFIG_GPS_LOCK_NI,       // gps network initiated (NI) is locked when GPS is disabled
+    GNSS_CONFIG_GPS_LOCK_MO_AND_NI,// gps MO and NI is locked when GPS is disabled
+};
+typedef int32_t GnssConfigGpsLock;
+
+// SUPL version
+typedef enum {
+    GNSS_CONFIG_SUPL_VERSION_1_0_0 = 1,
+    GNSS_CONFIG_SUPL_VERSION_2_0_0,
+    GNSS_CONFIG_SUPL_VERSION_2_0_2,
+    GNSS_CONFIG_SUPL_VERSION_2_0_4,
+} GnssConfigSuplVersion;
+
+// LTE Positioning Profile
+typedef uint16_t GnssConfigLppProfileMask;
+typedef enum {
+    GNSS_CONFIG_LPP_PROFILE_RRLP_ON_LTE = 0,                         // RRLP on LTE (Default)
+    GNSS_CONFIG_LPP_PROFILE_USER_PLANE_BIT                 = (1<<0), // LPP User Plane (UP) on LTE
+    GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_BIT              = (1<<1), // LPP_Control_Plane (CP)
+    GNSS_CONFIG_LPP_PROFILE_USER_PLANE_OVER_NR5G_SA_BIT    = (1<<2), // LPP User Plane (UP) on LTE
+    GNSS_CONFIG_LPP_PROFILE_CONTROL_PLANE_OVER_NR5G_SA_BIT = (1<<3), // LPP_Control_Plane (CP)
+} GnssConfigLppProfileBits;
+
+// Technology for LPPe Control Plane
+typedef uint16_t GnssConfigLppeControlPlaneMask;
+typedef enum {
+    GNSS_CONFIG_LPPE_CONTROL_PLANE_DBH_BIT                  = (1<<0), // DBH
+    GNSS_CONFIG_LPPE_CONTROL_PLANE_WLAN_AP_MEASUREMENTS_BIT = (1<<1), // WLAN_AP_MEASUREMENTS
+    GNSS_CONFIG_LPPE_CONTROL_PLANE_SRN_AP_MEASUREMENTS_BIT = (1<<2), // SRN_AP_MEASUREMENTS
+    GNSS_CONFIG_LPPE_CONTROL_PLANE_SENSOR_BARO_MEASUREMENTS_BIT = (1<<3),
+                                                             // SENSOR_BARO_MEASUREMENTS
+} GnssConfigLppeControlPlaneBits;
+
+// Technology for LPPe User Plane
+typedef uint16_t GnssConfigLppeUserPlaneMask;
+typedef enum {
+    GNSS_CONFIG_LPPE_USER_PLANE_DBH_BIT                  = (1<<0), // DBH
+    GNSS_CONFIG_LPPE_USER_PLANE_WLAN_AP_MEASUREMENTS_BIT = (1<<1), // WLAN_AP_MEASUREMENTS
+    GNSS_CONFIG_LPPE_USER_PLANE_SRN_AP_MEASUREMENTS_BIT = (1<<2), // SRN_AP_MEASUREMENTS
+    GNSS_CONFIG_LPPE_USER_PLANE_SENSOR_BARO_MEASUREMENTS_BIT = (1<<3),
+                                                            // SENSOR_BARO_MEASUREMENTS
+} GnssConfigLppeUserPlaneBits;
+
+// Positioning Protocol on A-GLONASS system
+typedef uint16_t GnssConfigAGlonassPositionProtocolMask;
+typedef enum {
+    GNSS_CONFIG_RRC_CONTROL_PLANE_BIT = (1<<0),  // RRC Control Plane
+    GNSS_CONFIG_RRLP_USER_PLANE_BIT   = (1<<1),  // RRLP User Plane
+    GNSS_CONFIG_LLP_USER_PLANE_BIT    = (1<<2),  // LPP User Plane
+    GNSS_CONFIG_LLP_CONTROL_PLANE_BIT = (1<<3),  // LPP Control Plane
+} GnssConfigAGlonassPositionProtocolBits;
+
+typedef enum {
+    GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_NO = 0,
+    GNSS_CONFIG_EMERGENCY_PDN_FOR_EMERGENCY_SUPL_YES,
+} GnssConfigEmergencyPdnForEmergencySupl;
+
+typedef enum {
+    GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_NO = 0,
+    GNSS_CONFIG_SUPL_EMERGENCY_SERVICES_YES,
+} GnssConfigSuplEmergencyServices;
+
+typedef uint16_t GnssConfigSuplModeMask;
+typedef enum {
+    GNSS_CONFIG_SUPL_MODE_MSB_BIT = (1<<0),
+    GNSS_CONFIG_SUPL_MODE_MSA_BIT = (1<<1),
+} GnssConfigSuplModeBits;
+
+typedef uint32_t GnssConfigFlagsMask;
+typedef enum {
+    GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT                   = (1<<0),
+    GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT               = (1<<1),
+    GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT        = (1<<2),
+    GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT                = (1<<3),
+    GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT         = (1<<4),
+    GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT            = (1<<5),
+    GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT = (1<<6),
+    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),
+    GNSS_CONFIG_FLAGS_EMERGENCY_EXTENSION_SECONDS_BIT      = (1<<11),
+    GNSS_CONFIG_FLAGS_ROBUST_LOCATION_BIT                  = (1<<12),
+    GNSS_CONFIG_FLAGS_MIN_GPS_WEEK_BIT                     = (1<<13),
+    GNSS_CONFIG_FLAGS_MIN_SV_ELEVATION_BIT                 = (1<<14),
+    GNSS_CONFIG_FLAGS_CONSTELLATION_SECONDARY_BAND_BIT     = (1<<15),
+} GnssConfigFlagsBits;
+
+typedef enum {
+    GNSS_NI_ENCODING_TYPE_NONE = 0,
+    GNSS_NI_ENCODING_TYPE_GSM_DEFAULT,
+    GNSS_NI_ENCODING_TYPE_UTF8,
+    GNSS_NI_ENCODING_TYPE_UCS2,
+} GnssNiEncodingType;
+
+typedef enum {
+    GNSS_NI_TYPE_VOICE = 0,
+    GNSS_NI_TYPE_SUPL,
+    GNSS_NI_TYPE_CONTROL_PLANE,
+    GNSS_NI_TYPE_EMERGENCY_SUPL
+} GnssNiType;
+
+typedef uint16_t GnssNiOptionsMask;
+typedef enum {
+    GNSS_NI_OPTIONS_NOTIFICATION_BIT     = (1<<0),
+    GNSS_NI_OPTIONS_VERIFICATION_BIT     = (1<<1),
+    GNSS_NI_OPTIONS_PRIVACY_OVERRIDE_BIT = (1<<2),
+} GnssNiOptionsBits;
+
+typedef enum {
+    GNSS_NI_RESPONSE_ACCEPT = 1,
+    GNSS_NI_RESPONSE_DENY,
+    GNSS_NI_RESPONSE_NO_RESPONSE,
+    GNSS_NI_RESPONSE_IGNORE,
+} GnssNiResponse;
+
+typedef enum {
+    GNSS_SV_TYPE_UNKNOWN = 0,
+    GNSS_SV_TYPE_GPS,
+    GNSS_SV_TYPE_SBAS,
+    GNSS_SV_TYPE_GLONASS,
+    GNSS_SV_TYPE_QZSS,
+    GNSS_SV_TYPE_BEIDOU,
+    GNSS_SV_TYPE_GALILEO,
+    GNSS_SV_TYPE_NAVIC,
+} GnssSvType;
+
+typedef enum {
+    GNSS_EPH_TYPE_UNKNOWN = 0,
+    GNSS_EPH_TYPE_EPHEMERIS,
+    GNSS_EPH_TYPE_ALMANAC,
+} GnssEphemerisType;
+
+typedef enum {
+    GNSS_EPH_SOURCE_UNKNOWN = 0,
+    GNSS_EPH_SOURCE_DEMODULATED,
+    GNSS_EPH_SOURCE_SUPL_PROVIDED,
+    GNSS_EPH_SOURCE_OTHER_SERVER_PROVIDED,
+    GNSS_EPH_SOURCE_LOCAL,
+} GnssEphemerisSource;
+
+typedef enum {
+    GNSS_EPH_HEALTH_UNKNOWN = 0,
+    GNSS_EPH_HEALTH_GOOD,
+    GNSS_EPH_HEALTH_BAD,
+} GnssEphemerisHealth;
+
+typedef uint16_t GnssSvOptionsMask;
+typedef enum {
+    GNSS_SV_OPTIONS_HAS_EPHEMER_BIT             = (1<<0),
+    GNSS_SV_OPTIONS_HAS_ALMANAC_BIT             = (1<<1),
+    GNSS_SV_OPTIONS_USED_IN_FIX_BIT             = (1<<2),
+    GNSS_SV_OPTIONS_HAS_CARRIER_FREQUENCY_BIT   = (1<<3),
+    GNSS_SV_OPTIONS_HAS_GNSS_SIGNAL_TYPE_BIT    = (1<<4)
+} GnssSvOptionsBits;
+
+typedef enum {
+    GNSS_ASSISTANCE_TYPE_SUPL = 0,
+    GNSS_ASSISTANCE_TYPE_C2K,
+    GNSS_ASSISTANCE_TYPE_SUPL_EIMS,
+    GNSS_ASSISTANCE_TYPE_SUPL_IMS,
+} GnssAssistanceType;
+
+typedef enum {
+    GNSS_SUPL_MODE_STANDALONE = 0,
+    GNSS_SUPL_MODE_MSB,
+    GNSS_SUPL_MODE_MSA,
+} GnssSuplMode;
+
+typedef enum {
+    BATCHING_MODE_ROUTINE = 0,   // positions are reported when batched positions memory is full
+    BATCHING_MODE_TRIP,          // positions are reported when a certain distance is covered
+    BATCHING_MODE_NO_AUTO_REPORT // no report of positions automatically, instead queried on demand
+} BatchingMode;
+
+typedef enum {
+    BATCHING_STATUS_TRIP_COMPLETED = 0,
+    BATCHING_STATUS_POSITION_AVAILABE,
+    BATCHING_STATUS_POSITION_UNAVAILABLE
+} BatchingStatus;
+
+typedef uint16_t GnssMeasurementsAdrStateMask;
+typedef enum {
+    GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_UNKNOWN                 = 0,
+    GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_VALID_BIT               = (1<<0),
+    GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_RESET_BIT               = (1<<1),
+    GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_CYCLE_SLIP_BIT          = (1<<2),
+    GNSS_MEASUREMENTS_ACCUMULATED_DELTA_RANGE_STATE_HALF_CYCLE_RESOLVED_BIT = (1<<3),
+} GnssMeasurementsAdrStateBits;
+
+typedef enum {
+    GNSS_MEASUREMENTS_CODE_TYPE_A       = 0,
+    GNSS_MEASUREMENTS_CODE_TYPE_B       = 1,
+    GNSS_MEASUREMENTS_CODE_TYPE_C       = 2,
+    GNSS_MEASUREMENTS_CODE_TYPE_I       = 3,
+    GNSS_MEASUREMENTS_CODE_TYPE_L       = 4,
+    GNSS_MEASUREMENTS_CODE_TYPE_M       = 5,
+    GNSS_MEASUREMENTS_CODE_TYPE_P       = 6,
+    GNSS_MEASUREMENTS_CODE_TYPE_Q       = 7,
+    GNSS_MEASUREMENTS_CODE_TYPE_S       = 8,
+    GNSS_MEASUREMENTS_CODE_TYPE_W       = 9,
+    GNSS_MEASUREMENTS_CODE_TYPE_X       = 10,
+    GNSS_MEASUREMENTS_CODE_TYPE_Y       = 11,
+    GNSS_MEASUREMENTS_CODE_TYPE_Z       = 12,
+    GNSS_MEASUREMENTS_CODE_TYPE_N       = 13,
+    GNSS_MEASUREMENTS_CODE_TYPE_OTHER   = 255,
+} GnssMeasurementsCodeType;
+
+typedef uint32_t GnssMeasurementsDataFlagsMask;
+typedef enum {
+    GNSS_MEASUREMENTS_DATA_SV_ID_BIT                        = (1<<0),
+    GNSS_MEASUREMENTS_DATA_SV_TYPE_BIT                      = (1<<1),
+    GNSS_MEASUREMENTS_DATA_STATE_BIT                        = (1<<2),
+    GNSS_MEASUREMENTS_DATA_RECEIVED_SV_TIME_BIT             = (1<<3),
+    GNSS_MEASUREMENTS_DATA_RECEIVED_SV_TIME_UNCERTAINTY_BIT = (1<<4),
+    GNSS_MEASUREMENTS_DATA_CARRIER_TO_NOISE_BIT             = (1<<5),
+    GNSS_MEASUREMENTS_DATA_PSEUDORANGE_RATE_BIT             = (1<<6),
+    GNSS_MEASUREMENTS_DATA_PSEUDORANGE_RATE_UNCERTAINTY_BIT = (1<<7),
+    GNSS_MEASUREMENTS_DATA_ADR_STATE_BIT                    = (1<<8),
+    GNSS_MEASUREMENTS_DATA_ADR_BIT                          = (1<<9),
+    GNSS_MEASUREMENTS_DATA_ADR_UNCERTAINTY_BIT              = (1<<10),
+    GNSS_MEASUREMENTS_DATA_CARRIER_FREQUENCY_BIT            = (1<<11),
+    GNSS_MEASUREMENTS_DATA_CARRIER_CYCLES_BIT               = (1<<12),
+    GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_BIT                = (1<<13),
+    GNSS_MEASUREMENTS_DATA_CARRIER_PHASE_UNCERTAINTY_BIT    = (1<<14),
+    GNSS_MEASUREMENTS_DATA_MULTIPATH_INDICATOR_BIT          = (1<<15),
+    GNSS_MEASUREMENTS_DATA_SIGNAL_TO_NOISE_RATIO_BIT        = (1<<16),
+    GNSS_MEASUREMENTS_DATA_AUTOMATIC_GAIN_CONTROL_BIT       = (1<<17),
+    GNSS_MEASUREMENTS_DATA_FULL_ISB_BIT                     = (1<<18),
+    GNSS_MEASUREMENTS_DATA_FULL_ISB_UNCERTAINTY_BIT         = (1<<19),
+    GNSS_MEASUREMENTS_DATA_SATELLITE_ISB_BIT                = (1<<20),
+    GNSS_MEASUREMENTS_DATA_SATELLITE_ISB_UNCERTAINTY_BIT    = (1<<21),
+    GNSS_MEASUREMENTS_DATA_CYCLE_SLIP_COUNT_BIT             = (1<<22),
+} GnssMeasurementsDataFlagsBits;
+
+typedef uint32_t GnssMeasurementsStateMask;
+typedef enum {
+    GNSS_MEASUREMENTS_STATE_UNKNOWN_BIT               = 0,
+    GNSS_MEASUREMENTS_STATE_CODE_LOCK_BIT             = (1<<0),
+    GNSS_MEASUREMENTS_STATE_BIT_SYNC_BIT              = (1<<1),
+    GNSS_MEASUREMENTS_STATE_SUBFRAME_SYNC_BIT         = (1<<2),
+    GNSS_MEASUREMENTS_STATE_TOW_DECODED_BIT           = (1<<3),
+    GNSS_MEASUREMENTS_STATE_MSEC_AMBIGUOUS_BIT        = (1<<4),
+    GNSS_MEASUREMENTS_STATE_SYMBOL_SYNC_BIT           = (1<<5),
+    GNSS_MEASUREMENTS_STATE_GLO_STRING_SYNC_BIT       = (1<<6),
+    GNSS_MEASUREMENTS_STATE_GLO_TOD_DECODED_BIT       = (1<<7),
+    GNSS_MEASUREMENTS_STATE_BDS_D2_BIT_SYNC_BIT       = (1<<8),
+    GNSS_MEASUREMENTS_STATE_BDS_D2_SUBFRAME_SYNC_BIT  = (1<<9),
+    GNSS_MEASUREMENTS_STATE_GAL_E1BC_CODE_LOCK_BIT    = (1<<10),
+    GNSS_MEASUREMENTS_STATE_GAL_E1C_2ND_CODE_LOCK_BIT = (1<<11),
+    GNSS_MEASUREMENTS_STATE_GAL_E1B_PAGE_SYNC_BIT     = (1<<12),
+    GNSS_MEASUREMENTS_STATE_SBAS_SYNC_BIT             = (1<<13),
+    GNSS_MEASUREMENTS_STATE_TOW_KNOWN_BIT             = (1<<14),
+    GNSS_MEASUREMENTS_STATE_GLO_TOD_KNOWN_BIT         = (1<<15),
+    GNSS_MEASUREMENTS_STATE_2ND_CODE_LOCK_BIT         = (1<<16),
+} GnssMeasurementsStateBits;
+
+typedef uint16_t GnssSingleSatCorrectionMask;
+typedef enum {
+    GNSS_MEAS_CORR_UNKNOWN_BIT                     = 0,
+    GNSS_MEAS_CORR_HAS_SAT_IS_LOS_PROBABILITY_BIT  = (1 << 0),
+    GNSS_MEAS_CORR_HAS_EXCESS_PATH_LENGTH_BIT      = (1 << 1),
+    GNSS_MEAS_CORR_HAS_EXCESS_PATH_LENGTH_UNC_BIT  = (1 << 2),
+    GNSS_MEAS_CORR_HAS_REFLECTING_PLANE_BIT        = (1 << 3),
+} GnssSingleSatCorrectionBits;
+
+typedef enum {
+    GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_UNKNOWN = 0,
+    GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_PRESENT,
+    GNSS_MEASUREMENTS_MULTIPATH_INDICATOR_NOT_PRESENT,
+} GnssMeasurementsMultipathIndicator;
+
+typedef uint32_t GnssMeasurementsClockFlagsMask;
+typedef enum {
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_LEAP_SECOND_BIT                  = (1<<0),
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_BIT                         = (1<<1),
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_TIME_UNCERTAINTY_BIT             = (1<<2),
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_FULL_BIAS_BIT                    = (1<<3),
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_BIT                         = (1<<4),
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_BIAS_UNCERTAINTY_BIT             = (1<<5),
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_BIT                        = (1<<6),
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_DRIFT_UNCERTAINTY_BIT            = (1<<7),
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_HW_CLOCK_DISCONTINUITY_COUNT_BIT = (1<<8),
+    GNSS_MEASUREMENTS_CLOCK_FLAGS_ELAPSED_REAL_TIME_BIT            = (1<<9),
+} GnssMeasurementsClockFlagsBits;
+
+typedef uint32_t GnssAidingDataSvMask;
+typedef enum {
+    GNSS_AIDING_DATA_SV_EPHEMERIS_BIT    = (1<<0), // ephemeris
+    GNSS_AIDING_DATA_SV_ALMANAC_BIT      = (1<<1), // almanac
+    GNSS_AIDING_DATA_SV_HEALTH_BIT       = (1<<2), // health
+    GNSS_AIDING_DATA_SV_DIRECTION_BIT    = (1<<3), // direction
+    GNSS_AIDING_DATA_SV_STEER_BIT        = (1<<4), // steer
+    GNSS_AIDING_DATA_SV_ALMANAC_CORR_BIT = (1<<5), // almanac correction
+    GNSS_AIDING_DATA_SV_BLACKLIST_BIT    = (1<<6), // blacklist SVs
+    GNSS_AIDING_DATA_SV_SA_DATA_BIT      = (1<<7), // sensitivity assistance data
+    GNSS_AIDING_DATA_SV_NO_EXIST_BIT     = (1<<8), // SV does not exist
+    GNSS_AIDING_DATA_SV_IONOSPHERE_BIT   = (1<<9), // ionosphere correction
+    GNSS_AIDING_DATA_SV_TIME_BIT         = (1<<10),// reset satellite time
+    GNSS_AIDING_DATA_SV_MB_DATA          = (1<<11),// delete multiband data
+    GNSS_AIDING_DATA_SV_POLY_BIT         = (1<<12),// poly
+} GnssAidingDataSvBits;
+
+typedef uint32_t GnssAidingDataSvTypeMask;
+typedef enum {
+    GNSS_AIDING_DATA_SV_TYPE_GPS_BIT      = (1<<0),
+    GNSS_AIDING_DATA_SV_TYPE_GLONASS_BIT  = (1<<1),
+    GNSS_AIDING_DATA_SV_TYPE_QZSS_BIT     = (1<<2),
+    GNSS_AIDING_DATA_SV_TYPE_BEIDOU_BIT   = (1<<3),
+    GNSS_AIDING_DATA_SV_TYPE_GALILEO_BIT  = (1<<4),
+    GNSS_AIDING_DATA_SV_TYPE_NAVIC_BIT    = (1<<5),
+    GNSS_AIDING_DATA_SV_TYPE_MAX          = (1<<6),
+} GnssAidingDataSvTypeBits;
+#define GNSS_AIDING_DATA_SV_TYPE_MASK_ALL (GNSS_AIDING_DATA_SV_TYPE_MAX-1)
+
+/* Gnss constellation type mask */
+typedef uint16_t GnssConstellationTypeMask;
+typedef enum {
+    GNSS_CONSTELLATION_TYPE_GPS_BIT      = (1<<0),
+    GNSS_CONSTELLATION_TYPE_GLONASS_BIT  = (1<<1),
+    GNSS_CONSTELLATION_TYPE_QZSS_BIT     = (1<<2),
+    GNSS_CONSTELLATION_TYPE_BEIDOU_BIT   = (1<<3),
+    GNSS_CONSTELLATION_TYPE_GALILEO_BIT  = (1<<4),
+    GNSS_CONSTELLATION_TYPE_SBAS_BIT     = (1<<5),
+    GNSS_CONSTELLATION_TYPE_NAVIC_BIT    = (1<<6),
+} GnssConstellationTypeBits;
+
+#define GNSS_CONSTELLATION_TYPE_MASK_ALL\
+        (GNSS_CONSTELLATION_TYPE_GPS_BIT     | GNSS_CONSTELLATION_TYPE_GLONASS_BIT |\
+         GNSS_CONSTELLATION_TYPE_QZSS_BIT    | GNSS_CONSTELLATION_TYPE_BEIDOU_BIT  |\
+         GNSS_CONSTELLATION_TYPE_GALILEO_BIT | GNSS_CONSTELLATION_TYPE_SBAS_BIT    |\
+         GNSS_CONSTELLATION_TYPE_NAVIC_BIT)
+
+/** GNSS Signal Type and RF Band */
+typedef uint32_t GnssSignalTypeMask;
+typedef enum {
+    /** GPS L1CA Signal */
+    GNSS_SIGNAL_GPS_L1CA            = (1<<0),
+    /** GPS L1C Signal */
+    GNSS_SIGNAL_GPS_L1C             = (1<<1),
+    /** GPS L2 RF Band */
+    GNSS_SIGNAL_GPS_L2              = (1<<2),
+    /** GPS L5 RF Band */
+    GNSS_SIGNAL_GPS_L5              = (1<<3),
+    /** GLONASS G1 (L1OF) RF Band */
+    GNSS_SIGNAL_GLONASS_G1          = (1<<4),
+    /** GLONASS G2 (L2OF) RF Band */
+    GNSS_SIGNAL_GLONASS_G2          = (1<<5),
+    /** GALILEO E1 RF Band */
+    GNSS_SIGNAL_GALILEO_E1          = (1<<6),
+    /** GALILEO E5A RF Band */
+    GNSS_SIGNAL_GALILEO_E5A         = (1<<7),
+    /** GALILEO E5B RF Band */
+    GNSS_SIGNAL_GALILEO_E5B         = (1<<8),
+    /** BEIDOU B1 RF Band */
+    GNSS_SIGNAL_BEIDOU_B1           = (1<<9),
+    /** BEIDOU B2 RF Band */
+    GNSS_SIGNAL_BEIDOU_B2           = (1<<10),
+    /** QZSS L1CA RF Band */
+    GNSS_SIGNAL_QZSS_L1CA           = (1<<11),
+    /** QZSS L1S RF Band */
+    GNSS_SIGNAL_QZSS_L1S            = (1<<12),
+    /** QZSS L2 RF Band */
+    GNSS_SIGNAL_QZSS_L2             = (1<<13),
+    /** QZSS L5 RF Band */
+    GNSS_SIGNAL_QZSS_L5             = (1<<14),
+    /** SBAS L1 RF Band */
+    GNSS_SIGNAL_SBAS_L1             = (1<<15),
+    /** BEIDOU B1I RF Band */
+    GNSS_SIGNAL_BEIDOU_B1I          = (1<<16),
+    /** BEIDOU B1C RF Band */
+    GNSS_SIGNAL_BEIDOU_B1C          = (1<<17),
+    /** BEIDOU B2I RF Band */
+    GNSS_SIGNAL_BEIDOU_B2I          = (1<<18),
+    /** BEIDOU B2AI RF Band */
+    GNSS_SIGNAL_BEIDOU_B2AI         = (1<<19),
+    /** NAVIC L5 RF Band */
+    GNSS_SIGNAL_NAVIC_L5            = (1<<20),
+    /** BEIDOU B2A_Q RF Band */
+    GNSS_SIGNAL_BEIDOU_B2AQ         = (1<<21),
+} GnssSignalTypeBits;
+
+#define GNSS_SIGNAL_TYPE_MASK_ALL\
+    (GNSS_SIGNAL_GPS_L1CA | GNSS_SIGNAL_GPS_L1C | GNSS_SIGNAL_GPS_L2 |\
+     GNSS_SIGNAL_GPS_L5| GNSS_SIGNAL_GLONASS_G1 | GNSS_SIGNAL_GLONASS_G2 |\
+     GNSS_SIGNAL_GALILEO_E1 | GNSS_SIGNAL_GALILEO_E5A | GNSS_SIGNAL_GALILEO_E5B |\
+     GNSS_SIGNAL_BEIDOU_B1I | GNSS_SIGNAL_BEIDOU_B1C | GNSS_SIGNAL_BEIDOU_B2I|\
+     GNSS_SIGNAL_BEIDOU_B2AI | GNSS_SIGNAL_QZSS_L1CA | GNSS_SIGNAL_QZSS_L1S |\
+     GNSS_SIGNAL_QZSS_L2| GNSS_SIGNAL_QZSS_L5 | GNSS_SIGNAL_SBAS_L1 |\
+     GNSS_SIGNAL_NAVIC_L5 | GNSS_SIGNAL_BEIDOU_B2AQ)
+
+typedef enum
+{
+    GNSS_LOC_SV_SYSTEM_UNKNOWN                = 0,
+    /** unknown sv system. */
+    GNSS_LOC_SV_SYSTEM_MIN                    = 1,
+    /**< Min enum of valid SV system. */
+    GNSS_LOC_SV_SYSTEM_GPS                    = 1,
+    /**< GPS satellite. */
+    GNSS_LOC_SV_SYSTEM_GALILEO                = 2,
+    /**< GALILEO satellite. */
+    GNSS_LOC_SV_SYSTEM_SBAS                   = 3,
+    /**< SBAS satellite. */
+    GNSS_LOC_SV_SYSTEM_GLONASS                = 4,
+    /**< GLONASS satellite. */
+    GNSS_LOC_SV_SYSTEM_BDS                    = 5,
+    /**< BDS satellite. */
+    GNSS_LOC_SV_SYSTEM_QZSS                   = 6,
+    /**< QZSS satellite. */
+    GNSS_LOC_SV_SYSTEM_NAVIC                  = 7,
+    /**< NAVIC satellite. */
+    GNSS_LOC_SV_SYSTEM_MAX                    = 7,
+    /**< Max enum of valid SV system. */
+} Gnss_LocSvSystemEnumType;
+
+typedef enum {
+    GNSS_LOC_SIGNAL_TYPE_GPS_L1CA = 0,          /**<  GPS L1CA Signal  */
+    GNSS_LOC_SIGNAL_TYPE_GPS_L1C = 1,           /**<  GPS L1C Signal  */
+    GNSS_LOC_SIGNAL_TYPE_GPS_L2C_L = 2,         /**<  GPS L2C_L RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_GPS_L5_Q = 3,          /**<  GPS L5_Q RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_GLONASS_G1 = 4,        /**<  GLONASS G1 (L1OF) RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_GLONASS_G2 = 5,        /**<  GLONASS G2 (L2OF) RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_GALILEO_E1_C = 6,      /**<  GALILEO E1_C RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_GALILEO_E5A_Q = 7,     /**<  GALILEO E5A_Q RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_GALILEO_E5B_Q = 8,     /**<  GALILEO E5B_Q RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1_I = 9,       /**<  BEIDOU B1_I RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_BEIDOU_B1C = 10,       /**<  BEIDOU B1C RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_BEIDOU_B2_I = 11,      /**<  BEIDOU B2_I RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_BEIDOU_B2A_I = 12,     /**<  BEIDOU B2A_I RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_QZSS_L1CA = 13,        /**<  QZSS L1CA RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_QZSS_L1S = 14,         /**<  QZSS L1S RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_QZSS_L2C_L = 15,       /**<  QZSS L2C_L RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_QZSS_L5_Q = 16,        /**<  QZSS L5_Q RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_SBAS_L1_CA = 17,       /**<  SBAS L1_CA RF Band  */
+    GNSS_LOC_SIGNAL_TYPE_NAVIC_L5 = 18,         /**<  NAVIC L5 RF Band */
+    GNSS_LOC_SIGNAL_TYPE_BEIDOU_B2A_Q = 19,     /**<  BEIDOU B2A_Q RF Band  */
+    GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES = 20    /**<  Maximum number of signal types */
+} Gnss_LocSignalEnumType;
+
+typedef uint32_t PositioningEngineMask;
+typedef enum {
+    STANDARD_POSITIONING_ENGINE = (1 << 0),
+    DEAD_RECKONING_ENGINE       = (1 << 1),
+    PRECISE_POSITIONING_ENGINE  = (1 << 2),
+    VP_POSITIONING_ENGINE  = (1 << 3)
+} PositioningEngineBits;
+#define POSITION_ENGINE_MASK_ALL \
+        (STANDARD_POSITIONING_ENGINE|DEAD_RECKONING_ENGINE| \
+        PRECISE_POSITIONING_ENGINE|VP_POSITIONING_ENGINE)
+
+/** Specify the position engine running state. <br/> */
+enum LocEngineRunState {
+    /** Request the position engine to be put into resume state.
+     *  <br/> */
+    LOC_ENGINE_RUN_STATE_PAUSE   = 1,
+    /** Request the position engine to be put into resume state.
+     *  <br/> */
+    LOC_ENGINE_RUN_STATE_RESUME   = 2,
+};
+
+typedef uint64_t GnssDataMask;
+typedef enum {
+    // Jammer Indicator is available
+    GNSS_LOC_DATA_JAMMER_IND_BIT = (1ULL << 0),
+    // AGC is available
+    GNSS_LOC_DATA_AGC_BIT = (1ULL << 1)
+} GnssDataBits;
+
+typedef uint32_t GnssSystemTimeStructTypeFlags;
+typedef enum {
+    GNSS_SYSTEM_TIME_WEEK_VALID             = (1 << 0),
+    GNSS_SYSTEM_TIME_WEEK_MS_VALID          = (1 << 1),
+    GNSS_SYSTEM_CLK_TIME_BIAS_VALID         = (1 << 2),
+    GNSS_SYSTEM_CLK_TIME_BIAS_UNC_VALID     = (1 << 3),
+    GNSS_SYSTEM_REF_FCOUNT_VALID            = (1 << 4),
+    GNSS_SYSTEM_NUM_CLOCK_RESETS_VALID      = (1 << 5)
+} GnssSystemTimeTypeBits;
+
+typedef uint32_t GnssGloTimeStructTypeFlags;
+typedef enum {
+    GNSS_CLO_DAYS_VALID                     = (1 << 0),
+    GNSS_GLO_MSEC_VALID                     = (1 << 1),
+    GNSS_GLO_CLK_TIME_BIAS_VALID            = (1 << 2),
+    GNSS_GLO_CLK_TIME_BIAS_UNC_VALID        = (1 << 3),
+    GNSS_GLO_REF_FCOUNT_VALID               = (1 << 4),
+    GNSS_GLO_NUM_CLOCK_RESETS_VALID         = (1 << 5),
+    GNSS_GLO_FOUR_YEAR_VALID                = (1 << 6)
+} GnssGloTimeTypeBits;
+
+typedef struct {
+    GnssAidingDataSvMask svMask;         // bitwise OR of GnssAidingDataSvBits
+    GnssAidingDataSvTypeMask svTypeMask; // bitwise OR of GnssAidingDataSvTypeBits
+} GnssAidingDataSv;
+
+typedef uint32_t GnssAidingDataCommonMask;
+typedef enum {
+    GNSS_AIDING_DATA_COMMON_POSITION_BIT      = (1<<0), // position estimate
+    GNSS_AIDING_DATA_COMMON_TIME_BIT          = (1<<1), // reset all clock values
+    GNSS_AIDING_DATA_COMMON_UTC_BIT           = (1<<2), // UTC estimate
+    GNSS_AIDING_DATA_COMMON_RTI_BIT           = (1<<3), // RTI
+    GNSS_AIDING_DATA_COMMON_FREQ_BIAS_EST_BIT = (1<<4), // frequency bias estimate
+    GNSS_AIDING_DATA_COMMON_CELLDB_BIT        = (1<<5), // all celldb info
+} GnssAidingDataCommonBits;
+
+typedef struct {
+    GnssAidingDataCommonMask mask; // bitwise OR of GnssAidingDataCommonBits
+} GnssAidingDataCommon;
+
+typedef uint32_t DrEngineAidingDataMask;
+typedef enum {
+    DR_ENGINE_AIDING_DATA_CALIBRATION_BIT = (1<<0), // Calibration data for DRE engine
+} DrEngineAidingDataBits;
+
+typedef struct {
+    bool deleteAll;              // if true, delete all aiding data and ignore other params
+    GnssAidingDataSv sv;         // SV specific aiding data
+    GnssAidingDataCommon common; // common aiding data
+    DrEngineAidingDataMask dreAidingDataMask;// aiding data mask for dr engine
+    PositioningEngineMask posEngineMask;     // engines to perform the delete operation on.
+} GnssAidingData;
+
+typedef uint16_t DrCalibrationStatusMask;
+typedef enum {
+    // Indicate that roll calibration is needed. Need to take more turns on level ground
+    DR_ROLL_CALIBRATION_NEEDED  = (1<<0),
+    // Indicate that pitch calibration is needed. Need to take more turns on level ground
+    DR_PITCH_CALIBRATION_NEEDED = (1<<1),
+    // Indicate that yaw calibration is needed. Need to accelerate in a straight line
+    DR_YAW_CALIBRATION_NEEDED   = (1<<2),
+    // Indicate that odo calibration is needed. Need to accelerate in a straight line
+    DR_ODO_CALIBRATION_NEEDED   = (1<<3),
+    // Indicate that gyro calibration is needed. Need to take more turns on level ground
+    DR_GYRO_CALIBRATION_NEEDED  = (1<<4)
+} DrCalibrationStatusBits;
+
+typedef struct {
+    uint32_t size;           // set to sizeof(Location)
+    LocationFlagsMask flags; // bitwise OR of LocationFlagsBits to mark which params are valid
+    uint64_t timestamp;      // UTC timestamp for location fix, milliseconds since January 1, 1970
+    double latitude;         // in degrees
+    double longitude;        // in degrees
+    double altitude;         // in meters above the WGS 84 reference ellipsoid
+    float speed;             // in meters per second
+    float bearing;           // in degrees; range [0, 360)
+    float accuracy;          // in meters
+    float verticalAccuracy;  // in meters
+    float speedAccuracy;     // in meters/second
+    float bearingAccuracy;   // in degrees (0 to 359.999)
+    float conformityIndex;   // in range [0, 1]
+    LocationTechnologyMask techMask;
+    LocationSpoofMask spoofMask;
+    uint64_t elapsedRealTime;    // in ns
+    uint64_t elapsedRealTimeUnc; // in ns
+} Location;
+
+typedef enum {
+    LOC_REQ_ENGINE_FUSED_BIT = (1<<0),
+    LOC_REQ_ENGINE_SPE_BIT   = (1<<1),
+    LOC_REQ_ENGINE_PPE_BIT   = (1<<2),
+    LOC_REQ_ENGINE_VPE_BIT   = (1<<3)
+} LocReqEngineTypeMask;
+
+typedef enum {
+    LOC_OUTPUT_ENGINE_FUSED   = 0,
+    /** This is the GNSS fix from modem */
+    LOC_OUTPUT_ENGINE_SPE     = 1,
+    /** This is the GNSS fix with correction PPP/RTK correction */
+    LOC_OUTPUT_ENGINE_PPE     = 2,
+    LOC_OUTPUT_ENGINE_VPE = 3,
+    LOC_OUTPUT_ENGINE_COUNT,
+} LocOutputEngineType;
+
+struct LocationOptions {
+    uint32_t size;          // set to sizeof(LocationOptions)
+    uint32_t minInterval; // in milliseconds
+    uint32_t minDistance; // in meters. if minDistance > 0, gnssSvCallback/gnssNmeaCallback/
+                          // gnssMeasurementsCallback may not be called
+    GnssSuplMode mode;    // Standalone/MS-Based/MS-Assisted
+    // behavior when this field is 0:
+    //  if engine hub is running, this will be fused fix,
+    //  if engine hub is not running, this will be SPE fix
+    LocReqEngineTypeMask locReqEngTypeMask;
+
+    inline LocationOptions() :
+            size(0), minInterval(0), minDistance(0), mode(GNSS_SUPL_MODE_STANDALONE),
+            locReqEngTypeMask((LocReqEngineTypeMask)0) {}
+};
+
+typedef enum {
+    GNSS_POWER_MODE_INVALID = 0,
+    GNSS_POWER_MODE_M1,  /* Improved Accuracy Mode */
+    GNSS_POWER_MODE_M2,  /* Normal Mode */
+    GNSS_POWER_MODE_M3,  /* Background Mode */
+    GNSS_POWER_MODE_M4,  /* Background Mode */
+    GNSS_POWER_MODE_M5   /* Background Mode */
+} GnssPowerMode;
+
+struct TrackingOptions : LocationOptions {
+    GnssPowerMode powerMode; /* Power Mode to be used for time based tracking
+                                sessions */
+    uint32_t tbm;  /* Time interval between measurements specified in millis.
+                      Applicable to background power modes */
+
+    inline TrackingOptions() :
+            LocationOptions(), powerMode(GNSS_POWER_MODE_INVALID), tbm(0) {}
+    inline TrackingOptions(uint32_t s, GnssPowerMode m, uint32_t t) :
+            LocationOptions(), powerMode(m), tbm(t) { LocationOptions::size = s; }
+    inline TrackingOptions(const LocationOptions& options) :
+            LocationOptions(options), powerMode(GNSS_POWER_MODE_INVALID), tbm(0) {}
+    inline void setLocationOptions(const LocationOptions& options) {
+        size = sizeof(TrackingOptions);
+        minInterval = options.minInterval;
+        minDistance = options.minDistance;
+        mode = options.mode;
+        locReqEngTypeMask = options.locReqEngTypeMask;
+    }
+    inline LocationOptions getLocationOptions() {
+        LocationOptions locOption;
+        locOption.size = sizeof(locOption);
+        locOption.minDistance = minDistance;
+        locOption.minInterval = minInterval;
+        locOption.mode = mode;
+        locOption.locReqEngTypeMask = locReqEngTypeMask;
+        return locOption;
+    }
+};
+
+struct BatchingOptions : LocationOptions {
+    BatchingMode batchingMode;
+
+    inline BatchingOptions() :
+            LocationOptions(), batchingMode(BATCHING_MODE_ROUTINE) {}
+    inline BatchingOptions(uint32_t s, BatchingMode m) :
+            LocationOptions(), batchingMode(m) { LocationOptions::size = s; }
+    inline BatchingOptions(const LocationOptions& options) :
+            LocationOptions(options), batchingMode(BATCHING_MODE_ROUTINE) {}
+    inline void setLocationOptions(const LocationOptions& options) {
+        minInterval = options.minInterval;
+        minDistance = options.minDistance;
+        mode = options.mode;
+    }
+};
+
+typedef struct {
+    uint32_t size;
+    BatchingStatus batchingStatus;
+} BatchingStatusInfo;
+
+typedef struct {
+    uint32_t size;                          // set to sizeof(GeofenceOption)
+    GeofenceBreachTypeMask breachTypeMask;  // bitwise OR of GeofenceBreachTypeBits
+    uint32_t responsiveness;                // in milliseconds
+    uint32_t dwellTime;                     // in seconds
+} GeofenceOption;
+
+typedef struct {
+    uint32_t size;    // set to sizeof(GeofenceInfo)
+    double latitude;  // in degrees
+    double longitude; // in degrees
+    double radius;    // in meters
+} GeofenceInfo;
+
+typedef struct {
+    uint32_t size;             // set to sizeof(GeofenceBreachNotification)
+    uint32_t count;            // number of ids in array
+    uint32_t* ids;           // array of ids that have breached
+    Location location;       // location associated with breach
+    GeofenceBreachType type; // type of breach
+    uint64_t timestamp;      // timestamp of breach
+} GeofenceBreachNotification;
+
+typedef struct {
+    uint32_t size;                       // set to sizeof(GeofenceBreachNotification)
+    GeofenceStatusAvailable available; // GEOFENCE_STATUS_AVAILABILE_NO/_YES
+    LocationTechnologyType techType;   // GNSS
+} GeofenceStatusNotification;
+
+typedef struct {
+    uint64_t gpsSvUsedIdsMask;
+    uint64_t gloSvUsedIdsMask;
+    uint64_t galSvUsedIdsMask;
+    uint64_t bdsSvUsedIdsMask;
+    uint64_t qzssSvUsedIdsMask;
+    uint64_t navicSvUsedIdsMask;
+} GnssLocationSvUsedInPosition;
+
+typedef struct {
+    /** GnssSignalType mask */
+    GnssSignalTypeMask gnssSignalType;
+   /** Specifies GNSS Constellation Type */
+    Gnss_LocSvSystemEnumType gnssConstellation;
+    /** Unique SV Identifier.
+     *  For SV Range of supported constellation, please refer to
+     *  the comment section of svId in GnssSv.
+     *  For GLONASS:  When slot-number to SV ID mapping is unknown, set as 255.
+     */
+    uint16_t gnssSvId;
+} GnssMeasUsageInfo;
+
+/** @struct
+    Body Frame parameters
+*/
+typedef struct {
+    GnssLocationPosDataMask bodyFrameDataMask; // Contains Body frame LocPosDataMask bits
+    float longAccel;                           // Forward Acceleration in body frame (m/s2)
+    float latAccel;                            // Sideward Acceleration in body frame (m/s2)
+    float vertAccel;                           // Vertical Acceleration in body frame (m/s2)
+    float yawRate;                             // Heading Rate (Radians/second)
+    float pitch;                               // Body pitch (Radians)
+    float longAccelUnc;   // Uncertainty of Forward Acceleration in body frame
+    float latAccelUnc;    // Uncertainty of Side-ward Acceleration in body frame
+    float vertAccelUnc;   // Uncertainty of Vertical Acceleration in body frame
+    float yawRateUnc;     // Uncertainty of Heading Rate
+    float pitchUnc;       // Uncertainty of Body pitch
+} GnssLocationPositionDynamics;
+
+typedef struct {
+    GnssLocationPosDataMaskExt bodyFrameDataMask; // Contains Ext Body frame LocPosDataMask bits
+    float pitchRate;      // Body pitch rate (Radians/second)
+    float pitchRateUnc;   // Uncertainty of pitch rate (Radians/second)
+    float roll;           // Roll of body frame. Clockwise positive. (radian
+    float rollUnc;        // Uncertainty of Roll, 68% confidence level (radian)
+    float rollRate;       // Roll rate of body frame. Clockwise positive. (radian/second)
+    float rollRateUnc;    // Uncertainty of Roll rate, 68% confidence level (radian/second)
+    float yaw;            // Yaw of body frame. Clockwise positive (radian)
+    float yawUnc;         // Uncertainty of Yaw, 68% confidence level (radian)
+} GnssLocationPositionDynamicsExt;
+
+typedef struct {
+    /** Validity mask for below fields */
+    GnssSystemTimeStructTypeFlags validityMask;
+    /** Extended week number at reference tick.
+    Unit: Week.
+    Set to 65535 if week number is unknown.
+    For GPS:
+      Calculated from midnight, Jan. 6, 1980.
+      OTA decoded 10 bit GPS week is extended to map between:
+      [NV6264 to (NV6264 + 1023)].
+      NV6264: Minimum GPS week number configuration.
+      Default value of NV6264: 1738
+    For BDS:
+      Calculated from 00:00:00 on January 1, 2006 of Coordinated Universal Time (UTC).
+    For GAL:
+      Calculated from 00:00 UT on Sunday August 22, 1999 (midnight between August 21 and August 22).
+   */
+    uint16_t systemWeek;
+    /** Time in to the current week at reference tick.
+       Unit: Millisecond. Range: 0 to 604799999.
+       Check for systemClkTimeUncMs before use */
+    uint32_t systemMsec;
+    /** System clock time bias (sub-millisecond)
+        Units: Millisecond
+        Note: System time (TOW Millisecond) = systemMsec - systemClkTimeBias.
+        Check for systemClkTimeUncMs before use. */
+    float systemClkTimeBias;
+    /** Single sided maximum time bias uncertainty
+        Units: Millisecond */
+    float systemClkTimeUncMs;
+    /** FCount (free running HW timer) value. Don't use for relative time purpose
+         due to possible discontinuities.
+         Unit: Millisecond */
+    uint32_t refFCount;
+    /** Number of clock resets/discontinuities detected, affecting the local hardware counter value. */
+    uint32_t numClockResets;
+} GnssSystemTimeStructType;
+
+typedef struct {
+    /** GLONASS day number in four years. Refer to GLONASS ICD.
+        Applicable only for GLONASS and shall be ignored for other constellations.
+        If unknown shall be set to 65535 */
+    uint16_t gloDays;
+    /** Validity mask for below fields */
+    GnssGloTimeStructTypeFlags validityMask;
+    /** GLONASS time of day in Millisecond. Refer to GLONASS ICD.
+        Units: Millisecond
+        Check for gloClkTimeUncMs before use */
+    uint32_t gloMsec;
+    /** GLONASS clock time bias (sub-millisecond)
+        Units: Millisecond
+        Note: GLO time (TOD Millisecond) = gloMsec - gloClkTimeBias.
+        Check for gloClkTimeUncMs before use. */
+    float gloClkTimeBias;
+    /** Single sided maximum time bias uncertainty
+        Units: Millisecond */
+    float gloClkTimeUncMs;
+    /** FCount (free running HW timer) value. Don't use for relative time purpose
+        due to possible discontinuities.
+        Unit: Millisecond */
+    uint32_t  refFCount;
+    /** Number of clock resets/discontinuities detected, affecting the local hardware counter value. */
+    uint32_t numClockResets;
+    /** GLONASS four year number from 1996. Refer to GLONASS ICD.
+        Applicable only for GLONASS and shall be ignored for other constellations.
+        If unknown shall be set to 255 */
+    uint8_t gloFourYear;
+} GnssGloTimeStructType;
+
+typedef union {
+    GnssSystemTimeStructType gpsSystemTime;
+    GnssSystemTimeStructType galSystemTime;
+    GnssSystemTimeStructType bdsSystemTime;
+    GnssSystemTimeStructType qzssSystemTime;
+    GnssGloTimeStructType    gloSystemTime;
+    GnssSystemTimeStructType navicSystemTime;
+} SystemTimeStructUnion;
+    /** Time applicability of PVT report */
+typedef struct {
+    /** Specifies GNSS system time reported. Mandatory field */
+    Gnss_LocSvSystemEnumType gnssSystemTimeSrc;
+    /** Reporting of GPS system time is recommended.
+      If GPS time is unknown & other satellite system time is known,
+      it should be reported.
+      Mandatory field
+     */
+    SystemTimeStructUnion u;
+} GnssSystemTime;
+
+typedef uint32_t DrSolutionStatusMask;
+#define VEHICLE_SENSOR_SPEED_INPUT_DETECTED (1<<0)
+#define VEHICLE_SENSOR_SPEED_INPUT_USED     (1<<1)
+
+typedef struct {
+    double latitude;  // in degree
+    double longitude; // in degree
+    float altitude;  // altitude wrt to ellipsoid
+} LLAInfo;
+
+enum loc_sess_status {
+    LOC_SESS_SUCCESS,
+    LOC_SESS_INTERMEDIATE,
+    LOC_SESS_FAILURE
+};
+
+typedef struct {
+    uint32_t size;                      // set to sizeof(GnssLocationInfo)
+    Location location;                  // basic locaiton info, latitude, longitude, and etc
+    GnssLocationInfoFlagMask flags;     // bitwise OR of GnssLocationInfoBits for param validity
+    float altitudeMeanSeaLevel;         // altitude wrt mean sea level
+    float pdop;                         // position dilusion of precision
+    float hdop;                         // horizontal dilusion of precision
+    float vdop;                         // vertical dilusion of precision
+    float gdop;                         // geometric  dilution of precision
+    float tdop;                         // time dilution of precision
+    float magneticDeviation;            // magnetic deviation
+    LocationReliability horReliability; // horizontal reliability
+    LocationReliability verReliability; // vertical reliability
+    float horUncEllipseSemiMajor;       // horizontal elliptical accuracy semi-major axis
+    float horUncEllipseSemiMinor;       // horizontal elliptical accuracy semi-minor axis
+    float horUncEllipseOrientAzimuth;   // horizontal elliptical accuracy azimuth
+    float northStdDeviation;            // North standard deviation Unit: Meters
+    float eastStdDeviation;             // East standard deviation. Unit: Meters
+    float northVelocity;                // North Velocity.Unit: Meters/sec
+    float eastVelocity;                 // East Velocity Unit Meters/sec
+    float upVelocity;                   // Up Velocity. Unit Meters/sec
+    float northVelocityStdDeviation;
+    float eastVelocityStdDeviation;
+    float upVelocityStdDeviation;
+    uint16_t numSvUsedInPosition;
+    GnssLocationSvUsedInPosition svUsedInPosition;// Gnss sv used in position data
+    GnssLocationNavSolutionMask navSolutionMask;  // Nav solution mask to indicate sbas corrections
+    GnssLocationPositionDynamics bodyFrameData;   // Body Frame Dynamics: 4wayAcceleration and
+                                                  // pitch set with validity
+    GnssSystemTime gnssSystemTime;            // GNSS System Time
+    uint8_t numOfMeasReceived; // Number of measurements received for use in fix.
+    GnssMeasUsageInfo measUsageInfo[GNSS_SV_MAX]; // GNSS Measurement Usage info
+    uint8_t leapSeconds;                          // leap second
+    float timeUncMs;                              // Time uncertainty in milliseconds
+    uint8_t calibrationConfidence;                // Sensor calibration confidence percent,
+                                                  // in range of [0, 100]
+    DrCalibrationStatusMask calibrationStatus;    // Sensor calibration status
+    // location engine type. When the fix. when the type is set to
+    // LOC_ENGINE_SRC_FUSED, the fix is the propagated/aggregated
+    // reports from all engines running on the system (e.g.:
+    // DR/SPE/PPE/VPE). To check which location engine contributes to
+    // the fused output, check for locOutputEngMask.
+    LocOutputEngineType locOutputEngType;
+    // when loc output eng type is set to fused, this field
+    // indicates the set of engines contribute to the fix.
+    PositioningEngineMask locOutputEngMask;
+    // When robust location is enabled, this field
+    // will how well the various input data considered for
+    // navigation solution conform to expectations.
+    // Range: 0 (least conforming) to 1 (most conforming)
+    float conformityIndex;
+    GnssLocationPositionDynamicsExt bodyFrameDataExt;   // Additional Body Frame Dynamics
+    // VRR-based latitude/longitude/altitude
+    LLAInfo llaVRPBased;
+    // VRR-based east, north, and up velocity
+    float enuVelocityVRPBased[3];
+    DrSolutionStatusMask drSolutionStatusMask;
+    // true: altitude is assumed, false: altitude is calculated
+    bool altitudeAssumed;
+    // location session status
+    loc_sess_status sessionStatus;
+} GnssLocationInfoNotification;
+
+typedef struct {
+    uint32_t size;                           // set to sizeof(GnssNiNotification)
+    GnssNiType type;                       // type of NI (Voice, SUPL, Control Plane)
+    GnssNiOptionsMask options;             // bitwise OR of GnssNiOptionsBits
+    uint32_t timeout;                      // time (seconds) to wait for user input
+    GnssNiResponse timeoutResponse;        // the response that should be sent when timeout expires
+    char requestor[GNSS_NI_REQUESTOR_MAX]; // the requestor that is making the request
+    GnssNiEncodingType requestorEncoding;  // the encoding type for requestor
+    char message[GNSS_NI_MESSAGE_ID_MAX];  // the message to show user
+    GnssNiEncodingType messageEncoding;    // the encoding type for message
+    char extras[GNSS_NI_MESSAGE_ID_MAX];
+} GnssNiNotification;
+
+// carrier frequency of the signal tracked
+#define GPS_L1CA_CARRIER_FREQUENCY      (1575420000.0)
+#define GPS_L1C_CARRIER_FREQUENCY       (1575420000.0)
+#define GPS_L2C_L_CARRIER_FREQUENCY     (1227600000.0)
+#define GPS_L5_Q_CARRIER_FREQUENCY      (1176450000.0)
+#define GLONASS_G1_CARRIER_FREQUENCY    (1602000000.0)
+#define GLONASS_G2_CARRIER_FREQUENCY    (1246000000.0)
+#define GALILEO_E1_C_CARRIER_FREQUENCY  (1575420000.0)
+#define GALILEO_E5A_Q_CARRIER_FREQUENCY (1176450000.0)
+#define GALILEO_E5B_Q_CARRIER_FREQUENCY (1207140000.0)
+#define BEIDOU_B1_I_CARRIER_FREQUENCY   (1561098000.0)
+#define BEIDOU_B1C_CARRIER_FREQUENCY    (1575420000.0)
+#define BEIDOU_B2_I_CARRIER_FREQUENCY   (1207140000.0)
+#define BEIDOU_B2A_I_CARRIER_FREQUENCY  (1176450000.0)
+#define BEIDOU_B2A_Q_CARRIER_FREQUENCY  (1176450000.0)
+#define QZSS_L1CA_CARRIER_FREQUENCY     (1575420000.0)
+#define QZSS_L1S_CARRIER_FREQUENCY      (1575420000.0)
+#define QZSS_L2C_L_CARRIER_FREQUENCY    (1227600000.0)
+#define QZSS_L5_Q_CARRIER_FREQUENCY     (1176450000.0)
+#define SBAS_L1_CA_CARRIER_FREQUENCY    (1575420000.0)
+#define NAVIC_L5_CARRIER_FREQUENCY      (1176450000.0)
+
+typedef struct {
+    uint32_t size;       // set to sizeof(GnssSv)
+    // Unique SV Identifier.
+    // SV Range for supported constellation is specified as below:
+    //    - For GPS:     1 to 32
+    //    - For GLONASS: 65 to 96
+    //    - For SBAS:    120 to 158 and 183 to 191
+    //    - For QZSS:    193 to 197
+    //    - For BDS:     201 to 263
+    //    - For GAL:     301 to 336
+    //    - For NAVIC:   401 to 414
+    uint16_t svId;
+    GnssSvType type;   // type of SV (GPS, SBAS, GLONASS, QZSS, BEIDOU, GALILEO, NAVIC)
+    float cN0Dbhz;     // signal strength
+    float elevation;   // elevation of SV (in degrees)
+    float azimuth;     // azimuth of SV (in degrees)
+    GnssSvOptionsMask gnssSvOptionsMask; // Bitwise OR of GnssSvOptionsBits
+    float carrierFrequencyHz; // carrier frequency of the signal tracked
+    GnssSignalTypeMask gnssSignalTypeMask; // Specifies GNSS signal type
+    double basebandCarrierToNoiseDbHz; // baseband signal strength
+    uint16_t  gloFrequency; // GLONASS Frequency channel number
+} GnssSv;
+
+struct GnssConfigSetAssistanceServer {
+    uint32_t size;             // set to sizeof(GnssConfigSetAssistanceServer)
+    GnssAssistanceType type; // SUPL or C2K
+    const char* hostName;    // null terminated string
+    uint32_t port;           // port of server
+
+    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 {
+    // set to sizeof(GnssMeasurementsData)
+    uint32_t size;
+    // bitwise OR of GnssMeasurementsDataFlagsBits
+    GnssMeasurementsDataFlagsMask flags;
+    // Unique SV Identifier
+    // For SV Range of supported constellation,
+    // please refer to the comment section of svId in GnssSv.
+    int16_t svId;
+    GnssSvType svType;
+    double timeOffsetNs;
+    GnssMeasurementsStateMask stateMask;       // bitwise OR of GnssMeasurementsStateBits
+    int64_t receivedSvTimeNs;
+    int64_t receivedSvTimeUncertaintyNs;
+    double carrierToNoiseDbHz;
+    double pseudorangeRateMps;
+    double pseudorangeRateUncertaintyMps;
+    GnssMeasurementsAdrStateMask adrStateMask; // bitwise OR of GnssMeasurementsAdrStateBits
+    double adrMeters;
+    double adrUncertaintyMeters;
+    float carrierFrequencyHz;
+    int64_t carrierCycles;
+    double carrierPhase;
+    double carrierPhaseUncertainty;
+    GnssMeasurementsMultipathIndicator multipathIndicator;
+    double signalToNoiseRatioDb;
+    double agcLevelDb;
+    GnssMeasurementsCodeType codeType;
+    char otherCodeTypeName[GNSS_MAX_NAME_LENGTH];
+    double basebandCarrierToNoiseDbHz;
+    GnssSignalTypeMask gnssSignalType;
+    double fullInterSignalBiasNs;
+    double fullInterSignalBiasUncertaintyNs;
+    double satelliteInterSignalBiasNs;
+    double satelliteInterSignalBiasUncertaintyNs;
+    int16_t gloFrequency;
+    uint8_t cycleSlipCount;
+} GnssMeasurementsData;
+
+typedef struct {
+    GnssSvType svType;
+    float carrierFrequencyHz;
+    GnssMeasurementsCodeType codeType;
+    char otherCodeTypeName[GNSS_MAX_NAME_LENGTH];
+} GnssMeasurementsSignalType;
+
+typedef struct {
+    uint32_t size;                          // set to sizeof(GnssReflectingPlane)
+    double latitudeDegrees;
+    double longitudeDegrees;
+    double altitudeMeters;
+    double azimuthDegrees;
+} GnssReflectingPlane;
+
+typedef struct {
+    uint32_t size;                          // set to sizeof(GnssSingleSatCorrection)
+    GnssSingleSatCorrectionMask flags;
+    GnssSvType svType;
+    uint16_t svId;
+    float carrierFrequencyHz;
+    float probSatIsLos;
+    float excessPathLengthMeters;
+    float excessPathLengthUncertaintyMeters;
+    GnssReflectingPlane reflectingPlane;
+} GnssSingleSatCorrection;
+
+typedef struct {
+    uint32_t size;                          // set to sizeof(GnssMeasurementCorrections)
+    double latitudeDegrees;
+    double longitudeDegrees;
+    double altitudeMeters;
+    double horizontalPositionUncertaintyMeters;
+    double verticalPositionUncertaintyMeters;
+    uint64_t toaGpsNanosecondsOfWeek;
+    std::vector<GnssSingleSatCorrection> satCorrections;
+    bool hasEnvironmentBearing;
+    float environmentBearingDegrees;
+    float environmentBearingUncertaintyDegrees;
+} GnssMeasurementCorrections;
+
+typedef struct {
+    uint32_t size;                          // set to sizeof(GnssMeasurementsClock)
+    GnssMeasurementsClockFlagsMask flags; // bitwise OR of GnssMeasurementsClockFlagsBits
+    int16_t leapSecond;
+    int64_t timeNs;
+    double timeUncertaintyNs;
+    int64_t fullBiasNs;
+    double biasNs;
+    double biasUncertaintyNs;
+    double driftNsps;
+    double driftUncertaintyNsps;
+    uint32_t hwClockDiscontinuityCount;
+    GnssMeasurementsSignalType referenceSignalTypeForIsb;
+    uint64_t elapsedRealTime;    // in ns
+    uint64_t elapsedRealTimeUnc; // in ns
+} GnssMeasurementsClock;
+
+typedef struct {
+    uint32_t size;                 // set to sizeof(GnssSvNotification)
+    uint32_t count;                // number of SVs in the GnssSv array
+    bool gnssSignalTypeMaskValid;
+    GnssSv gnssSvs[GNSS_SV_MAX]; // information on a number of SVs
+} GnssSvNotification;
+
+typedef struct {
+    uint32_t size;         // set to sizeof(GnssNmeaNotification)
+    uint64_t timestamp;  // timestamp
+    const char* nmea;    // nmea text
+    uint32_t length;       // length of the nmea text
+} GnssNmeaNotification;
+
+typedef struct {
+    uint32_t size;                 // set to sizeof(GnssDataNotification)
+    GnssDataMask  gnssDataMask[GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES];  // bitwise OR of GnssDataBits
+    double        jammerInd[GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES];     // Jammer Indication
+    double        agc[GNSS_LOC_MAX_NUMBER_OF_SIGNAL_TYPES];           // Automatic gain control
+} GnssDataNotification;
+
+typedef struct {
+    uint32_t size;         // set to sizeof(GnssMeasurementsNotification)
+    uint32_t count;        // number of items in GnssMeasurements array
+    GnssMeasurementsData measurements[GNSS_MEASUREMENTS_MAX];
+    GnssMeasurementsClock clock; // clock
+} GnssMeasurementsNotification;
+
+typedef uint32_t GnssSvId;
+
+struct GnssSvIdSource{
+    uint32_t size;              // set to sizeof(GnssSvIdSource)
+    GnssSvType constellation;   // constellation for the sv to blacklist
+    GnssSvId svId;              // Unique SV Identifier,
+                                // For SV Range of supported constellation,
+                                // please refer to the comment section of svId in GnssSv.
+};
+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)
+struct GnssSvIdConfig {
+    uint32_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;
+
+    // SBAS - SV 120 to 158, maps to 0 to 38
+    //        SV 183 to 191, maps to 39 to 47
+#define GNSS_SV_CONFIG_SBAS_INITIAL_SV_ID     120
+#define GNSS_SV_CONFIG_SBAS_INITIAL_SV_LENGTH 39
+#define GNSS_SV_CONFIG_SBAS_INITIAL2_SV_ID    183
+    uint64_t sbasBlacklistSvMask;
+
+    //Navic - SV 401 maps to bit 0
+#define GNSS_SV_CONFIG_NAVIC_INITIAL_SV_ID 401
+    uint64_t navicBlacklistSvMask;
+
+    inline bool equals(const GnssSvIdConfig& inConfig) {
+        if ((inConfig.size == size) &&
+                (inConfig.gloBlacklistSvMask == gloBlacklistSvMask) &&
+                (inConfig.bdsBlacklistSvMask == bdsBlacklistSvMask) &&
+                (inConfig.qzssBlacklistSvMask == qzssBlacklistSvMask) &&
+                (inConfig.galBlacklistSvMask == galBlacklistSvMask) &&
+                (inConfig.sbasBlacklistSvMask == sbasBlacklistSvMask) &&
+                (inConfig.navicBlacklistSvMask == navicBlacklistSvMask)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+};
+
+// Specify the valid mask for robust location configure
+// defined in GnssConfigRobustLocation.
+enum GnssConfigRobustLocationValidMask {
+    // GnssConfigRobustLocation has valid enabled field.
+    GNSS_CONFIG_ROBUST_LOCATION_ENABLED_VALID_BIT          = (1<<0),
+    // GnssConfigRobustLocation has valid enabledForE911 field.
+    GNSS_CONFIG_ROBUST_LOCATION_ENABLED_FOR_E911_VALID_BIT = (1<<1),
+    // GnssConfigRobustLocation has valid version field.
+    GNSS_CONFIG_ROBUST_LOCATION_VERSION_VALID_BIT          = (1<<2),
+};
+
+struct GnssConfigRobustLocationVersion {
+    // Major version number
+    uint8_t major;
+    // Minor version number
+    uint16_t minor;
+    inline bool equals(const GnssConfigRobustLocationVersion& version) const {
+        return (version.major == major && version.minor == minor);
+    }
+};
+
+// specify the robust location configuration used by modem GNSS engine
+struct GnssConfigRobustLocation {
+   GnssConfigRobustLocationValidMask validMask;
+   bool enabled;
+   bool enabledForE911;
+   GnssConfigRobustLocationVersion version;
+
+   inline bool equals(const GnssConfigRobustLocation& config) const {
+        if (config.validMask == validMask &&
+            config.enabled == enabled &&
+            config.enabledForE911 == enabledForE911 &&
+            config.version.equals(version)) {
+            return true;
+        }
+        return false;
+    }
+};
+
+/* Mask indicating enabled or disabled constellations and
+   secondary frequency.*/
+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),
+    GNSS_SV_TYPES_MASK_NAVIC_BIT = (1<<4),
+    GNSS_SV_TYPES_MASK_GPS_BIT   = (1<<5),
+} GnssSvTypesMaskBits;
+#define GNSS_SV_TYPES_MASK_ALL \
+    (GNSS_SV_TYPES_MASK_GPS_BIT|GNSS_SV_TYPES_MASK_GLO_BIT|GNSS_SV_TYPES_MASK_BDS_BIT|\
+     GNSS_SV_TYPES_MASK_QZSS_BIT|GNSS_SV_TYPES_MASK_GAL_BIT|GNSS_SV_TYPES_MASK_NAVIC_BIT)
+
+/* This SV Type config is injected directly to GNSS Adapter
+ * bypassing Location API */
+struct GnssSvTypeConfig{
+    uint32_t size; // set to sizeof(GnssSvTypeConfig)
+    // Enabled Constellations
+    GnssSvTypesMask enabledSvTypesMask;
+    // Disabled Constellations
+    GnssSvTypesMask blacklistedSvTypesMask;
+
+    inline bool equals (const GnssSvTypeConfig& inConfig) const {
+        return ((inConfig.size == size) &&
+                (inConfig.enabledSvTypesMask == enabledSvTypesMask) &&
+                (inConfig.blacklistedSvTypesMask == blacklistedSvTypesMask));
+    }
+};
+
+struct GnssConfig{
+    uint32_t size;  // set to sizeof(GnssConfig)
+    GnssConfigFlagsMask flags; // bitwise OR of GnssConfigFlagsBits to mark which params are valid
+    GnssConfigGpsLock gpsLock;
+    GnssConfigSuplVersion suplVersion;
+    GnssConfigSetAssistanceServer assistanceServer;
+    GnssConfigLppProfileMask lppProfileMask;
+    GnssConfigLppeControlPlaneMask lppeControlPlaneMask;
+    GnssConfigLppeUserPlaneMask lppeUserPlaneMask;
+    GnssConfigAGlonassPositionProtocolMask aGlonassPositionProtocolMask;
+    GnssConfigEmergencyPdnForEmergencySupl emergencyPdnForEmergencySupl;
+    GnssConfigSuplEmergencyServices suplEmergencyServices;
+    GnssConfigSuplModeMask suplModeMask; //bitwise OR of GnssConfigSuplModeBits
+    std::vector<GnssSvIdSource> blacklistedSvIds;
+    uint32_t emergencyExtensionSeconds;
+    GnssConfigRobustLocation robustLocationConfig;
+    uint16_t minGpsWeek;
+    uint8_t minSvElevation;
+    GnssSvTypeConfig secondaryBandConfig;
+
+    inline bool equals(const GnssConfig& config) {
+        if (flags == config.flags &&
+                gpsLock == config.gpsLock &&
+                suplVersion == config.suplVersion &&
+                assistanceServer.equals(config.assistanceServer) &&
+                lppProfileMask == config.lppProfileMask &&
+                lppeControlPlaneMask == config.lppeControlPlaneMask &&
+                lppeUserPlaneMask == config.lppeUserPlaneMask &&
+                aGlonassPositionProtocolMask == config.aGlonassPositionProtocolMask &&
+                emergencyPdnForEmergencySupl == config.emergencyPdnForEmergencySupl &&
+                suplEmergencyServices == config.suplEmergencyServices &&
+                suplModeMask == config.suplModeMask  &&
+                blacklistedSvIds == config.blacklistedSvIds &&
+                emergencyExtensionSeconds == config.emergencyExtensionSeconds &&
+                robustLocationConfig.equals(config.robustLocationConfig) &&
+                minGpsWeek == config.minGpsWeek &&
+                minSvElevation == config.minSvElevation &&
+                secondaryBandConfig.equals(config.secondaryBandConfig)) {
+            return true;
+        }
+        return false;
+    }
+};
+
+typedef struct {
+    uint32_t size;                        // set to sizeof
+    bool                                mValid;
+    Location                            mLocation;
+    double                              verticalAccuracyMeters;
+    double                              speedAccuracyMetersPerSecond;
+    double                              bearingAccuracyDegrees;
+    timespec                            mUtcReported;
+} GnssDebugLocation;
+
+typedef struct {
+    uint32_t size;                        // set to sizeof
+    bool                                mValid;
+    int64_t                             timeEstimate;
+    float                               timeUncertaintyNs;
+    float                               frequencyUncertaintyNsPerSec;
+} GnssDebugTime;
+
+typedef struct {
+    // set to sizeof
+    uint32_t size;
+    // Unique SV Identifier
+    // For SV Range of supported constellation,
+    // please refer to the comment section of svId in GnssSv.
+    uint32_t                            svid;
+    GnssSvType                          constellation;
+    GnssEphemerisType                   mEphemerisType;
+    GnssEphemerisSource                 mEphemerisSource;
+    GnssEphemerisHealth                 mEphemerisHealth;
+    float                               ephemerisAgeSeconds;
+    bool                                serverPredictionIsAvailable;
+    float                               serverPredictionAgeSeconds;
+} GnssDebugSatelliteInfo;
+
+typedef struct {
+    uint32_t size;                        // set to sizeof
+    GnssDebugLocation                   mLocation;
+    GnssDebugTime                       mTime;
+    std::vector<GnssDebugSatelliteInfo> mSatelliteInfo;
+} GnssDebugReport;
+
+typedef uint32_t LeapSecondSysInfoMask;
+typedef enum {
+    // current leap second info is available. This info will only
+    // be available if the leap second change info is not available.
+    //
+    // If leap second change info is avaiable, to figure out
+    // the current leap second info, compare current gps time with
+    // the gps timestamp of leap second change to know whether to choose
+    // leapSecondBefore or leapSecondAfter as current leap second.
+    LEAP_SECOND_SYS_INFO_CURRENT_LEAP_SECONDS_BIT = (1ULL << 0),
+    // the last known leap change event is available.
+    // The info can be available on two scenario:
+    // 1: this leap second change event has been scheduled and yet to happen
+    // 2: this leap second change event has already happened and next
+    //    leap second change event has not yet been scheduled.
+    LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT = (1ULL << 1),
+} LeapSecondSysInfoDataBits;
+
+struct LeapSecondChangeInfo {
+    // GPS timestamp that corrresponds to the last known
+    // leap second change event.
+    //
+    // The info can be available on two scenario:
+    // 1: this leap second change event has been scheduled and yet to happen
+    // 2: this leap second change event has already happened and next
+    //    leap second change event has not yet been scheduled.
+    GnssSystemTimeStructType gpsTimestampLsChange;
+    // Number of leap seconds prior to the leap second change event
+    // that corresponds to the timestamp at gpsTimestampLsChange.
+    uint8_t leapSecondsBeforeChange;
+    // Number of leap seconds after the leap second change event
+    // that corresponds to the timestamp at gpsTimestampLsChange.
+    uint8_t leapSecondsAfterChange;
+};
+
+struct LeapSecondSystemInfo {
+    LeapSecondSysInfoMask leapSecondInfoMask;
+    uint8_t               leapSecondCurrent;
+    LeapSecondChangeInfo  leapSecondChangeInfo;
+};
+
+typedef uint32_t LocationSystemInfoMask;
+typedef enum {
+    // contains current leap second or leap second change info
+    LOCATION_SYS_INFO_LEAP_SECOND = (1ULL << 0),
+} LocationSystemInfoDataBits;
+
+struct LocationSystemInfo {
+    LocationSystemInfoMask systemInfoMask;
+    LeapSecondSystemInfo   leapSecondSysInfo;
+};
+
+// Specify the set of terrestrial technologies
+enum TerrestrialTechMask {
+    TERRESTRIAL_TECH_GTP_WWAN = 1 << 0,
+};
+
+// Specify parameters related to lever arm
+struct LeverArmParams {
+    // Offset along the vehicle forward axis
+    float forwardOffsetMeters;
+    // Offset along the vehicle starboard axis
+    float sidewaysOffsetMeters;
+    // Offset along the vehicle up axis
+    float upOffsetMeters;
+};
+
+typedef uint32_t LeverArmTypeMask;
+
+enum LeverArmTypeBits {
+    // Lever arm regarding the VRP (Vehicle Reference Point) w.r.t
+    // the origin (at the GPS Antenna)
+    LEVER_ARM_TYPE_GNSS_TO_VRP_BIT = (1<<0),
+    // Lever arm regarding GNSS Antenna w.r.t the origin at the IMU
+    // e.g.: inertial measurement unit for DR (dead reckoning
+    // engine)
+    LEVER_ARM_TYPE_DR_IMU_TO_GNSS_BIT = (1<<1),
+    // Lever arm regarding GNSS Antenna w.r.t the origin at the
+    // IMU (inertial measurement unit) for VEPP (vision enhanced
+    // precise positioning engine)
+    LEVER_ARM_TYPE_VEPP_IMU_TO_GNSS_BIT = (1<<2)
+};
+
+struct LeverArmConfigInfo {
+    // Valid mask for the types of lever arm parameters provided
+    LeverArmTypeMask leverArmValidMask;
+    // Lever arm regarding the VRP (Vehicle Reference Point) w.r.t the origin
+    // (at the GPS Antenna)
+    LeverArmParams   gnssToVRP;
+    // Lever arm parameters regarding GNSS Antenna w.r.t the origin at the IMU
+    // (inertial measurement unit) for DR (dead reckoning engine)
+    LeverArmParams   drImuToGnss;
+    // Lever arm regarding GNSS Antenna w.r.t the origin at the IMU
+    // (inertial measurement unit) for VEPP (vision enhanced precise position engine)
+    LeverArmParams   veppImuToGnss;
+};
+
+// Specify vehicle body-to-Sensor mount parameters to be used
+// by dead reckoning positioning engine.
+struct BodyToSensorMountParams {
+    // The misalignment of the sensor board along the
+    // horizontal plane of the vehicle chassis measured looking
+    // from the vehicle to forward direction. In unit of degree.
+    float rollOffset;
+    // The misalignment along the horizontal plane of the vehicle
+    // chassis measured looking from the vehicle to the right
+    // side. Positive pitch indicates vehicle is inclined such
+    // that forward wheels are at higher elevation than rear
+    // wheels. In unit of degree.
+    float yawOffset;
+    // The angle between the vehicle forward direction and the
+    // sensor axis as seen from the top of the vehicle, and
+    // measured in counterclockwise direction. In unit of degree.
+    float pitchOffset;
+    // Single uncertainty number that may be the largest of the
+    // roll, pitch and yaw offset uncertainties.
+    float offsetUnc;
+};
+
+typedef uint64_t DeadReckoningEngineConfigValidMask;
+// Specify the valid mask for the configuration paramters of
+// dead reckoning position engine.
+enum DeadReckoningEngineConfigValidBit {
+    // DeadReckoningEngineConfig has valid
+    // DeadReckoningEngineConfig::DeadReckoningEngineConfig.
+    BODY_TO_SENSOR_MOUNT_PARAMS_BIT    = (1<<0),
+    // DeadReckoningEngineConfig has valid
+    //  DeadReckoningEngineConfig::vehicleSpeedScaleFactor.
+    VEHICLE_SPEED_SCALE_FACTOR_BIT     = (1<<1),
+    // DeadReckoningEngineConfig has valid
+    //  DeadReckoningEngineConfig::vehicleSpeedScaleFactorUnc.
+    VEHICLE_SPEED_SCALE_FACTOR_UNC_BIT = (1<<2),
+    // DeadReckoningEngineConfig has valid
+    //  DeadReckoningEngineConfig::gyroScaleFactor.
+    GYRO_SCALE_FACTOR_BIT              = (1<<3),
+    // DeadReckoningEngineConfig has valid
+    // DeadReckoningEngineConfig::gyroScaleFactorUnc.
+    GYRO_SCALE_FACTOR_UNC_BIT          = (1<<4),
+};
+
+// Specify the configuration parameters for the dead reckoning
+//  position engine
+struct DeadReckoningEngineConfig{
+    // Specify the valid fields in the config.
+    DeadReckoningEngineConfigValidMask validMask;
+    // Body to sensor mount parameters for use by dead reckoning
+    //  positioning engine
+    BodyToSensorMountParams bodyToSensorMountParams;
+
+    // Vehicle Speed Scale Factor configuration input for the dead
+    // reckoning positioning engine. The multiplicative scale
+    // factor is applied to received Vehicle Speed value (in m/s)
+    // to obtain the true Vehicle Speed.
+    //
+    // Range is [0.9 to 1.1].
+    //
+    // Note: The scale factor is specific to a given vehicle
+    // make & model.
+    float vehicleSpeedScaleFactor;
+    // Vehicle Speed Scale Factor Uncertainty (68% confidence)
+    // configuration input for the dead reckoning positioning
+    // engine.
+    //
+    // Range is [0.0 to 0.1].
+    //
+    // Note: The scale factor unc is specific to a given vehicle
+    // make & model.
+    float vehicleSpeedScaleFactorUnc;
+
+    // Gyroscope Scale Factor configuration input for the dead
+    // reckoning positioning engine. The multiplicative scale
+    // factor is applied to received gyroscope value to obtain the
+    // true value.
+    //
+    // Range is [0.9 to 1.1].
+    //
+    // Note: The scale factor is specific to the Gyroscope sensor
+    // and typically derived from either sensor data-sheet or
+    // from actual calibration.
+    float gyroScaleFactor;
+
+    // Gyroscope Scale Factor uncertainty (68% confidence)
+    // configuration input for the dead reckoning positioning
+    // engine.
+    //
+    // Range is [0.0 to 0.1].
+    // engine.
+    //
+    // Note: The scale factor unc is specific to the make & model
+    // of Gyroscope sensor and typically derived from either
+    // sensor data-sheet or from actual calibration.
+    float gyroScaleFactorUnc;
+};
+
+/* Provides the capabilities of the system
+   capabilities callback is called once soon after createInstance is called */
+typedef std::function<void(
+    LocationCapabilitiesMask capabilitiesMask // bitwise OR of LocationCapabilitiesBits
+)> capabilitiesCallback;
+
+/* Used by tracking, batching, and miscellanous APIs
+   responseCallback is called for every Tracking, Batching API, and Miscellanous API */
+typedef std::function<void(
+    LocationError err, // if not SUCCESS, then id is not valid
+    uint32_t id        // id to be associated to the request
+)> responseCallback;
+
+/* Used by APIs that gets more than one LocationError in it's response
+   collectiveResponseCallback is called for every geofence API call.
+   ids array and LocationError array are only valid until collectiveResponseCallback returns. */
+typedef std::function<void(
+    uint32_t count, // number of locations in arrays
+    LocationError* errs, // array of LocationError associated to the request
+    uint32_t* ids // array of ids to be associated to the request
+)> collectiveResponseCallback;
+
+/* Used for startTracking API, optional can be NULL
+   trackingCallback is called when delivering a location in a tracking session
+   broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+    Location location
+)> trackingCallback;
+
+/* Used for startBatching API, optional can be NULL
+   batchingCallback is called when delivering locations in a batching session.
+   broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+    uint32_t count,      // number of locations in array
+    Location* location, // array of locations
+    BatchingOptions batchingOptions // Batching options
+)> batchingCallback;
+
+typedef std::function<void(
+    BatchingStatusInfo batchingStatus, // batch status
+    std::list<uint32_t> & listOfCompletedTrips
+)> batchingStatusCallback;
+
+/* Gives GNSS Location information, optional can be NULL
+    gnssLocationInfoCallback is called only during a tracking session
+    broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+    GnssLocationInfoNotification gnssLocationInfoNotification
+)> gnssLocationInfoCallback;
+
+/* Gives default combined location information from all engines and
+   location information individually from selected engines.
+   This callback is only used when there are multiple engines
+   running in the system.
+
+   optional can be NULL
+
+   engineLocationsInfoCallback is called only during a tracking session
+   broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+    uint32_t count,
+    GnssLocationInfoNotification* engineLocationInfoNotification
+)> engineLocationsInfoCallback;
+
+/* Used for addGeofences API, optional can be NULL
+   geofenceBreachCallback is called when any number of geofences have a state change */
+typedef std::function<void(
+    GeofenceBreachNotification geofenceBreachNotification
+)> geofenceBreachCallback;
+
+/* Used for addGeofences API, optional can be NULL
+       geofenceStatusCallback is called when any number of geofences have a status change */
+typedef std::function<void(
+    GeofenceStatusNotification geofenceStatusNotification
+)> geofenceStatusCallback;
+
+/* Network Initiated request, optional can be NULL
+   This callback should be responded to by calling gnssNiResponse */
+typedef std::function<void(
+    uint32_t id, // id that should be used to respond by calling gnssNiResponse
+    GnssNiNotification gnssNiNotification
+)> gnssNiCallback;
+
+/* Gives GNSS SV information, optional can be NULL
+    gnssSvCallback is called only during a tracking session
+    broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+    GnssSvNotification gnssSvNotification
+)> gnssSvCallback;
+
+/* Gives GNSS NMEA data, optional can be NULL
+    gnssNmeaCallback is called only during a tracking session
+    broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+    GnssNmeaNotification gnssNmeaNotification
+)> gnssNmeaCallback;
+
+/* Gives GNSS data, optional can be NULL
+    gnssDataCallback is called only during a tracking session
+    broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+    GnssDataNotification gnssDataNotification
+)> gnssDataCallback;
+
+/* Gives GNSS Measurements information, optional can be NULL
+    gnssMeasurementsCallback is called only during a tracking session
+    broadcasted to all clients, no matter if a session has started by client */
+typedef std::function<void(
+    GnssMeasurementsNotification gnssMeasurementsNotification
+)> gnssMeasurementsCallback;
+
+/* Provides the current GNSS configuration to the client */
+typedef std::function<void(
+    uint32_t session_id,
+    const GnssConfig& config
+)> gnssConfigCallback;
+
+/* LocationSystemInfoCb is for receiving rare occuring location
+   system information update. optional, can be NULL.
+*/
+typedef std::function<void(
+    LocationSystemInfo locationSystemInfo
+)> locationSystemInfoCallback;
+
+typedef std::function<void(
+)> locationApiDestroyCompleteCallback;
+
+typedef uint16_t LocationAdapterTypeMask;
+typedef enum {
+    LOCATION_ADAPTER_GNSS_TYPE_BIT      = (1<<0), // adapter type is GNSS
+    LOCATION_ADAPTER_BATCHING_TYPE_BIT  = (1<<1), // adapter type is BATCHING
+    LOCATION_ADAPTER_GEOFENCE_TYPE_BIT  = (1<<2)  // adapter type is geo fence
+} LocationAdapterTypeBits;
+
+typedef struct {
+    uint32_t size; // set to sizeof(LocationCallbacks)
+    capabilitiesCallback capabilitiesCb;             // mandatory
+    responseCallback responseCb;                     // mandatory
+    collectiveResponseCallback collectiveResponseCb; // mandatory
+    trackingCallback trackingCb;                     // optional
+    batchingCallback batchingCb;                     // optional
+    geofenceBreachCallback geofenceBreachCb;         // optional
+    geofenceStatusCallback geofenceStatusCb;         // optional
+    gnssLocationInfoCallback gnssLocationInfoCb;     // optional
+    gnssNiCallback gnssNiCb;                         // optional
+    gnssSvCallback gnssSvCb;                         // optional
+    gnssNmeaCallback gnssNmeaCb;                     // optional
+    gnssDataCallback gnssDataCb;                     // optional
+    gnssMeasurementsCallback gnssMeasurementsCb;     // optional
+    batchingStatusCallback batchingStatusCb;         // optional
+    locationSystemInfoCallback locationSystemInfoCb; // optional
+    engineLocationsInfoCallback engineLocationsInfoCb;     // optional
+} LocationCallbacks;
+
+typedef struct {
+    uint32_t size;                        // set to sizeof
+    double x;
+    double xUncertainty;
+    double y;
+    double yUncertainty;
+    double z;
+    double zUncertainty;
+} GnssCoordinate;
+
+typedef struct {
+    uint32_t size;                        // set to sizeof
+    double carrierFrequencyMHz;
+    GnssCoordinate phaseCenterOffsetCoordinateMillimeters;
+    std::vector<std::vector<double>> phaseCenterVariationCorrectionMillimeters;
+    std::vector<std::vector<double>> phaseCenterVariationCorrectionUncertaintyMillimeters;
+    std::vector<std::vector<double>> signalGainCorrectionDbi;
+    std::vector<std::vector<double>> signalGainCorrectionUncertaintyDbi;
+} GnssAntennaInformation;
+
+typedef struct {
+    uint32_t size;                        // set to sizeof
+    bool requiresNmeaLocation;
+    std::string hostNameOrIp;    // null terminated string
+    std::string mountPoint;      // null terminated string
+    std::string username;        // null terminated string
+    std::string password;        // null terminated string
+    uint32_t port;
+    bool useSSL;
+} GnssNtripConnectionParams;
+
+typedef struct {
+    uint64_t meQtimer1;
+    uint64_t meQtimer2;
+    uint64_t meQtimer3;
+    uint64_t peQtimer1;
+    uint64_t peQtimer2;
+    uint64_t peQtimer3;
+    uint64_t smQtimer1;
+    uint64_t smQtimer2;
+    uint64_t smQtimer3;
+    uint64_t locMwQtimer;
+    uint64_t hlosQtimer1;
+    uint64_t hlosQtimer2;
+    uint64_t hlosQtimer3;
+    uint64_t hlosQtimer4;
+    uint64_t hlosQtimer5;
+} GnssLatencyInfo;
+
+#endif /* LOCATIONDATATYPES_H */
diff --git a/gps/location/Makefile.am b/gps/location/Makefile.am
new file mode 100644
index 0000000..6a5a750
--- /dev/null
+++ b/gps/location/Makefile.am
@@ -0,0 +1,44 @@
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CFLAGS = \
+     -I./ \
+     -I../utils \
+     $(LOCPLA_CFLAGS) \
+     $(GPSUTILS_CFLAGS) \
+     -std=c++11
+
+liblocation_api_la_SOURCES = \
+    LocationAPI.cpp \
+    LocationAPIClientBase.cpp
+
+if USE_EXTERNAL_AP
+AM_CFLAGS += -DFEATURE_EXTERNAL_AP
+endif
+
+if USE_GLIB
+liblocation_api_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+liblocation_api_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
+liblocation_api_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+liblocation_api_la_CFLAGS = $(AM_CFLAGS)
+liblocation_api_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0
+liblocation_api_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+liblocation_api_la_LIBADD = -lstdc++ -ldl $(GPSUTILS_LIBS)
+
+library_include_HEADERS = \
+    LocationAPI.h \
+    LocationAPIClientBase.h \
+    location_interface.h \
+    LocationDataTypes.h \
+    ILocationAPI.h
+
+#Create and Install libraries
+lib_LTLIBRARIES = liblocation_api.la
+
+library_includedir = $(pkgincludedir)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = location-api.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/gps/location/configure.ac b/gps/location/configure.ac
new file mode 100644
index 0000000..f8376f5
--- /dev/null
+++ b/gps/location/configure.ac
@@ -0,0 +1,95 @@
+# configure.ac -- Autoconf script for gps location-api-iface
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps location-api-iface package version 1.0.0
+AC_INIT([location-api-iface],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([location-api.pc.in])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+# Checks for libraries.
+PKG_CHECK_MODULES([GPSUTILS], [gps-utils])
+AC_SUBST([GPSUTILS_CFLAGS])
+AC_SUBST([GPSUTILS_LIBS])
+
+AC_ARG_WITH([core_includes],
+      AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
+         [Specify the location of the core headers]),
+      [core_incdir=$withval],
+      with_core_includes=no)
+
+if test "x$with_core_includes" != "xno"; then
+   CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
+fi
+
+AC_ARG_WITH([locpla_includes],
+      AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+        [Specify the path to locpla-includes in loc-pla_git.bb]),
+      [locpla_incdir=$withval],
+      with_locpla_includes=no)
+
+if test "x${with_locpla_includes}" != "xno"; then
+   AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_SUBST([CPPFLAGS])
+
+AC_ARG_WITH([glib],
+      AC_HELP_STRING([--with-glib],
+         [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+        AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+        PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GThread >= 2.16 is required))
+        PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GLib >= 2.16 is required))
+        GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+        GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+        AC_SUBST(GLIB_CFLAGS)
+        AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+# External AP
+AC_ARG_WITH([external_ap],
+    AC_HELP_STRING([--with-external_ap=@<:@dir@:>@],
+        [Using External Application Processor]),
+    [],
+    with_external_ap=no)
+
+if test "x$with_external_ap" != "xno"; then
+    CPPFLAGS="${CPPFLAGS} -DFEATURE_EXTERNAL_AP"
+fi
+
+AM_CONDITIONAL(USE_EXTERNAL_AP, test "x${with_external_ap}" = "xyes")
+
+AC_CONFIG_FILES([ \
+        Makefile \
+        location-api.pc \
+        ])
+
+AC_OUTPUT
diff --git a/gps/location/location-api.pc.in b/gps/location/location-api.pc.in
new file mode 100644
index 0000000..c7b146a
--- /dev/null
+++ b/gps/location/location-api.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: location-api
+Description: Location API
+Version: @VERSION
+Libs: -L${libdir} -llocation_api
+Cflags: -I${includedir}/location-api
diff --git a/gps/location/location_interface.h b/gps/location/location_interface.h
new file mode 100644
index 0000000..69d4f0c
--- /dev/null
+++ b/gps/location/location_interface.h
@@ -0,0 +1,144 @@
+/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LOCATION_INTERFACE_H
+#define LOCATION_INTERFACE_H
+
+#include <LocationAPI.h>
+#include <gps_extended_c.h>
+#include <functional>
+
+/* Used for callback to deliver GNSS energy consumed */
+/** @fn
+    @brief Used by query API that retrieves energy consumed by
+           modem GNSS engine.
+
+    @param gnssEnergyConsumedFromFirstBoot:
+            Energy consumed by the GNSS engine since the first bootup
+            in units of 0.1 milli watt seconds.
+            A value of 0xffffffffffffffff indicates an invalid reading.
+*/
+typedef std::function<void(
+    uint64_t gnssEnergyConsumedFromFirstBoot
+)> GnssEnergyConsumedCallback;
+
+typedef void (*removeClientCompleteCallback)(LocationAPI* client);
+
+struct GnssInterface {
+    size_t size;
+    void (*initialize)(void);
+    void (*deinitialize)(void);
+    void (*addClient)(LocationAPI* client, const LocationCallbacks& callbacks);
+    void (*removeClient)(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+    void (*requestCapabilities)(LocationAPI* client);
+    uint32_t (*startTracking)(LocationAPI* client, TrackingOptions&);
+    void (*updateTrackingOptions)(LocationAPI* client, uint32_t id, TrackingOptions&);
+    void (*stopTracking)(LocationAPI* client, uint32_t id);
+    void (*gnssNiResponse)(LocationAPI* client, uint32_t id, GnssNiResponse response);
+    void (*setControlCallbacks)(LocationControlCallbacks& controlCallbacks);
+    uint32_t (*enable)(LocationTechnologyType techType);
+    void (*disable)(uint32_t id);
+    uint32_t* (*gnssUpdateConfig)(const 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);
+    void (*injectTime)(int64_t time, int64_t timeReference, int32_t uncertainty);
+    void (*agpsInit)(const AgpsCbInfo& cbInfo);
+    void (*agpsDataConnOpen)(AGpsExtType agpsType, const char* apnName, int apnLen, int ipType);
+    void (*agpsDataConnClosed)(AGpsExtType agpsType);
+    void (*agpsDataConnFailed)(AGpsExtType agpsType);
+    void (*getDebugReport)(GnssDebugReport& report);
+    void (*updateConnectionStatus)(bool connected, int8_t type, bool roaming,
+                                   NetworkHandle networkHandle, std::string& apn);
+    void (*odcpiInit)(const OdcpiRequestCallback& callback, OdcpiPrioritytype priority);
+    void (*odcpiInject)(const Location& location);
+    void (*blockCPI)(double latitude, double longitude, float accuracy,
+                     int blockDurationMsec, double latLonDiffThreshold);
+    void (*getGnssEnergyConsumed)(GnssEnergyConsumedCallback energyConsumedCb);
+    void (*enableNfwLocationAccess)(bool enable);
+    void (*nfwInit)(const NfwCbInfo& cbInfo);
+    void (*getPowerStateChanges)(std::function<void(bool)> powerStateCb);
+    void (*injectLocationExt)(const GnssLocationInfoNotification &locationInfo);
+    void (*updateBatteryStatus)(bool charging);
+    void (*updateSystemPowerState)(PowerStateType systemPowerState);
+    uint32_t (*setConstrainedTunc) (bool enable, float tuncConstraint, uint32_t energyBudget);
+    uint32_t (*setPositionAssistedClockEstimator) (bool enable);
+    uint32_t (*gnssUpdateSvConfig)(const GnssSvTypeConfig& constellationEnablementConfig,
+                                   const GnssSvIdConfig&   blacklistSvConfig);
+    uint32_t (*configLeverArm)(const LeverArmConfigInfo& configInfo);
+    bool (*measCorrInit)(const measCorrSetCapabilitiesCb setCapabilitiesCb);
+    bool (*measCorrSetCorrections)(const GnssMeasurementCorrections gnssMeasCorr);
+    void (*measCorrClose)();
+    uint32_t (*antennaInfoInit)(const antennaInfoCb antennaInfoCallback);
+    void (*antennaInfoClose) ();
+    uint32_t (*configRobustLocation)(bool enable, bool enableForE911);
+    uint32_t (*configMinGpsWeek)(uint16_t minGpsWeek);
+    uint32_t (*configDeadReckoningEngineParams)(const DeadReckoningEngineConfig& dreConfig);
+    void (*updateNTRIPGGAConsent)(bool consentAccepted);
+    void (*enablePPENtripStream)(const GnssNtripConnectionParams& params, bool enableRTKEngine);
+    void (*disablePPENtripStream)();
+    uint32_t (*gnssUpdateSecondaryBandConfig)(const GnssSvTypeConfig& secondaryBandConfig);
+    uint32_t (*gnssGetSecondaryBandConfig)();
+    void (*resetNetworkInfo)();
+    uint32_t (*configEngineRunState)(PositioningEngineMask engType,
+                                     LocEngineRunState engState);
+};
+
+struct BatchingInterface {
+    size_t size;
+    void (*initialize)(void);
+    void (*deinitialize)(void);
+    void (*addClient)(LocationAPI* client, const LocationCallbacks& callbacks);
+    void (*removeClient)(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+    void (*requestCapabilities)(LocationAPI* client);
+    uint32_t (*startBatching)(LocationAPI* client, BatchingOptions&);
+    void (*stopBatching)(LocationAPI* client, uint32_t id);
+    void (*updateBatchingOptions)(LocationAPI* client, uint32_t id, BatchingOptions&);
+    void (*getBatchedLocations)(LocationAPI* client, uint32_t id, size_t count);
+};
+
+struct GeofenceInterface {
+    size_t size;
+    void (*initialize)(void);
+    void (*deinitialize)(void);
+    void (*addClient)(LocationAPI* client, const LocationCallbacks& callbacks);
+    void (*removeClient)(LocationAPI* client, removeClientCompleteCallback rmClientCb);
+    void (*requestCapabilities)(LocationAPI* client);
+    uint32_t* (*addGeofences)(LocationAPI* client, size_t count, GeofenceOption*, GeofenceInfo*);
+    void (*removeGeofences)(LocationAPI* client, size_t count, uint32_t* ids);
+    void (*modifyGeofences)(LocationAPI* client, size_t count, uint32_t* ids,
+                            GeofenceOption* options);
+    void (*pauseGeofences)(LocationAPI* client, size_t count, uint32_t* ids);
+    void (*resumeGeofences)(LocationAPI* client, size_t count, uint32_t* ids);
+};
+
+#endif /* LOCATION_INTERFACE_H */
diff --git a/gps/pla/Android.bp b/gps/pla/Android.bp
new file mode 100644
index 0000000..5f240eb
--- /dev/null
+++ b/gps/pla/Android.bp
@@ -0,0 +1,7 @@
+
+cc_library_headers {
+
+    name: "libloc_pla_headers",
+    export_include_dirs: ["android"],
+    vendor: true,
+}
diff --git a/gps/pla/android/loc_pla.h b/gps/pla/android/loc_pla.h
new file mode 100644
index 0000000..34cb591
--- /dev/null
+++ b/gps/pla/android/loc_pla.h
@@ -0,0 +1,97 @@
+/* Copyright (c) 2014, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LOC_PLA__
+#define __LOC_PLA__
+
+#ifdef __cplusplus
+#include <utils/SystemClock.h>
+#define uptimeMillis() android::uptimeMillis()
+#define elapsedRealtime() android::elapsedRealtime()
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cutils/properties.h>
+#include <cutils/threads.h>
+#include <cutils/sched_policy.h>
+#include <cutils/android_filesystem_config.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define UID_GPS (AID_GPS)
+#define GID_GPS (AID_GPS)
+#define UID_LOCCLIENT (4021)
+#define GID_LOCCLIENT (4021)
+
+#define LOC_PATH_GPS_CONF_STR      "/vendor/etc/gps.conf"
+#define LOC_PATH_IZAT_CONF_STR     "/vendor/etc/izat.conf"
+#define LOC_PATH_FLP_CONF_STR      "/vendor/etc/flp.conf"
+#define LOC_PATH_LOWI_CONF_STR     "/vendor/etc/lowi.conf"
+#define LOC_PATH_SAP_CONF_STR      "/vendor/etc/sap.conf"
+#define LOC_PATH_APDR_CONF_STR     "/vendor/etc/apdr.conf"
+#define LOC_PATH_XTWIFI_CONF_STR   "/vendor/etc/xtwifi.conf"
+#define LOC_PATH_QUIPC_CONF_STR    "/vendor/etc/quipc.conf"
+#define LOC_PATH_ANT_CORR_STR      "/vendor/etc/gnss_antenna_info.conf"
+#define LOC_PATH_SLIM_CONF_STR     "/vendor/etc/slim.conf"
+#define LOC_PATH_VPE_CONF_STR      "/vendor/etc/vpeglue.conf"
+
+/*!
+ * @brief Function for memory block copy
+ *
+ * @param[out] p_Dest     Destination buffer.
+ * @param[in]  q_DestSize Destination buffer size.
+ * @param[in]  p_Src      Source buffer.
+ * @param[in]  q_SrcSize  Source buffer size.
+ *
+ * @return Number of bytes copied.
+ */
+static inline size_t memscpy (void *p_Dest, size_t q_DestSize, const void *p_Src, size_t q_SrcSize)
+{
+    size_t res = (q_DestSize < q_SrcSize) ? q_DestSize : q_SrcSize;
+    if (p_Dest && p_Src && q_DestSize > 0 && q_SrcSize > 0) {
+        memcpy(p_Dest, p_Src, res);
+    } else {
+        res = 0;
+    }
+    return res;
+}
+
+/*API for boot kpi marker prints  */
+inline int loc_boot_kpi_marker(const char * pFmt, ...)
+{
+    return -1;
+}
+
+#ifdef __cplusplus
+}
+#endif /*__cplusplus */
+
+#endif /* __LOC_PLA__ */
diff --git a/gps/pla/oe/loc_pla.h b/gps/pla/oe/loc_pla.h
new file mode 100644
index 0000000..268b6bf
--- /dev/null
+++ b/gps/pla/oe/loc_pla.h
@@ -0,0 +1,175 @@
+/* Copyright (c) 2014, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LOC_PLA__
+#define __LOC_PLA__
+
+#ifdef __cplusplus
+#ifndef FEATURE_EXTERNAL_AP
+#include <utils/SystemClock.h>
+#endif /* FEATURE_EXTERNAL_AP */
+#include <inttypes.h>
+#include <sys/time.h>
+#include <time.h>
+
+#if defined(__GNUC__) && defined(__GNUC_PREREQ)
+#if __GNUC_PREREQ(6,0)
+    #pragma message "GNU C version is above 6"
+#else
+    #pragma message "GNU C version is less than 6"
+    #define NO_UNORDERED_SET_OR_MAP
+#endif
+#endif
+
+// use set/map instead of unordered_set/unordered_map for
+// older GCC versions
+#ifdef NO_UNORDERED_SET_OR_MAP
+#define unordered_set set
+#define unordered_map map
+#endif
+
+inline int64_t sysTimeMillis(int clock)
+{
+    struct timespec ts;
+    int64_t time_ms = 0;
+    clock_gettime(clock, &ts);
+    time_ms += (ts.tv_sec * 1000000000LL);
+    time_ms += ts.tv_nsec + 500000LL;
+    return time_ms / 1000000LL;
+}
+
+inline int64_t uptimeMillis() {
+    return sysTimeMillis(CLOCK_MONOTONIC);
+}
+inline int64_t elapsedRealtime() {
+    return sysTimeMillis(CLOCK_BOOTTIME);
+}
+
+extern "C" {
+#endif
+
+#ifndef FEATURE_EXTERNAL_AP
+#include <cutils/properties.h>
+#include <cutils/threads.h>
+#include <cutils/sched_policy.h>
+#else
+#define set_sched_policy(a, b)
+#endif /* FEATURE_EXTERNAL_AP */
+#include <pthread.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#define MAX_COMMAND_STR_LEN (255)
+#define BOOT_KPI_FILE "/sys/kernel/debug/bootkpi/kpi_values"
+#ifndef OFF_TARGET
+#include <glib.h>
+#define strlcat g_strlcat
+#define strlcpy g_strlcpy
+#else
+#define strlcat strncat
+#define strlcpy strncpy
+#endif
+
+#define UID_GPS (1021)
+#define GID_GPS (1021)
+#define UID_LOCCLIENT (4021)
+#define GID_LOCCLIENT (4021)
+
+#define LOC_PATH_GPS_CONF_STR      "/etc/gps.conf"
+#define LOC_PATH_IZAT_CONF_STR     "/etc/izat.conf"
+#define LOC_PATH_FLP_CONF_STR      "/etc/flp.conf"
+#define LOC_PATH_LOWI_CONF_STR     "/etc/lowi.conf"
+#define LOC_PATH_SAP_CONF_STR      "/etc/sap.conf"
+#define LOC_PATH_APDR_CONF_STR     "/etc/apdr.conf"
+#define LOC_PATH_XTWIFI_CONF_STR   "/etc/xtwifi.conf"
+#define LOC_PATH_QUIPC_CONF_STR    "/etc/quipc.conf"
+#define LOC_PATH_ANT_CORR_STR      "/etc/gnss_antenna_info.conf"
+#define LOC_PATH_SLIM_CONF_STR     "/etc/slim.conf"
+#define LOC_PATH_VPE_CONF_STR      "/etc/vpeglue.conf"
+
+#ifdef FEATURE_EXTERNAL_AP
+#define PROPERTY_VALUE_MAX 92
+
+inline int property_get(const char* key, char* value, const char* default_value)
+{
+    strlcpy(value, default_value, PROPERTY_VALUE_MAX - 1);
+    return strlen(value);
+}
+#endif /* FEATURE_EXTERNAL_AP */
+
+/*!
+ * @brief Function for memory block copy
+ *
+ * @param[out] p_Dest     Destination buffer.
+ * @param[in]  q_DestSize Destination buffer size.
+ * @param[in]  p_Src      Source buffer.
+ * @param[in]  q_SrcSize  Source buffer size.
+ *
+ * @return Number of bytes copied.
+ */
+static inline size_t memscpy (void *p_Dest, size_t q_DestSize, const void *p_Src, size_t q_SrcSize)
+{
+    size_t res = (q_DestSize < q_SrcSize) ? q_DestSize : q_SrcSize;
+    if (p_Dest && p_Src && q_DestSize > 0 && q_SrcSize > 0) {
+        memcpy(p_Dest, p_Src, res);
+    } else {
+        res = 0;
+    }
+    return res;
+}
+
+/*API for boot kpi marker prints  */
+static inline int loc_boot_kpi_marker(const char * pFmt, ...)
+{
+    int result = 0;
+    FILE *stream = NULL;
+    char data[MAX_COMMAND_STR_LEN] = {};
+    char buf[MAX_COMMAND_STR_LEN] = {};
+
+    va_list ap;
+    va_start(ap, pFmt);
+    vsnprintf(&buf[0], sizeof(buf), pFmt, ap);
+    snprintf(data, sizeof(data), "echo -n %s > %s", buf, BOOT_KPI_FILE);
+    stream = popen(data, "w" );
+    if (NULL == stream) {
+        result = -1;
+    } else {
+        pclose(stream);
+    }
+    va_end(ap);
+    return result;
+}
+
+#ifdef __cplusplus
+}
+#endif /*__cplusplus */
+
+#endif /* __LOC_PLA__ */
diff --git a/gps/utils/Android.bp b/gps/utils/Android.bp
new file mode 100644
index 0000000..33d8440
--- /dev/null
+++ b/gps/utils/Android.bp
@@ -0,0 +1,54 @@
+
+cc_library_shared {
+
+    name: "libgps.utils",
+    vendor: true,
+
+
+
+    //# Libs
+    shared_libs: [
+        "libdl",
+        "libutils",
+        "libcutils",
+        "liblog",
+        "libprocessgroup",
+    ],
+
+    srcs: [
+        "loc_log.cpp",
+        "loc_cfg.cpp",
+        "msg_q.c",
+        "linked_list.c",
+        "loc_target.cpp",
+        "LocHeap.cpp",
+        "LocTimer.cpp",
+        "LocThread.cpp",
+        "MsgTask.cpp",
+        "loc_misc_utils.cpp",
+        "loc_nmea.cpp",
+        "LocIpc.cpp",
+        "LogBuffer.cpp",
+    ],
+
+    cflags: [
+        "-fno-short-enums",
+        "-D_ANDROID_",
+    ] + GNSS_CFLAGS,
+
+    //# Includes
+    ldflags: ["-Wl,--export-dynamic"],
+
+    header_libs: [
+        "libutils_headers",
+        "libloc_pla_headers",
+        "liblocation_api_headers",
+    ],
+}
+
+cc_library_headers {
+
+    name: "libgps.utils_headers",
+    export_include_dirs: ["."],
+    vendor: true,
+}
diff --git a/gps/utils/LocHeap.cpp b/gps/utils/LocHeap.cpp
new file mode 100644
index 0000000..4d047e4
--- /dev/null
+++ b/gps/utils/LocHeap.cpp
@@ -0,0 +1,280 @@
+/* Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <LocHeap.h>
+
+namespace loc_util {
+
+class LocHeapNode {
+    friend class LocHeap;
+
+    // size of of the subtree, excluding self, 1 if no subtree
+    int mSize;
+    LocHeapNode* mLeft;
+    LocHeapNode* mRight;
+    LocRankable* mData;
+public:
+    inline LocHeapNode(LocRankable& data) :
+        mSize(1), mLeft(NULL), mRight(NULL), mData(&data) {}
+    ~LocHeapNode();
+
+    // this only swaps the data of the two nodes, so no
+    // detach / re-attached is necessary
+    void swap(LocHeapNode& node);
+
+    LocRankable* detachData();
+
+    // push a node into the tree stucture, keeping sorted by rank
+    void push(LocHeapNode& node);
+
+    // pop the head node out of the tree stucture. keeping sorted by rank
+    static LocHeapNode* pop(LocHeapNode*& top);
+
+    // remove a specific node from the tree
+    // returns the pointer to the node removed, which would be either the
+    //         same as input (if successfully removed); or NULL (if failed).
+    static LocHeapNode* remove(LocHeapNode*& top, LocRankable& data);
+
+    // convenience method to compare data ranking
+    inline bool outRanks(LocHeapNode& node) { return mData->outRanks(*node.mData); }
+    inline bool outRanks(LocRankable& data) { return mData->outRanks(data); }
+
+    // checks if mSize is correct, AND this node is the highest ranking
+    // of the entire subtree
+    bool checkNodes();
+
+    inline int getSize() { return mSize; }
+};
+
+inline
+LocHeapNode::~LocHeapNode() {
+    if (mLeft) {
+        delete mLeft;
+        mLeft = NULL;
+    }
+    if (mRight) {
+        delete mRight;
+        mRight = NULL;
+    }
+    if (mData) {
+        mData = NULL;
+    }
+}
+
+inline
+void LocHeapNode::swap(LocHeapNode& node) {
+    LocRankable* tmpData = node.mData;
+    node.mData = mData;
+    mData = tmpData;
+}
+
+inline
+LocRankable* LocHeapNode::detachData()  {
+    LocRankable* data = mData;
+    mData = NULL;
+    return data;
+}
+
+// push keeps the tree sorted by rank, it also tries to balance the
+// tree by adding the new node to the smaller of the subtrees.
+// The pointer to the tree and internal links never change. If the
+// mData of tree top ranks lower than that of the incoming node,
+// mData will be swapped with that of the incoming node to ensure
+// ranking, no restructuring the container nodes.
+void LocHeapNode::push(LocHeapNode& node) {
+    // ensure the current node ranks higher than in the incoming one
+    if (node.outRanks(*this)) {
+        swap(node);
+    }
+
+    // now drop the new node (ensured lower than *this) into a subtree
+    if (NULL == mLeft) {
+        mLeft = &node;
+    } else if (NULL == mRight) {
+        mRight = &node;
+    } else if (mLeft->mSize <= mRight->mSize) {
+        mLeft->push(node);
+    } else {
+        mRight->push(node);
+    }
+    mSize++;
+}
+
+// pop keeps the tree sorted by rank, but it does not try to balance
+// the tree. It recursively swaps with the higher ranked top of the
+// subtrees.
+// The return is a popped out node from leaf level, that has the data
+// swapped all the way down from the top. The pinter to the tree and
+// internal links will not be changed or restructured, except for the
+// node that is popped out.
+// If the return pointer == this, this the last node in the tree.
+LocHeapNode* LocHeapNode::pop(LocHeapNode*& top) {
+    // we know the top has the highest ranking at this point, else
+    // the tree is broken. This top will be popped out.  But we need
+    // a node from the left or right child, whichever ranks higher,
+    // to replace the current top. This then will need to be done
+    // recursively to the leaf level. So we swap the mData of the
+    // current top node all the way down to the leaf level.
+    LocHeapNode* poppedNode = top;
+    // top is losing a node in its subtree
+    top->mSize--;
+    if (top->mLeft || top->mRight) {
+        // if mLeft is NULL, mRight for sure is NOT NULL, take that;
+        // else if mRight is NULL, mLeft for sure is NOT, take that;
+        // else we take the address of whatever has higher ranking mData
+        LocHeapNode*& subTop = (NULL == top->mLeft) ? top->mRight :
+            ((NULL == top->mRight) ? top->mLeft :
+             (top->mLeft->outRanks(*(top->mRight)) ? top->mLeft : top->mRight));
+        // swap mData, the tree top gets updated with the new data.
+        top->swap(*subTop);
+        // pop out from the subtree
+        poppedNode = pop(subTop);
+    } else {
+        // if the top has only single node
+        // detach the poppedNode from the tree
+        // subTop is the reference of ether mLeft or mRight
+        // NOT a local stack pointer. so it MUST be NULL'ed here.
+        top = NULL;
+    }
+
+    return poppedNode;
+}
+
+// navigating through the tree and find the node that hass the input
+// data. Since this is a heap, we do recursive linear search.
+// returns the pointer to the node removed, which would be either the
+//         same as input (if successfully removed); or NULL (if failed).
+LocHeapNode* LocHeapNode::remove(LocHeapNode*& top, LocRankable& data) {
+    LocHeapNode* removedNode = NULL;
+    // this is the node, by address
+    if (&data == (LocRankable*)(top->mData)) {
+        // pop this node out
+        removedNode = pop(top);
+    } else if (!data.outRanks(*top->mData)) {
+        // subtrees might have this node
+        if (top->mLeft) {
+            removedNode = remove(top->mLeft, data);
+        }
+        // if we did not find in mLeft, and mRight is not empty
+        if (!removedNode && top->mRight) {
+            removedNode = remove(top->mRight, data);
+        }
+
+        // top lost a node in its subtree
+        if (removedNode) {
+            top->mSize--;
+        }
+    }
+
+    return removedNode;
+}
+
+// checks if mSize is correct, AND this node is the highest ranking
+// of the entire subtree
+bool LocHeapNode::checkNodes() {
+    // size of the current subtree
+    int totalSize = mSize;
+    if (mLeft) {
+        // check the consistency of left subtree
+        if (mLeft->outRanks(*this) || !mLeft->checkNodes()) {
+            return false;
+        }
+        // subtract the size of left subtree (with subtree head)
+        totalSize -= mLeft->mSize;
+    }
+
+    if (mRight) {
+        // check the consistency of right subtree
+        if (mRight->outRanks(*this) || !mRight->checkNodes()) {
+            return false;
+        }
+        // subtract the size of right subtree (with subtree head)
+        totalSize -= mRight->mSize;
+    }
+
+    // for the tree nodes to consistent, totalSize must be 1 now
+    return totalSize == 1;
+}
+
+LocHeap::~LocHeap() {
+    if (mTree) {
+        delete mTree;
+    }
+}
+
+void LocHeap::push(LocRankable& node) {
+    LocHeapNode* heapNode = new LocHeapNode(node);
+    if (!mTree) {
+        mTree = heapNode;
+    } else {
+        mTree->push(*heapNode);
+    }
+}
+
+LocRankable* LocHeap::peek() {
+    LocRankable* top = NULL;
+    if (mTree) {
+        top = mTree->mData;
+    }
+    return top;
+}
+
+LocRankable* LocHeap::pop() {
+    LocRankable* locNode = NULL;
+    if (mTree) {
+        // mTree may become NULL after this call
+        LocHeapNode* heapNode = LocHeapNode::pop(mTree);
+        locNode = heapNode->detachData();
+        delete heapNode;
+    }
+    return locNode;
+}
+
+LocRankable* LocHeap::remove(LocRankable& rankable) {
+    LocRankable* locNode = NULL;
+    if (mTree) {
+        // mTree may become NULL after this call
+        LocHeapNode* heapNode = LocHeapNode::remove(mTree, rankable);
+        if (heapNode) {
+            locNode = heapNode->detachData();
+            delete heapNode;
+        }
+    }
+    return locNode;
+}
+
+} // namespace loc_util
+
+#ifdef __LOC_UNIT_TEST__
+bool LocHeap::checkTree() {
+    return ((NULL == mTree) || mTree->checkNodes());
+}
+uint32_t LocHeap::getTreeSize() {
+    return (NULL == mTree) ? 0 : mTree->getSize();
+}
+#endif
diff --git a/gps/utils/LocHeap.h b/gps/utils/LocHeap.h
new file mode 100644
index 0000000..bb62d6b
--- /dev/null
+++ b/gps/utils/LocHeap.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __LOC_HEAP__
+#define __LOC_HEAP__
+
+#include <stddef.h>
+#include <string.h>
+
+namespace loc_util {
+
+// abstract class to be implemented by client to provide a rankable class
+class LocRankable {
+public:
+    virtual inline ~LocRankable() {}
+
+    // method to rank objects of such type for sorting purposes.
+    // The pointer of the input node would be stored in the heap.
+    // >0 if ranks higher than the input;
+    // ==0 if equally ranks with the input;
+    // <0 if ranks lower than the input
+    virtual int ranks(LocRankable& rankable) = 0;
+
+    // convenient method to rank objects of such type for sorting purposes.
+    inline bool outRanks(LocRankable& rankable) { return ranks(rankable) > 0; }
+};
+
+// opaque class to provide service implementation.
+class LocHeapNode;
+
+// a heap whose left and right children are not sorted. It is sorted only vertically,
+// i.e. parent always ranks higher than children, if they exist. Ranking algorithm is
+// implemented in Rankable. The reason that there is no sort between children is to
+// help beter balance the tree with lower cost. When a node is pushed to the tree,
+// it is guaranteed that the subtree that is smaller gets to have the new node.
+class LocHeap {
+protected:
+    LocHeapNode* mTree;
+public:
+    inline LocHeap() : mTree(NULL) {}
+    ~LocHeap();
+
+    // push keeps the tree sorted by rank, it also tries to balance the
+    // tree by adding the new node to the smaller of the subtrees.
+    // node is reference to an obj that is managed by client, that client
+    //      creates and destroyes. The destroy should happen after the
+    //      node is popped out from the heap.
+    void push(LocRankable& node);
+
+    // Peeks the node data on tree top, which has currently the highest ranking
+    // There is no change the tree structure with this operation
+    // Returns NULL if the tree is empty, otherwise pointer to the node data of
+    //         the tree top.
+    LocRankable* peek();
+
+    // pop keeps the tree sorted by rank, but it does not try to balance
+    // the tree.
+    // Return - pointer to the node popped out, or NULL if heap is already empty
+    LocRankable* pop();
+
+    // navigating through the tree and find the node that ranks the same
+    // as the input data, then remove it from the tree. Rank is implemented
+    // by rankable obj.
+    // returns the pointer to the node removed; or NULL (if failed).
+    LocRankable* remove(LocRankable& rankable);
+
+#ifdef __LOC_UNIT_TEST__
+    bool checkTree();
+    uint32_t getTreeSize();
+#endif
+};
+
+} // namespace loc_util
+
+#endif //__LOC_HEAP__
diff --git a/gps/utils/LocIpc.cpp b/gps/utils/LocIpc.cpp
new file mode 100644
index 0000000..746ca87
--- /dev/null
+++ b/gps/utils/LocIpc.cpp
@@ -0,0 +1,430 @@
+/* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <loc_misc_utils.h>
+#include <log_util.h>
+#include <LocIpc.h>
+#include <algorithm>
+
+using namespace std;
+
+namespace loc_util {
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LocSvc_LocIpc"
+
+#define SOCK_OP_AND_LOG(buf, length, opable, rtv, exe)  \
+    if (nullptr == (buf) || 0 == (length)) { \
+        LOC_LOGe("Invalid inputs: buf - %p, length - %u", (buf), (length)); \
+    } else if (!(opable)) {                                             \
+        LOC_LOGe("Invalid object: operable - %d", (opable));            \
+    } else { \
+        rtv = (exe); \
+        if (-1 == rtv) { \
+            LOC_LOGw("failed reason: %s", strerror(errno)); \
+        } \
+    }
+
+const char Sock::MSG_ABORT[] = "LocIpc::Sock::ABORT";
+const char Sock::LOC_IPC_HEAD[] = "$MSGLEN$";
+ssize_t Sock::send(const void *buf, uint32_t len, int flags, const struct sockaddr *destAddr,
+                          socklen_t addrlen) const {
+    ssize_t rtv = -1;
+    SOCK_OP_AND_LOG(buf, len, isValid(), rtv, sendto(buf, len, flags, destAddr, addrlen));
+    return rtv;
+}
+ssize_t Sock::recv(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, int flags,
+                   struct sockaddr *srcAddr, socklen_t *addrlen, int sid) const {
+    ssize_t rtv = -1;
+    if (-1 == sid) {
+        sid = mSid;
+    } // else it sid would be connection based socket id for recv
+    SOCK_OP_AND_LOG(dataCb.get(), mMaxTxSize, isValid(), rtv,
+                    recvfrom(recver, dataCb, sid, flags, srcAddr, addrlen));
+    return rtv;
+}
+ssize_t Sock::sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr,
+                     socklen_t addrlen) const {
+    ssize_t rtv = -1;
+    if (len <= mMaxTxSize) {
+        rtv = ::sendto(mSid, buf, len, flags, destAddr, addrlen);
+    } else {
+        std::string head(LOC_IPC_HEAD + to_string(len));
+        rtv = ::sendto(mSid, head.c_str(), head.length(), flags, destAddr, addrlen);
+        if (rtv > 0) {
+            for (size_t offset = 0; offset < len && rtv > 0; offset += rtv) {
+                rtv = ::sendto(mSid, (char*)buf + offset, min(len - offset, (size_t)mMaxTxSize),
+                               flags, destAddr, addrlen);
+            }
+            rtv = (rtv > 0) ? (head.length() + len) : -1;
+        }
+    }
+    return rtv;
+}
+ssize_t Sock::recvfrom(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb,
+                       int sid, int flags, struct sockaddr *srcAddr, socklen_t *addrlen) const  {
+    std::string msg(mMaxTxSize, 0);
+    ssize_t nBytes = ::recvfrom(sid, (void*)msg.data(), msg.size(), flags, srcAddr, addrlen);
+    if (nBytes > 0) {
+        if (strncmp(msg.data(), MSG_ABORT, sizeof(MSG_ABORT)) == 0) {
+            LOC_LOGi("recvd abort msg.data %s", msg.data());
+            nBytes = 0;
+        } else if (strncmp(msg.data(), LOC_IPC_HEAD, sizeof(LOC_IPC_HEAD) - 1)) {
+            // short message
+            msg.resize(nBytes);
+            dataCb->onReceive(msg.data(), nBytes, &recver);
+        } else {
+            // long message
+            size_t msgLen = 0;
+            sscanf(msg.data() + sizeof(LOC_IPC_HEAD) - 1, "%zu", &msgLen);
+            msg.resize(msgLen);
+            for (size_t msgLenReceived = 0; (msgLenReceived < msgLen) && (nBytes > 0);
+                 msgLenReceived += nBytes) {
+                nBytes = ::recvfrom(sid, &(msg[msgLenReceived]), msg.size() - msgLenReceived,
+                                    flags, srcAddr, addrlen);
+            }
+            if (nBytes > 0) {
+                nBytes = msgLen;
+                dataCb->onReceive(msg.data(), nBytes, &recver);
+            }
+        }
+    }
+
+    return nBytes;
+}
+ssize_t Sock::sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen) {
+    return send(MSG_ABORT, sizeof(MSG_ABORT), flags, destAddr, addrlen);
+}
+
+class LocIpcLocalSender : public LocIpcSender {
+protected:
+    shared_ptr<Sock> mSock;
+    struct sockaddr_un mAddr;
+    inline virtual bool isOperable() const override { return mSock != nullptr && mSock->isValid(); }
+    inline virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t /* msgId */) const {
+        return mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr));
+    }
+public:
+    inline LocIpcLocalSender(const char* name) : LocIpcSender(),
+            mSock(nullptr),
+            mAddr({.sun_family = AF_UNIX, {}}) {
+
+        int fd = -1;
+        if (nullptr != name) {
+            fd = ::socket(AF_UNIX, SOCK_DGRAM, 0);
+            if (fd >= 0) {
+                timeval timeout;
+                timeout.tv_sec = 2;
+                timeout.tv_usec = 0;
+                setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
+            }
+        }
+        mSock.reset(new Sock(fd));
+        if (mSock != nullptr && mSock->isValid()) {
+            snprintf(mAddr.sun_path, sizeof(mAddr.sun_path), "%s", name);
+        }
+    }
+};
+
+class LocIpcLocalRecver : public LocIpcLocalSender, public LocIpcRecver {
+protected:
+    inline virtual ssize_t recv() const override {
+        socklen_t size = sizeof(mAddr);
+        return mSock->recv(*this, mDataCb, 0, (struct sockaddr*)&mAddr, &size);
+    }
+public:
+    inline LocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener, const char* name) :
+            LocIpcLocalSender(name), LocIpcRecver(listener, *this) {
+
+        if ((unlink(mAddr.sun_path) < 0) && (errno != ENOENT)) {
+            LOC_LOGw("unlink socket error. reason:%s", strerror(errno));
+        }
+
+        umask(0157);
+        if (mSock->isValid() && ::bind(mSock->mSid, (struct sockaddr*)&mAddr, sizeof(mAddr)) < 0) {
+            LOC_LOGe("bind socket error. sock fd: %d: %s, reason: %s", mSock->mSid,
+                    mAddr.sun_path, strerror(errno));
+            mSock->close();
+        }
+    }
+    inline virtual ~LocIpcLocalRecver() { unlink(mAddr.sun_path); }
+    inline virtual const char* getName() const override { return mAddr.sun_path; };
+    inline virtual void abort() const override {
+        if (isSendable()) {
+            mSock->sendAbort(0, (struct sockaddr*)&mAddr, sizeof(mAddr));
+        }
+    }
+};
+
+class LocIpcInetSender : public LocIpcSender {
+protected:
+    int mSockType;
+    shared_ptr<Sock> mSock;
+    const string mName;
+    sockaddr_in mAddr;
+    inline virtual bool isOperable() const override { return mSock != nullptr && mSock->isValid(); }
+    virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t /* msgId */) const {
+        return mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr));
+    }
+public:
+    inline LocIpcInetSender(const LocIpcInetSender& sender) :
+            mSockType(sender.mSockType), mSock(sender.mSock),
+            mName(sender.mName), mAddr(sender.mAddr) {
+    }
+    inline LocIpcInetSender(const char* name, int32_t port, int sockType) : LocIpcSender(),
+            mSockType(sockType),
+            mSock(make_shared<Sock>((nullptr == name) ? -1 : (::socket(AF_INET, mSockType, 0)))),
+            mName((nullptr == name) ? "" : name),
+            mAddr({.sin_family = AF_INET, .sin_port = htons(port),
+                    .sin_addr = {htonl(INADDR_ANY)}}) {
+        if (mSock != nullptr && mSock->isValid() && nullptr != name) {
+            struct hostent* hp = gethostbyname(name);
+            if (nullptr != hp) {
+                memcpy((char*)&(mAddr.sin_addr.s_addr), hp->h_addr_list[0], hp->h_length);
+            }
+        }
+    }
+
+    unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) override {
+        return make_unique<SockRecver>(listener, *this, mSock);
+    }
+};
+
+class LocIpcInetTcpSender : public LocIpcInetSender {
+protected:
+    mutable bool mFirstTime;
+
+    virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t /* msgId */) const {
+        if (mFirstTime) {
+            mFirstTime = false;
+            ::connect(mSock->mSid, (const struct sockaddr*)&mAddr, sizeof(mAddr));
+        }
+        return mSock->send(data, length, 0, (struct sockaddr*)&mAddr, sizeof(mAddr));
+    }
+
+public:
+    inline LocIpcInetTcpSender(const char* name, int32_t port) :
+            LocIpcInetSender(name, port, SOCK_STREAM),
+            mFirstTime(true) {}
+};
+
+class LocIpcInetRecver : public LocIpcInetSender, public LocIpcRecver {
+     int32_t mPort;
+protected:
+     virtual ssize_t recv() const = 0;
+public:
+    inline LocIpcInetRecver(const shared_ptr<ILocIpcListener>& listener, const char* name,
+                               int32_t port, int sockType) :
+            LocIpcInetSender(name, port, sockType), LocIpcRecver(listener, *this),
+            mPort(port) {
+        if (mSock->isValid() && ::bind(mSock->mSid, (struct sockaddr*)&mAddr, sizeof(mAddr)) < 0) {
+            LOC_LOGe("bind socket error. sock fd: %d, reason: %s", mSock->mSid, strerror(errno));
+            mSock->close();
+        }
+    }
+    inline virtual ~LocIpcInetRecver() {}
+    inline virtual const char* getName() const override { return mName.data(); };
+    inline virtual void abort() const override {
+        if (isSendable()) {
+            sockaddr_in loopBackAddr = {.sin_family = AF_INET, .sin_port = htons(mPort),
+                    .sin_addr = {htonl(INADDR_LOOPBACK)}};
+            mSock->sendAbort(0, (struct sockaddr*)&loopBackAddr, sizeof(loopBackAddr));
+        }
+    }
+    inline virtual unique_ptr<LocIpcSender> getLastSender() const override {
+        return make_unique<LocIpcInetSender>(static_cast<const LocIpcInetSender&>(*this));
+    }
+};
+
+class LocIpcInetTcpRecver : public LocIpcInetRecver {
+    mutable int32_t mConnFd;
+protected:
+    inline virtual ssize_t recv() const override {
+        socklen_t size = sizeof(mAddr);
+        if (-1 == mConnFd && mSock->isValid()) {
+            if (::listen(mSock->mSid, 3) < 0 ||
+                (mConnFd = accept(mSock->mSid, (struct sockaddr*)&mAddr, &size)) < 0) {
+                mSock->close();
+                mConnFd = -1;
+            }
+        }
+        return mSock->recv(*this, mDataCb, 0, (struct sockaddr*)&mAddr, &size, mConnFd);
+    }
+public:
+    inline LocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener, const char* name,
+                               int32_t port) :
+            LocIpcInetRecver(listener, name, port, SOCK_STREAM), mConnFd(-1) {}
+    inline virtual ~LocIpcInetTcpRecver() { if (-1 != mConnFd) ::close(mConnFd);}
+};
+
+class LocIpcInetUdpRecver : public LocIpcInetRecver {
+protected:
+    inline virtual ssize_t recv() const override {
+        socklen_t size = sizeof(mAddr);
+        return mSock->recv(*this, mDataCb, 0, (struct sockaddr*)&mAddr, &size);
+    }
+public:
+    inline LocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener, const char* name,
+                                int32_t port) :
+            LocIpcInetRecver(listener, name, port, SOCK_DGRAM) {}
+
+    inline virtual ~LocIpcInetUdpRecver() {}
+};
+
+class LocIpcRunnable : public LocRunnable {
+    bool mAbortCalled;
+    LocIpc& mLocIpc;
+    unique_ptr<LocIpcRecver> mIpcRecver;
+public:
+    inline LocIpcRunnable(LocIpc& locIpc, unique_ptr<LocIpcRecver>& ipcRecver) :
+            mAbortCalled(false),
+            mLocIpc(locIpc),
+            mIpcRecver(move(ipcRecver)) {}
+    inline virtual bool run() override {
+        if (mIpcRecver != nullptr) {
+            mLocIpc.startBlockingListening(*(mIpcRecver.get()));
+            if (!mAbortCalled) {
+                LOC_LOGw("startListeningBlocking() returned w/o stopBlockingListening() called");
+            }
+        }
+        // return false so the calling thread exits while loop
+        return false;
+    }
+    inline virtual void interrupt() override {
+        mAbortCalled = true;
+        if (mIpcRecver != nullptr) {
+            mIpcRecver->abort();
+        }
+    }
+};
+
+bool LocIpc::startNonBlockingListening(unique_ptr<LocIpcRecver>& ipcRecver) {
+    if (ipcRecver != nullptr && ipcRecver->isRecvable()) {
+        std::string threadName("LocIpc-");
+        threadName.append(ipcRecver->getName());
+        return mThread.start(threadName.c_str(), make_shared<LocIpcRunnable>(*this, ipcRecver));
+    } else {
+        LOC_LOGe("ipcRecver is null OR ipcRecver->recvable() is fasle");
+        return false;
+    }
+}
+
+bool LocIpc::startBlockingListening(LocIpcRecver& ipcRecver) {
+    if (ipcRecver.isRecvable()) {
+        // inform that the socket is ready to receive message
+        ipcRecver.onListenerReady();
+        while (ipcRecver.recvData());
+        return true;
+    } else  {
+        LOC_LOGe("ipcRecver is null OR ipcRecver->recvable() is fasle");
+        return false;
+    }
+}
+
+void LocIpc::stopNonBlockingListening() {
+    mThread.stop();
+}
+
+void LocIpc::stopBlockingListening(LocIpcRecver& ipcRecver) {
+    if (ipcRecver.isRecvable()) {
+        ipcRecver.abort();
+    }
+}
+
+bool LocIpc::send(LocIpcSender& sender, const uint8_t data[], uint32_t length, int32_t msgId) {
+    return sender.sendData(data, length, msgId);
+}
+
+shared_ptr<LocIpcSender> LocIpc::getLocIpcLocalSender(const char* localSockName) {
+    return make_shared<LocIpcLocalSender>(localSockName);
+}
+unique_ptr<LocIpcRecver> LocIpc::getLocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener,
+                                                      const char* localSockName) {
+    return make_unique<LocIpcLocalRecver>(listener, localSockName);
+}
+static void* sLibQrtrHandle = nullptr;
+static const char* sLibQrtrName = "libloc_socket.so";
+shared_ptr<LocIpcSender> LocIpc::getLocIpcQrtrSender(int service, int instance) {
+    typedef shared_ptr<LocIpcSender> (*creator_t) (int, int);
+    static creator_t creator = (creator_t)dlGetSymFromLib(sLibQrtrHandle, sLibQrtrName,
+            "_ZN8loc_util22createLocIpcQrtrSenderEii");
+    return (nullptr == creator) ? nullptr : creator(service, instance);
+}
+unique_ptr<LocIpcRecver> LocIpc::getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
+                                                     int service, int instance,
+                                                     const shared_ptr<LocIpcQrtrWatcher>& watcher) {
+    typedef unique_ptr<LocIpcRecver> (*creator_t)(const shared_ptr<ILocIpcListener>&, int, int,
+                                                  const shared_ptr<LocIpcQrtrWatcher>& watcher);
+    static creator_t creator = (creator_t)dlGetSymFromLib(sLibQrtrHandle, sLibQrtrName,
+#ifdef USE_GLIB
+            "_ZN8loc_util22createLocIpcQrtrRecverERKSt10shared_ptrINS_15ILocIpcListenerEEiiRKS0_INS_17LocIpcQrtrWatcherEE");
+#else
+            "_ZN8loc_util22createLocIpcQrtrRecverERKNSt3__110shared_ptrINS_15ILocIpcListenerEEEiiRKNS1_INS_17LocIpcQrtrWatcherEEE");
+#endif
+    return (nullptr == creator) ? nullptr : creator(listener, service, instance, watcher);
+}
+shared_ptr<LocIpcSender> LocIpc::getLocIpcInetTcpSender(const char* serverName, int32_t port) {
+    return make_shared<LocIpcInetTcpSender>(serverName, port);
+}
+unique_ptr<LocIpcRecver> LocIpc::getLocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener,
+                                                            const char* serverName, int32_t port) {
+    return make_unique<LocIpcInetTcpRecver>(listener, serverName, port);
+}
+shared_ptr<LocIpcSender> LocIpc::getLocIpcInetUdpSender(const char* serverName, int32_t port) {
+    return make_shared<LocIpcInetSender>(serverName, port, SOCK_DGRAM);
+}
+unique_ptr<LocIpcRecver> LocIpc::getLocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener,
+                                                             const char* serverName, int32_t port) {
+    return make_unique<LocIpcInetUdpRecver>(listener, serverName, port);
+}
+pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>>
+        LocIpc::getLocIpcQmiLocServiceSenderRecverPair(const shared_ptr<ILocIpcListener>& listener, int instance) {
+    typedef pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>> (*creator_t)(const shared_ptr<ILocIpcListener>&, int);
+    static void* sLibEmuHandle = nullptr;
+    static creator_t creator = (creator_t)dlGetSymFromLib(sLibEmuHandle, "libloc_emu.so",
+#ifdef USE_GLIB
+            "_ZN13QmiLocService41createLocIpcQmiLocServiceSenderRecverPair"\
+            "ERKSt10shared_ptrIN8loc_util15ILocIpcListenerEEi");
+#else
+            "_ZN13QmiLocService41createLocIpcQmiLocServiceSenderRecverPair"\
+            "ERKNSt3__110shared_ptrIN8loc_util15ILocIpcListenerEEEi");
+#endif
+    return (nullptr == creator) ?
+            make_pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>>(nullptr, nullptr) :
+            creator(listener, instance);
+}
+
+}
diff --git a/gps/utils/LocIpc.h b/gps/utils/LocIpc.h
new file mode 100644
index 0000000..b2586e6
--- /dev/null
+++ b/gps/utils/LocIpc.h
@@ -0,0 +1,241 @@
+/* Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __LOC_IPC__
+#define __LOC_IPC__
+
+#include <string>
+#include <memory>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unordered_set>
+#include <mutex>
+#include <LocThread.h>
+
+using namespace std;
+
+namespace loc_util {
+
+class LocIpcRecver;
+class LocIpcSender;
+
+class ILocIpcListener {
+protected:
+    inline virtual ~ILocIpcListener() {}
+public:
+    // LocIpc client can overwrite this function to get notification
+    // when the socket for LocIpc is ready to receive messages.
+    inline virtual void onListenerReady() {}
+    virtual void onReceive(const char* data, uint32_t len, const LocIpcRecver* recver) = 0;
+};
+
+class LocIpcQrtrWatcher {
+    const unordered_set<int> mServicesToWatch;
+    unordered_set<int> mClientsToWatch;
+    mutex mMutex;
+    inline bool isInWatch(const unordered_set<int>& idsToWatch, int id) {
+        return idsToWatch.find(id) != idsToWatch.end();
+    }
+protected:
+    inline virtual ~LocIpcQrtrWatcher() {}
+    inline LocIpcQrtrWatcher(unordered_set<int> servicesToWatch)
+            : mServicesToWatch(servicesToWatch) {}
+public:
+    enum class ServiceStatus { UP, DOWN };
+    inline bool isServiceInWatch(int serviceId) {
+        return isInWatch(mServicesToWatch, serviceId);
+    }
+    inline bool isClientInWatch(int nodeId) {
+        lock_guard<mutex> lock(mMutex);
+        return isInWatch(mClientsToWatch, nodeId);
+    }
+    inline void addClientToWatch(int nodeId) {
+        lock_guard<mutex> lock(mMutex);
+        mClientsToWatch.emplace(nodeId);
+    }
+    virtual void onServiceStatusChange(int sericeId, int instanceId, ServiceStatus status,
+                                       const LocIpcSender& sender) = 0;
+    inline virtual void onClientGone(int nodeId, int portId) {}
+    inline const unordered_set<int>& getServicesToWatch() { return mServicesToWatch; }
+};
+
+class LocIpc {
+public:
+    inline LocIpc() = default;
+    inline virtual ~LocIpc() {
+        stopNonBlockingListening();
+    }
+
+    static shared_ptr<LocIpcSender>
+            getLocIpcLocalSender(const char* localSockName);
+    static shared_ptr<LocIpcSender>
+            getLocIpcInetUdpSender(const char* serverName, int32_t port);
+    static shared_ptr<LocIpcSender>
+            getLocIpcInetTcpSender(const char* serverName, int32_t port);
+    static shared_ptr<LocIpcSender>
+            getLocIpcQrtrSender(int service, int instance);
+
+    static unique_ptr<LocIpcRecver>
+            getLocIpcLocalRecver(const shared_ptr<ILocIpcListener>& listener,
+                                 const char* localSockName);
+    static unique_ptr<LocIpcRecver>
+            getLocIpcInetUdpRecver(const shared_ptr<ILocIpcListener>& listener,
+                                 const char* serverName, int32_t port);
+    static unique_ptr<LocIpcRecver>
+            getLocIpcInetTcpRecver(const shared_ptr<ILocIpcListener>& listener,
+                                   const char* serverName, int32_t port);
+    inline static unique_ptr<LocIpcRecver>
+            getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
+                                int service, int instance) {
+        const shared_ptr<LocIpcQrtrWatcher> qrtrWatcher = nullptr;
+        return getLocIpcQrtrRecver(listener, service, instance, qrtrWatcher);
+    }
+    static unique_ptr<LocIpcRecver>
+            getLocIpcQrtrRecver(const shared_ptr<ILocIpcListener>& listener,
+                                int service, int instance,
+                                const shared_ptr<LocIpcQrtrWatcher>& qrtrWatcher);
+
+    static pair<shared_ptr<LocIpcSender>, unique_ptr<LocIpcRecver>>
+            getLocIpcQmiLocServiceSenderRecverPair(const shared_ptr<ILocIpcListener>& listener,
+                                                   int instance);
+
+    // Listen for new messages in current thread. Calling this funciton will
+    // block current thread.
+    // The listening can be stopped by calling stopBlockingListening() passing
+    // in the same ipcRecver obj handle.
+    static bool startBlockingListening(LocIpcRecver& ipcRecver);
+    static void stopBlockingListening(LocIpcRecver& ipcRecver);
+
+    // Create a new LocThread and listen for new messages in it.
+    // Calling this function will return immediately and won't block current thread.
+    // The listening can be stopped by calling stopNonBlockingListening().
+    bool startNonBlockingListening(unique_ptr<LocIpcRecver>& ipcRecver);
+    void stopNonBlockingListening();
+
+    // Send out a message.
+    // Call this function to send a message in argument data to socket in argument name.
+    //
+    // Argument name contains the name of the target unix socket. data contains the
+    // message to be sent out. Convert your message to a string before calling this function.
+    // The function will return true on success, and false on failure.
+    static bool send(LocIpcSender& sender, const uint8_t data[],
+                     uint32_t length, int32_t msgId = -1);
+
+private:
+    LocThread mThread;
+};
+
+/* this is only when client needs to implement Sender / Recver that are not already provided by
+   the factor methods prvoided by LocIpc. */
+
+class LocIpcSender {
+protected:
+    LocIpcSender() = default;
+    virtual bool isOperable() const = 0;
+    virtual ssize_t send(const uint8_t data[], uint32_t length, int32_t msgId) const = 0;
+public:
+    virtual ~LocIpcSender() = default;
+    inline bool isSendable() const { return isOperable(); }
+    inline bool sendData(const uint8_t data[], uint32_t length, int32_t msgId) const {
+        return isSendable() && (send(data, length, msgId) > 0);
+    }
+    virtual unique_ptr<LocIpcRecver> getRecver(const shared_ptr<ILocIpcListener>& listener) {
+        return nullptr;
+    }
+    inline virtual void copyDestAddrFrom(const LocIpcSender& otherSender) {}
+};
+
+class LocIpcRecver {
+    LocIpcSender& mIpcSender;
+protected:
+    const shared_ptr<ILocIpcListener> mDataCb;
+    inline LocIpcRecver(const shared_ptr<ILocIpcListener>& listener, LocIpcSender& sender) :
+            mIpcSender(sender), mDataCb(listener) {}
+    LocIpcRecver(LocIpcRecver const& recver) = delete;
+    LocIpcRecver& operator=(LocIpcRecver const& recver) = delete;
+    virtual ssize_t recv() const = 0;
+public:
+    virtual ~LocIpcRecver() = default;
+    inline bool recvData() const { return isRecvable() && (recv() > 0); }
+    inline bool isRecvable() const { return mDataCb != nullptr && mIpcSender.isSendable(); }
+    virtual void onListenerReady() { if (mDataCb != nullptr) mDataCb->onListenerReady(); }
+    inline virtual unique_ptr<LocIpcSender> getLastSender() const {
+        return nullptr;
+    }
+    virtual void abort() const = 0;
+    virtual const char* getName() const = 0;
+};
+
+class Sock {
+    static const char MSG_ABORT[];
+    static const char LOC_IPC_HEAD[];
+    const uint32_t mMaxTxSize;
+    ssize_t sendto(const void *buf, size_t len, int flags, const struct sockaddr *destAddr,
+                   socklen_t addrlen) const;
+    ssize_t recvfrom(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb,
+                     int sid, int flags, struct sockaddr *srcAddr, socklen_t *addrlen) const;
+public:
+    int mSid;
+    inline Sock(int sid, const uint32_t maxTxSize = 8192) : mMaxTxSize(maxTxSize), mSid(sid) {}
+    inline ~Sock() { close(); }
+    inline bool isValid() const { return -1 != mSid; }
+    ssize_t send(const void *buf, uint32_t len, int flags, const struct sockaddr *destAddr,
+                 socklen_t addrlen) const;
+    ssize_t recv(const LocIpcRecver& recver, const shared_ptr<ILocIpcListener>& dataCb, int flags,
+                 struct sockaddr *srcAddr, socklen_t *addrlen, int sid = -1) const;
+    ssize_t sendAbort(int flags, const struct sockaddr *destAddr, socklen_t addrlen);
+    inline void close() {
+        if (isValid()) {
+            ::close(mSid);
+            mSid = -1;
+        }
+    }
+};
+
+class SockRecver : public LocIpcRecver {
+    shared_ptr<Sock> mSock;
+protected:
+    inline virtual ssize_t recv() const override {
+        return mSock->recv(*this, mDataCb, 0, nullptr, nullptr);
+    }
+public:
+    inline SockRecver(const shared_ptr<ILocIpcListener>& listener,
+                  LocIpcSender& sender, shared_ptr<Sock> sock) :
+            LocIpcRecver(listener, sender), mSock(sock) {
+    }
+    inline virtual const char* getName() const override {
+        return "SockRecver";
+    }
+    inline virtual void abort() const override {}
+};
+
+}
+
+#endif //__LOC_IPC__
diff --git a/gps/utils/LocLoggerBase.h b/gps/utils/LocLoggerBase.h
new file mode 100644
index 0000000..867b6e2
--- /dev/null
+++ b/gps/utils/LocLoggerBase.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef LOC_LOGGER_BASE_H
+#define LOC_LOGGER_BASE_H
+
+namespace loc_util {
+class LocLoggerBase {
+public:
+    virtual void log() {}
+};
+}
+
+#endif
diff --git a/gps/utils/LocSharedLock.h b/gps/utils/LocSharedLock.h
new file mode 100644
index 0000000..1ef2c57
--- /dev/null
+++ b/gps/utils/LocSharedLock.h
@@ -0,0 +1,81 @@
+/* Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __LOC_SHARED_LOCK__
+#define __LOC_SHARED_LOCK__
+
+#include <stddef.h>
+#ifndef FEATURE_EXTERNAL_AP
+#include <cutils/atomic.h>
+#endif /* FEATURE_EXTERNAL_AP */
+#include <pthread.h>
+
+#ifdef FEATURE_EXTERNAL_AP
+#include <atomic>
+
+inline int32_t android_atomic_inc(volatile int32_t *addr)
+{
+    volatile std::atomic_int_least32_t* a = (volatile std::atomic_int_least32_t*)addr;
+    return std::atomic_fetch_add_explicit(a, 1, std::memory_order_release);
+}
+
+inline int32_t android_atomic_dec(volatile int32_t *addr)
+{
+    volatile std::atomic_int_least32_t* a = (volatile std::atomic_int_least32_t*)addr;
+    return std::atomic_fetch_sub_explicit(a, 1, std::memory_order_release);
+}
+#endif /* FEATURE_EXTERNAL_AP */
+
+namespace loc_util {
+
+// This is a utility created for use cases such that there are more than
+// one client who need to share the same lock, but it is not predictable
+// which of these clients is to last to go away. This shared lock deletes
+// itself when the last client calls its drop() method. To add a cient,
+// this share lock's share() method has to be called, so that the obj
+// can maintain an accurate client count.
+class LocSharedLock {
+    volatile int32_t mRef;
+    pthread_mutex_t mMutex;
+    inline ~LocSharedLock() { pthread_mutex_destroy(&mMutex); }
+public:
+    // first client to create this LockSharedLock
+    inline LocSharedLock() : mRef(1) { pthread_mutex_init(&mMutex, NULL); }
+    // following client(s) are to *share()* this lock created by the first client
+    inline LocSharedLock* share() { android_atomic_inc(&mRef); return this; }
+    // whe a client no longer needs this shared lock, drop() shall be called.
+    inline void drop() { if (1 == android_atomic_dec(&mRef)) delete this; }
+    // locking the lock to enter critical section
+    inline void lock() { pthread_mutex_lock(&mMutex); }
+    // unlocking the lock to leave the critical section
+    inline void unlock() { pthread_mutex_unlock(&mMutex); }
+};
+
+} //namespace loc_util
+
+#endif //__LOC_SHARED_LOCK__
diff --git a/gps/utils/LocThread.cpp b/gps/utils/LocThread.cpp
new file mode 100644
index 0000000..3cac1f9
--- /dev/null
+++ b/gps/utils/LocThread.cpp
@@ -0,0 +1,111 @@
+/* Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <sys/prctl.h>
+#include <LocThread.h>
+#include <string.h>
+#include <string>
+#include <thread>
+#include <loc_pla.h>
+
+using std::weak_ptr;
+using std::shared_ptr;
+using std::thread;
+using std::string;
+
+namespace loc_util {
+
+class LocThreadDelegate {
+    static const char defaultThreadName[];
+    weak_ptr<LocRunnable> mRunnable;
+    thread mThread;
+    LocThreadDelegate(const string tName, shared_ptr<LocRunnable> r);
+public:
+    ~LocThreadDelegate() {
+        shared_ptr<LocRunnable> runnable = mRunnable.lock();
+        if (nullptr != runnable) {
+            runnable->interrupt();
+        }
+    }
+    inline static LocThreadDelegate* create(const char* tName, shared_ptr<LocRunnable> runnable);
+};
+
+const char LocThreadDelegate::defaultThreadName[] = "LocThread";
+
+LocThreadDelegate* LocThreadDelegate::create(const char* tName, shared_ptr<LocRunnable> runnable) {
+    LocThreadDelegate* threadDelegate = nullptr;
+
+    if (nullptr != runnable) {
+        if (!tName) {
+            tName = defaultThreadName;
+        }
+
+        char lname[16];
+        auto nameSize = strlen(tName) + 1;
+        int len = std::min(sizeof(lname), nameSize) - 1;
+        memcpy(lname, tName, len);
+        lname[len] = 0;
+
+        threadDelegate = new LocThreadDelegate(lname, runnable);
+    }
+
+    return threadDelegate;
+}
+
+LocThreadDelegate::LocThreadDelegate(const string tName, shared_ptr<LocRunnable> runnable) :
+        mRunnable(runnable),
+        mThread([tName, runnable] {
+                prctl(PR_SET_NAME, tName.c_str(), 0, 0, 0);
+                runnable->prerun();
+                while (runnable->run());
+                runnable->postrun();
+            }) {
+
+    mThread.detach();
+}
+
+
+
+bool LocThread::start(const char* tName, shared_ptr<LocRunnable> runnable) {
+    bool success = false;
+    if (!mThread) {
+        mThread = LocThreadDelegate::create(tName, runnable);
+        // true only if thread is created successfully
+        success = (NULL != mThread);
+    }
+    return success;
+}
+
+void LocThread::stop() {
+    if (nullptr != mThread) {
+        delete mThread;
+        mThread = nullptr;
+    }
+}
+
+} // loc_util
diff --git a/gps/utils/LocThread.h b/gps/utils/LocThread.h
new file mode 100644
index 0000000..c7ece87
--- /dev/null
+++ b/gps/utils/LocThread.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __LOC_THREAD__
+#define __LOC_THREAD__
+
+#include <stddef.h>
+#include <memory>
+
+using std::shared_ptr;
+
+namespace loc_util {
+
+// abstract class to be implemented by client to provide a runnable class
+// which gets scheduled by LocThread
+class LocRunnable {
+public:
+    inline LocRunnable() = default;
+    inline virtual ~LocRunnable() = default;
+
+    // The method to be implemented by thread clients
+    // and be scheduled by LocThread
+    // This method will be repeated called until it returns false; or
+    // until thread is stopped.
+    virtual bool run() = 0;
+
+    // The method to be run before thread loop (conditionally repeatedly)
+    // calls run()
+    inline virtual void prerun() {}
+
+    // The method to be run after thread loop (conditionally repeatedly)
+    // calls run()
+    inline virtual void postrun() {}
+
+    // The method to wake up the potential blocking thread
+    // no op if not applicable
+    inline virtual void interrupt() = 0;
+};
+
+// opaque class to provide service implementation.
+class LocThreadDelegate;
+
+// A utility class to create a thread and run LocRunnable
+// caller passes in.
+class LocThread {
+    LocThreadDelegate* mThread;
+public:
+    inline LocThread() : mThread(NULL) {}
+    inline virtual ~LocThread() { stop(); }
+
+    // client starts thread with a runnable, which implements
+    // the logics to fun in the created thread context.
+    // The thread is always detached.
+    // runnable is an obj managed by client. Client creates and
+    //          frees it (but must be after stop() is called, or
+    //          this LocThread obj is deleted).
+    //          The obj will be deleted by LocThread if start()
+    //          returns true. Else it is client's responsibility
+    //          to delete the object
+    // Returns 0 if success; false if failure.
+    bool start(const char* threadName, shared_ptr<LocRunnable> runnable);
+
+    void stop();
+
+    // thread status check
+    inline bool isRunning() { return NULL != mThread; }
+};
+
+} // loc_util
+#endif //__LOC_THREAD__
diff --git a/gps/utils/LocTimer.cpp b/gps/utils/LocTimer.cpp
new file mode 100644
index 0000000..915cf54
--- /dev/null
+++ b/gps/utils/LocTimer.cpp
@@ -0,0 +1,648 @@
+/* Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/timerfd.h>
+#include <sys/epoll.h>
+#include <log_util.h>
+#include <loc_timer.h>
+#include <LocTimer.h>
+#include <LocHeap.h>
+#include <LocThread.h>
+#include <LocSharedLock.h>
+#include <MsgTask.h>
+
+#ifdef __HOST_UNIT_TEST__
+#define EPOLLWAKEUP 0
+#define CLOCK_BOOTTIME CLOCK_MONOTONIC
+#define CLOCK_BOOTTIME_ALARM CLOCK_MONOTONIC
+#endif
+
+namespace loc_util {
+
+/*
+There are implementations of 5 classes in this file:
+LocTimer, LocTimerDelegate, LocTimerContainer, LocTimerPollTask, LocTimerWrapper
+
+LocTimer - client front end, interface for client to start / stop timers, also
+           to provide a callback.
+LocTimerDelegate - an internal timer entity, which also is a LocRankable obj.
+                   Its life cycle is different than that of LocTimer. It gets
+                   created when LocTimer::start() is called, and gets deleted
+                   when it expires or clients calls the hosting LocTimer obj's
+                   stop() method. When a LocTimerDelegate obj is ticking, it
+                   stays in the corresponding LocTimerContainer. When expired
+                   or stopped, the obj is removed from the container. Since it
+                   is also a LocRankable obj, and LocTimerContainer also is a
+                   heap, its ranks() implementation decides where it is placed
+                   in the heap.
+LocTimerContainer - core of the timer service. It is a container (derived from
+                    LocHeap) for LocTimerDelegate (implements LocRankable) objs.
+                    There are 2 of such containers, one for sw timers (or Linux
+                    timers) one for hw timers (or Linux alarms). It adds one of
+                    each (those that expire the soonest) to kernel via services
+                    provided by LocTimerPollTask. All the heap management on the
+                    LocTimerDelegate objs are done in the MsgTask context, such
+                    that synchronization is ensured.
+LocTimerPollTask - is a class that wraps timerfd and epoll POXIS APIs. It also
+                   both implements LocRunnalbe with epoll_wait() in the run()
+                   method. It is also a LocThread client, so as to loop the run
+                   method.
+LocTimerWrapper - a LocTimer client itself, to implement the existing C API with
+                  APIs, loc_timer_start() and loc_timer_stop().
+
+*/
+
+class LocTimerPollTask;
+
+// This is a multi-functaional class that:
+// * extends the LocHeap class for the detection of head update upon add / remove
+//   events. When that happens, soonest time out changes, so timerfd needs update.
+// * contains the timers, and add / remove them into the heap
+// * provides and maps 2 of such containers, one for timers (or  mSwTimers), one
+//   for alarms (or mHwTimers);
+// * provides a polling thread;
+// * provides a MsgTask thread for synchronized add / remove / timer client callback.
+class LocTimerContainer : public LocHeap {
+    // mutex to synchronize getters of static members
+    static pthread_mutex_t mMutex;
+    // Container of timers
+    static LocTimerContainer* mSwTimers;
+    // Container of alarms
+    static LocTimerContainer* mHwTimers;
+    // Msg task to provider msg Q, sender and reader.
+    static MsgTask* mMsgTask;
+    // Poll task to provide epoll call and threading to poll.
+    static LocTimerPollTask* mPollTask;
+    // timer / alarm fd
+    int mDevFd;
+    // ctor
+    LocTimerContainer(bool wakeOnExpire);
+    // dtor
+    ~LocTimerContainer();
+    static MsgTask* getMsgTaskLocked();
+    static LocTimerPollTask* getPollTaskLocked();
+    // extend LocHeap and pop if the top outRanks input
+    LocTimerDelegate* popIfOutRanks(LocTimerDelegate& timer);
+    // update the timer POSIX calls with updated soonest timer spec
+    void updateSoonestTime(LocTimerDelegate* priorTop);
+
+public:
+    // factory method to control the creation of mSwTimers / mHwTimers
+    static LocTimerContainer* get(bool wakeOnExpire);
+
+    LocTimerDelegate* getSoonestTimer();
+    int getTimerFd();
+    // add a timer / alarm obj into the container
+    void add(LocTimerDelegate& timer);
+    // remove a timer / alarm obj from the container
+    void remove(LocTimerDelegate& timer);
+    // handling of timer / alarm expiration
+    void expire();
+};
+
+class TimerRunnable : public LocRunnable {
+    const int mFd;
+public:
+    inline TimerRunnable(const int fd) : mFd(fd) {}
+    // The method to be implemented by thread clients
+    // and be scheduled by LocThread
+    // This method will be repeated called until it returns false; or
+    // until thread is stopped.
+    virtual bool run() override;
+
+    // The method to wake up the potential blocking thread
+    // no op if not applicable
+    inline virtual void interrupt() { close(mFd); }
+};
+
+// This class implements the polling thread that epolls imer / alarm fds.
+// The LocRunnable::run() contains the actual polling.  The other methods
+// will be run in the caller's thread context to add / remove timer / alarm
+// fds the kernel, while the polling is blocked on epoll_wait() call.
+// Since the design is that we have maximally 2 polls, one for all the
+// timers; one for all the alarms, we will poll at most on 2 fds.  But it
+// is possile that all we have are only timers or alarms at one time, so we
+// allow dynamically add / remove fds we poll on. The design decision of
+// having 1 fd per container of timer / alarm is such that, we may not need
+// to make a system call each time a timer / alarm is added / removed, unless
+// that changes the "soonest" time out of that of all the timers / alarms.
+class LocTimerPollTask {
+    // the epoll fd
+    const int mFd;
+    // the thread that calls TimerRunnable::run() method, where
+    // epoll_wait() is blocking and waiting for events..
+    LocThread mThread;
+public:
+    // ctor
+    LocTimerPollTask();
+    // dtor
+    ~LocTimerPollTask() = default;
+    // add a container of timers. Each contain has a unique device fd, i.e.
+    // either timer or alarm fd, and a heap of timers / alarms. It is expected
+    // that container would have written to the device fd with the soonest
+    // time out value in the heap at the time of calling this method. So all
+    // this method does is to add the fd of the input container to the poll
+    // and also add the pointer of the container to the event data ptr, such
+    // when poll_wait wakes up on events, we know who is the owner of the fd.
+    void addPoll(LocTimerContainer& timerContainer);
+    // remove a fd that is assciated with a container. The expectation is that
+    // the atual timer would have been removed from the container.
+    void removePoll(LocTimerContainer& timerContainer);
+};
+
+// Internal class of timer obj. It gets born when client calls LocTimer::start();
+// and gets deleted when client calls LocTimer::stop() or when the it expire()'s.
+// This class implements LocRankable::ranks() so that when an obj is added into
+// the container (of LocHeap), it gets placed in sorted order.
+class LocTimerDelegate : public LocRankable {
+    friend class LocTimerContainer;
+    friend class LocTimer;
+    LocTimer* mClient;
+    LocSharedLock* mLock;
+    struct timespec mFutureTime;
+    LocTimerContainer* mContainer;
+    // not a complete obj, just ctor for LocRankable comparisons
+    inline LocTimerDelegate(struct timespec& delay)
+        : mClient(NULL), mLock(NULL), mFutureTime(delay), mContainer(NULL) {}
+    inline ~LocTimerDelegate() { if (mLock) { mLock->drop(); mLock = NULL; } }
+public:
+    LocTimerDelegate(LocTimer& client, struct timespec& futureTime, LocTimerContainer* container);
+    void destroyLocked();
+    // LocRankable virtual method
+    virtual int ranks(LocRankable& rankable);
+    void expire();
+    inline struct timespec getFutureTime() { return mFutureTime; }
+};
+
+/***************************LocTimerContainer methods***************************/
+
+// Most of these static recources are created on demand. They however are never
+// destoyed. The theory is that there are processes that link to this util lib
+// but never use timer, then these resources would never need to be created.
+// For those processes that do use timer, it will likely also need to every
+// once in a while. It might be cheaper keeping them around.
+pthread_mutex_t LocTimerContainer::mMutex = PTHREAD_MUTEX_INITIALIZER;
+LocTimerContainer* LocTimerContainer::mSwTimers = NULL;
+LocTimerContainer* LocTimerContainer::mHwTimers = NULL;
+MsgTask* LocTimerContainer::mMsgTask = NULL;
+LocTimerPollTask* LocTimerContainer::mPollTask = NULL;
+
+// ctor - initialize timer heaps
+// A container for swTimer (timer) is created, when wakeOnExpire is true; or
+// HwTimer (alarm), when wakeOnExpire is false.
+LocTimerContainer::LocTimerContainer(bool wakeOnExpire) :
+    mDevFd(timerfd_create(wakeOnExpire ? CLOCK_BOOTTIME_ALARM : CLOCK_BOOTTIME, 0)) {
+
+    if ((-1 == mDevFd) && (errno == EINVAL)) {
+        LOC_LOGW("%s: timerfd_create failure, fallback to CLOCK_MONOTONIC - %s",
+            __FUNCTION__, strerror(errno));
+        mDevFd = timerfd_create(CLOCK_MONOTONIC, 0);
+    }
+
+    if (-1 != mDevFd) {
+        // ensure we have the necessary resources created
+        LocTimerContainer::getPollTaskLocked();
+        LocTimerContainer::getMsgTaskLocked();
+    } else {
+        LOC_LOGE("%s: timerfd_create failure - %s", __FUNCTION__, strerror(errno));
+    }
+}
+
+// dtor
+// we do not ever destroy the static resources.
+inline
+LocTimerContainer::~LocTimerContainer() {
+    close(mDevFd);
+}
+
+LocTimerContainer* LocTimerContainer::get(bool wakeOnExpire) {
+    // get the reference of either mHwTimer or mSwTimers per wakeOnExpire
+    LocTimerContainer*& container = wakeOnExpire ? mHwTimers : mSwTimers;
+    // it is cheap to check pointer first than locking mutext unconditionally
+    if (!container) {
+        pthread_mutex_lock(&mMutex);
+        // let's check one more time to be safe
+        if (!container) {
+            container = new LocTimerContainer(wakeOnExpire);
+            // timerfd_create failure
+            if (-1 == container->getTimerFd()) {
+                delete container;
+                container = NULL;
+            }
+        }
+        pthread_mutex_unlock(&mMutex);
+    }
+    return container;
+}
+
+MsgTask* LocTimerContainer::getMsgTaskLocked() {
+    // it is cheap to check pointer first than locking mutext unconditionally
+    if (!mMsgTask) {
+        mMsgTask = new MsgTask("LocTimerMsgTask");
+    }
+    return mMsgTask;
+}
+
+LocTimerPollTask* LocTimerContainer::getPollTaskLocked() {
+    // it is cheap to check pointer first than locking mutext unconditionally
+    if (!mPollTask) {
+        mPollTask = new LocTimerPollTask();
+    }
+    return mPollTask;
+}
+
+inline
+LocTimerDelegate* LocTimerContainer::getSoonestTimer() {
+    return (LocTimerDelegate*)(peek());
+}
+
+inline
+int LocTimerContainer::getTimerFd() {
+    return mDevFd;
+}
+
+void LocTimerContainer::updateSoonestTime(LocTimerDelegate* priorTop) {
+    LocTimerDelegate* curTop = getSoonestTimer();
+
+    // check if top has changed
+    if (curTop != priorTop) {
+        struct itimerspec delay;
+        memset(&delay, 0, sizeof(struct itimerspec));
+        bool toSetTime = false;
+        // if tree is empty now, we remove poll and disarm timer
+        if (!curTop) {
+            mPollTask->removePoll(*this);
+            // setting the values to disarm timer
+            delay.it_value.tv_sec = 0;
+            delay.it_value.tv_nsec = 0;
+            toSetTime = true;
+        } else if (!priorTop || curTop->outRanks(*priorTop)) {
+            // do this first to avoid race condition, in case settime is called
+            // with too small an interval
+            mPollTask->addPoll(*this);
+            delay.it_value = curTop->getFutureTime();
+            toSetTime = true;
+        }
+        if (toSetTime) {
+            timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL);
+        }
+    }
+}
+
+// all the heap management is done in the MsgTask context.
+inline
+void LocTimerContainer::add(LocTimerDelegate& timer) {
+    struct MsgTimerPush : public LocMsg {
+        LocTimerContainer* mTimerContainer;
+        LocTimerDelegate* mTimer;
+        inline MsgTimerPush(LocTimerContainer& container, LocTimerDelegate& timer) :
+            LocMsg(), mTimerContainer(&container), mTimer(&timer) {}
+        inline virtual void proc() const {
+            LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer();
+            mTimerContainer->push((LocRankable&)(*mTimer));
+            mTimerContainer->updateSoonestTime(priorTop);
+        }
+    };
+
+    mMsgTask->sendMsg(new MsgTimerPush(*this, timer));
+}
+
+// all the heap management is done in the MsgTask context.
+void LocTimerContainer::remove(LocTimerDelegate& timer) {
+    struct MsgTimerRemove : public LocMsg {
+        LocTimerContainer* mTimerContainer;
+        LocTimerDelegate* mTimer;
+        inline MsgTimerRemove(LocTimerContainer& container, LocTimerDelegate& timer) :
+            LocMsg(), mTimerContainer(&container), mTimer(&timer) {}
+        inline virtual void proc() const {
+            LocTimerDelegate* priorTop = mTimerContainer->getSoonestTimer();
+
+            // update soonest timer only if mTimer is actually removed from
+            // mTimerContainer AND mTimer is not priorTop.
+            if (priorTop == ((LocHeap*)mTimerContainer)->remove((LocRankable&)*mTimer)) {
+                // if passing in NULL, we tell updateSoonestTime to update
+                // kernel with the current top timer interval.
+                mTimerContainer->updateSoonestTime(NULL);
+            }
+            // all timers are deleted here, and only here.
+            delete mTimer;
+        }
+    };
+
+    mMsgTask->sendMsg(new MsgTimerRemove(*this, timer));
+}
+
+// all the heap management is done in the MsgTask context.
+// Upon expire, we check and continuously pop the heap until
+// the top node's timeout is in the future.
+void LocTimerContainer::expire() {
+    struct MsgTimerExpire : public LocMsg {
+        LocTimerContainer* mTimerContainer;
+        inline MsgTimerExpire(LocTimerContainer& container) :
+            LocMsg(), mTimerContainer(&container) {}
+        inline virtual void proc() const {
+            struct timespec now;
+            // get time spec of now
+            clock_gettime(CLOCK_BOOTTIME, &now);
+            LocTimerDelegate timerOfNow(now);
+            // pop everything in the heap that outRanks now, i.e. has time older than now
+            // and then call expire() on that timer.
+            for (LocTimerDelegate* timer = (LocTimerDelegate*)mTimerContainer->pop();
+                 NULL != timer;
+                 timer = mTimerContainer->popIfOutRanks(timerOfNow)) {
+                // the timer delegate obj will be deleted before the return of this call
+                timer->expire();
+            }
+            mTimerContainer->updateSoonestTime(NULL);
+        }
+    };
+
+    struct itimerspec delay;
+    memset(&delay, 0, sizeof(struct itimerspec));
+    timerfd_settime(getTimerFd(), TFD_TIMER_ABSTIME, &delay, NULL);
+    mPollTask->removePoll(*this);
+    mMsgTask->sendMsg(new MsgTimerExpire(*this));
+}
+
+LocTimerDelegate* LocTimerContainer::popIfOutRanks(LocTimerDelegate& timer) {
+    LocTimerDelegate* poppedNode = NULL;
+    if (mTree && !timer.outRanks(*peek())) {
+        poppedNode = (LocTimerDelegate*)(pop());
+    }
+
+    return poppedNode;
+}
+
+
+/***************************LocTimerPollTask methods***************************/
+
+inline
+LocTimerPollTask::LocTimerPollTask()
+    : mFd(epoll_create(2)), mThread() {
+    // before a next call returens, a thread will be created. The run() method
+    // could already be running in parallel. Also, since each of the objs
+    // creates a thread, the container will make sure that there will be only
+    // one of such obj for our timer implementation.
+    mThread.start("LocTimerPollTask", std::make_shared<TimerRunnable>(mFd));
+}
+
+void LocTimerPollTask::addPoll(LocTimerContainer& timerContainer) {
+    struct epoll_event ev;
+    memset(&ev, 0, sizeof(ev));
+
+    ev.events = EPOLLIN;
+    ev.data.fd = timerContainer.getTimerFd();
+    // it is important that we set this context pointer with the input
+    // timer container this is how we know which container should handle
+    // which expiration.
+    ev.data.ptr = &timerContainer;
+
+    epoll_ctl(mFd, EPOLL_CTL_ADD, timerContainer.getTimerFd(), &ev);
+}
+
+inline
+void LocTimerPollTask::removePoll(LocTimerContainer& timerContainer) {
+    epoll_ctl(mFd, EPOLL_CTL_DEL, timerContainer.getTimerFd(), NULL);
+}
+
+// The polling thread context will call this method. If run() method needs to
+// be repetitvely called, it must return true from the previous call.
+bool TimerRunnable::run() {
+    struct epoll_event ev[2];
+
+    // we have max 2 descriptors to poll from
+    int fds = epoll_wait(mFd, ev, 2, -1);
+
+    // we pretty much want to continually poll until the fd is closed
+    bool rerun = (fds > 0) || (errno == EINTR);
+
+    if (fds > 0) {
+        // we may have 2 events
+        for (int i = 0; i < fds; i++) {
+            // each fd has a context pointer associated with the right timer container
+            LocTimerContainer* container = (LocTimerContainer*)(ev[i].data.ptr);
+            if (container) {
+                container->expire();
+            } else {
+                epoll_ctl(mFd, EPOLL_CTL_DEL, ev[i].data.fd, NULL);
+            }
+        }
+    }
+
+    // if rerun is true, we are requesting to be scheduled again
+    return rerun;
+}
+
+/***************************LocTimerDelegate methods***************************/
+
+inline
+LocTimerDelegate::LocTimerDelegate(LocTimer& client,
+                                   struct timespec& futureTime,
+                                   LocTimerContainer* container)
+    : mClient(&client),
+      mLock(mClient->mLock->share()),
+      mFutureTime(futureTime),
+      mContainer(container) {
+    // adding the timer into the container
+    mContainer->add(*this);
+}
+
+inline
+void LocTimerDelegate::destroyLocked() {
+    // client handle will likely be deleted soon after this
+    // method returns. Nulling this handle so that expire()
+    // won't call the callback on the dead handle any more.
+    mClient = NULL;
+
+    if (mContainer) {
+        LocTimerContainer* container = mContainer;
+        mContainer = NULL;
+        if (container) {
+            container->remove(*this);
+        }
+    } // else we do not do anything. No such *this* can be
+      // created and reached here with mContainer ever been
+      // a non NULL. So *this* must have reached the if clause
+      // once, and we want it reach there only once.
+}
+
+int LocTimerDelegate::ranks(LocRankable& rankable) {
+    int rank = -1;
+    LocTimerDelegate* timer = (LocTimerDelegate*)(&rankable);
+    if (timer) {
+        // larger time ranks lower!!!
+        // IOW, if input obj has bigger tv_sec/tv_nsec, this obj outRanks higher
+        rank = timer->mFutureTime.tv_sec - mFutureTime.tv_sec;
+        if(0 == rank)
+        {
+            //rank against tv_nsec for msec accuracy
+            rank = (int)(timer->mFutureTime.tv_nsec - mFutureTime.tv_nsec);
+        }
+    }
+    return rank;
+}
+
+inline
+void LocTimerDelegate::expire() {
+    // keeping a copy of client pointer to be safe
+    // when timeOutCallback() is called at the end of this
+    // method, *this* obj may be already deleted.
+    LocTimer* client = mClient;
+    // force a stop, which will lead to delete of this obj
+    if (client && client->stop()) {
+        // calling client callback with a pointer save on the stack
+        // only if stop() returns true, i.e. it hasn't been stopped
+        // already.
+        client->timeOutCallback();
+    }
+}
+
+
+/***************************LocTimer methods***************************/
+LocTimer::LocTimer() : mTimer(NULL), mLock(new LocSharedLock()) {
+}
+
+LocTimer::~LocTimer() {
+    stop();
+    if (mLock) {
+        mLock->drop();
+        mLock = NULL;
+    }
+}
+
+bool LocTimer::start(unsigned int timeOutInMs, bool wakeOnExpire) {
+    bool success = false;
+    mLock->lock();
+    if (!mTimer) {
+        struct timespec futureTime;
+        clock_gettime(CLOCK_BOOTTIME, &futureTime);
+        futureTime.tv_sec += timeOutInMs / 1000;
+        futureTime.tv_nsec += (timeOutInMs % 1000) * 1000000;
+        if (futureTime.tv_nsec >= 1000000000) {
+            futureTime.tv_sec += futureTime.tv_nsec / 1000000000;
+            futureTime.tv_nsec %= 1000000000;
+        }
+
+        LocTimerContainer* container;
+        container = LocTimerContainer::get(wakeOnExpire);
+        if (NULL != container) {
+            mTimer = new LocTimerDelegate(*this, futureTime, container);
+            // if mTimer is non 0, success should be 0; or vice versa
+        }
+        success = (NULL != mTimer);
+    }
+    mLock->unlock();
+    return success;
+}
+
+bool LocTimer::stop() {
+    bool success = false;
+    mLock->lock();
+    if (mTimer) {
+        LocTimerDelegate* timer = mTimer;
+        mTimer = NULL;
+        if (timer) {
+            timer->destroyLocked();
+            success = true;
+        }
+    }
+    mLock->unlock();
+    return success;
+}
+
+/***************************LocTimerWrapper methods***************************/
+//////////////////////////////////////////////////////////////////////////
+// This section below wraps for the C style APIs
+//////////////////////////////////////////////////////////////////////////
+class LocTimerWrapper : public LocTimer {
+    loc_timer_callback mCb;
+    void* mCallerData;
+    LocTimerWrapper* mMe;
+    static pthread_mutex_t mMutex;
+    inline ~LocTimerWrapper() { mCb = NULL; mMe = NULL; }
+public:
+    inline LocTimerWrapper(loc_timer_callback cb, void* callerData) :
+        mCb(cb), mCallerData(callerData), mMe(this) {
+    }
+    void destroy() {
+        pthread_mutex_lock(&mMutex);
+        if (NULL != mCb && this == mMe) {
+            delete this;
+        }
+        pthread_mutex_unlock(&mMutex);
+    }
+    virtual void timeOutCallback() {
+        loc_timer_callback cb = mCb;
+        void* callerData = mCallerData;
+        if (cb) {
+            cb(callerData, 0);
+        }
+        destroy();
+    }
+};
+
+} // namespace loc_util
+
+//////////////////////////////////////////////////////////////////////////
+// This section below wraps for the C style APIs
+//////////////////////////////////////////////////////////////////////////
+
+using loc_util::LocTimerWrapper;
+
+pthread_mutex_t LocTimerWrapper::mMutex = PTHREAD_MUTEX_INITIALIZER;
+
+void* loc_timer_start(uint64_t msec, loc_timer_callback cb_func,
+                      void *caller_data, bool wake_on_expire)
+{
+    LocTimerWrapper* locTimerWrapper = NULL;
+
+    if (cb_func) {
+        locTimerWrapper = new LocTimerWrapper(cb_func, caller_data);
+
+        if (locTimerWrapper) {
+            locTimerWrapper->start(msec, wake_on_expire);
+        }
+    }
+
+    return locTimerWrapper;
+}
+
+void loc_timer_stop(void*&  handle)
+{
+    if (handle) {
+        LocTimerWrapper* locTimerWrapper = (LocTimerWrapper*)(handle);
+        locTimerWrapper->destroy();
+        handle = NULL;
+    }
+}
diff --git a/gps/utils/LocTimer.h b/gps/utils/LocTimer.h
new file mode 100644
index 0000000..c883de2
--- /dev/null
+++ b/gps/utils/LocTimer.h
@@ -0,0 +1,78 @@
+/* Copyright (c) 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __LOC_TIMER_CPP_H__
+#define __LOC_TIMER_CPP_H__
+
+#include <stddef.h>
+#include <loc_pla.h>
+
+namespace loc_util {
+
+// opaque class to provide service implementation.
+class LocTimerDelegate;
+class LocSharedLock;
+
+// LocTimer client must extend this class and implementthe callback.
+// start() / stop() methods are to arm / disarm timer.
+class LocTimer
+{
+    LocTimerDelegate* mTimer;
+    LocSharedLock* mLock;
+    // don't really want mLock to be manipulated by clients, yet LocTimer
+    // has to have a reference to the lock so that the delete of LocTimer
+    // and LocTimerDelegate can work together on their share resources.
+    friend class LocTimerDelegate;
+
+public:
+    LocTimer();
+    virtual ~LocTimer();
+
+    // timeOutInMs:  timeout delay in ms
+    // wakeOnExpire: true if to wake up CPU (if sleeping) upon timer
+    //                        expiration and notify the client.
+    //               false if to wait until next time CPU wakes up (if
+    //                        sleeping) and then notify the client.
+    // return:       true on success;
+    //               false on failure, e.g. timer is already running.
+    bool start(uint32_t timeOutInMs, bool wakeOnExpire);
+
+    // return:       true on success;
+    //               false on failure, e.g. timer is not running.
+    bool stop();
+
+    //  LocTimer client Should implement this method.
+    //  This method is used for timeout calling back to client. This method
+    //  should be short enough (eg: send a message to your own thread).
+    virtual void timeOutCallback() = 0;
+};
+
+} // namespace loc_util
+
+#endif //__LOC_DELAY_H__
diff --git a/gps/utils/LocUnorderedSetMap.h b/gps/utils/LocUnorderedSetMap.h
new file mode 100644
index 0000000..7b25ad0
--- /dev/null
+++ b/gps/utils/LocUnorderedSetMap.h
@@ -0,0 +1,201 @@
+/* Copyright (c) 2015, 2017, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __LOC_UNORDERDED_SETMAP_H__
+#define __LOC_UNORDERDED_SETMAP_H__
+
+#include <algorithm>
+#include <loc_pla.h>
+
+#ifdef NO_UNORDERED_SET_OR_MAP
+    #include <set>
+    #include <map>
+#else
+    #include <unordered_set>
+    #include <unordered_map>
+#endif
+
+using std::unordered_set;
+using std::unordered_map;
+
+namespace loc_util {
+
+// Trim from *fromSet* any elements that also exist in *rVals*.
+// The optional *goneVals*, if not null, will be populated with removed elements.
+template <typename T>
+inline static void trimSet(unordered_set<T>& fromSet, const unordered_set<T>& rVals,
+                           unordered_set<T>* goneVals) {
+    for (auto val : rVals) {
+        if (fromSet.erase(val) > 0 && nullptr != goneVals) {
+            goneVals->insert(val);
+        }
+    }
+}
+
+// this method is destructive to the input unordered_sets.
+// the return set is the interset extracted out from the two input sets, *s1* and *s2*.
+// *s1* and *s2* will be left with the intersect removed from them.
+template <typename T>
+static unordered_set<T> removeAndReturnInterset(unordered_set<T>& s1, unordered_set<T>& s2) {
+    unordered_set<T> common = {};
+    for (auto b = s2.begin(); b != s2.end(); b++) {
+        auto a = find(s1.begin(), s1.end(), *b);
+        if (a != s1.end()) {
+            // this is a common item of both l1 and l2, remove from both
+            // but after we add to common
+            common.insert(*a);
+            s1.erase(a);
+            s2.erase(b);
+        }
+    }
+    return common;
+}
+
+template <typename KEY, typename VAL>
+class LocUnorderedSetMap {
+    unordered_map<KEY, unordered_set<VAL>> mMap;
+
+    // Trim the VALs pointed to by *iter*, with everything that also exist in *rVals*.
+    // If the set becomes empty, remove the map entry. *goneVals*, if not null, records
+    // the trimmed VALs.
+    bool trimOrRemove(typename unordered_map<KEY, unordered_set<VAL>>::iterator iter,
+                      const unordered_set<VAL>& rVals, unordered_set<VAL>* goneVals) {
+        trimSet<VAL>(iter->second, rVals, goneVals);
+        bool removeEntry = (iter->second.empty());
+        if (removeEntry) {
+            mMap.erase(iter);
+        }
+        return removeEntry;
+    }
+
+public:
+    inline LocUnorderedSetMap() {}
+    inline LocUnorderedSetMap(size_t size) : LocUnorderedSetMap() {
+        mMap.get_allocator().allocate(size);
+    }
+
+    inline bool empty() { return mMap.empty(); }
+
+    // This gets the raw pointer to the VALs pointed to by *key*
+    // If the entry is not in the map, nullptr will be returned.
+    inline unordered_set<VAL>* getValSetPtr(const KEY& key) {
+        auto entry = mMap.find(key);
+        return (entry != mMap.end()) ? &(entry->second) : nullptr;
+    }
+
+    //  This gets a copy of VALs pointed to by *key*
+    // If the entry is not in the map, an empty set will be returned.
+    inline unordered_set<VAL> getValSet(const KEY& key) {
+        auto entry = mMap.find(key);
+        return (entry != mMap.end()) ? entry->second : unordered_set<VAL>{};
+    }
+
+    // This gets all the KEYs from the map
+    inline unordered_set<KEY> getKeys() {
+        unordered_set<KEY> keys = {};
+        for (auto entry : mMap) {
+            keys.insert(entry.first);
+        }
+        return keys;
+    }
+
+    inline bool remove(const KEY& key) {
+        return mMap.erase(key) > 0;
+    }
+
+    // This looks into all the entries keyed by *keys*. Remove any VALs from the entries
+    // that also exist in *rVals*. If the entry is left with an empty set, the entry will
+    // be removed. The optional parameters *goneKeys* and *goneVals* will record the KEYs
+    // (or entries) and the collapsed VALs removed from the map, respectively.
+    inline void trimOrRemove(unordered_set<KEY>&& keys, const unordered_set<VAL>& rVals,
+                             unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
+        trimOrRemove(keys, rVals, goneKeys, goneVals);
+    }
+
+    inline void trimOrRemove(unordered_set<KEY>& keys, const unordered_set<VAL>& rVals,
+                             unordered_set<KEY>* goneKeys, unordered_set<VAL>* goneVals) {
+        for (auto key : keys) {
+            auto iter = mMap.find(key);
+            if (iter != mMap.end() && trimOrRemove(iter, rVals, goneVals) && nullptr != goneKeys) {
+                goneKeys->insert(iter->first);
+            }
+        }
+    }
+
+    // This adds all VALs from *newVals* to the map entry keyed by *key*. Or if it
+    // doesn't exist yet, add the set to the map.
+    bool add(const KEY& key, const unordered_set<VAL>& newVals) {
+        bool newEntryAdded = false;
+        if (!newVals.empty()) {
+            auto iter = mMap.find(key);
+            if (iter != mMap.end()) {
+                iter->second.insert(newVals.begin(), newVals.end());
+            } else {
+                mMap[key] = newVals;
+                newEntryAdded = true;
+            }
+        }
+        return newEntryAdded;
+    }
+
+    // This adds to each of entries in the map keyed by *keys* with the VALs in the
+    // *enwVals*. If there new entries added (new key in *keys*), *newKeys*, if not
+    // null, would be populated with those keys.
+    inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>&& newVals,
+                    unordered_set<KEY>* newKeys) {
+        add(keys, newVals, newKeys);
+    }
+
+    inline void add(const unordered_set<KEY>& keys, const unordered_set<VAL>& newVals,
+                    unordered_set<KEY>* newKeys) {
+        for (auto key : keys) {
+            if (add(key, newVals) && nullptr != newKeys) {
+                newKeys->insert(key);
+            }
+        }
+    }
+
+    // This puts *newVals* into the map keyed by *key*, and returns the VALs that are
+    // in effect removed from the keyed VAL set in the map entry.
+    // This call would also remove those same VALs from *newVals*.
+    inline unordered_set<VAL> update(const KEY& key, unordered_set<VAL>& newVals) {
+        unordered_set<VAL> goneVals = {};
+        if (newVals.empty()) {
+            mMap.erase(key);
+        } else {
+            auto curVals = mMap[key];
+            mMap[key] = newVals;
+            goneVals = removeAndReturnInterset(curVals, newVals);
+        }
+        return goneVals;
+    }
+};
+
+} // namespace loc_util
+
+#endif // #ifndef __LOC_UNORDERDED_SETMAP_H__
diff --git a/gps/utils/LogBuffer.cpp b/gps/utils/LogBuffer.cpp
new file mode 100644
index 0000000..c280c82
--- /dev/null
+++ b/gps/utils/LogBuffer.cpp
@@ -0,0 +1,189 @@
+/* Copyright (c) 2019 - 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "LogBuffer.h"
+#ifdef USE_GLIB
+#include <execinfo.h>
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "LocSvc_LogBuffer"
+
+namespace loc_util {
+
+LogBuffer* LogBuffer::mInstance;
+struct sigaction LogBuffer::mOriSigAction[NSIG];
+struct sigaction LogBuffer::mNewSigAction;
+mutex LogBuffer::sLock;
+
+LogBuffer* LogBuffer::getInstance() {
+    if (mInstance == nullptr) {
+        lock_guard<mutex> guard(sLock);
+        if (mInstance == nullptr) {
+            mInstance = new LogBuffer();
+        }
+    }
+    return mInstance;
+}
+
+LogBuffer::LogBuffer(): mLogList(TOTAL_LOG_LEVELS),
+        mConfigVec(TOTAL_LOG_LEVELS, ConfigsInLevel(TIME_DEPTH_THRESHOLD_MINIMAL_IN_SEC,
+                    MAXIMUM_NUM_IN_LIST, 0)) {
+    loc_param_s_type log_buff_config_table[] =
+    {
+        {"E_LEVEL_TIME_DEPTH",      &mConfigVec[0].mTimeDepthThres,  NULL, 'n'},
+        {"E_LEVEL_MAX_CAPACITY",    &mConfigVec[0].mMaxNumThres,     NULL, 'n'},
+        {"W_LEVEL_TIME_DEPTH",      &mConfigVec[1].mTimeDepthThres,  NULL, 'n'},
+        {"W_LEVEL_MAX_CAPACITY",    &mConfigVec[1].mMaxNumThres,     NULL, 'n'},
+        {"I_LEVEL_TIME_DEPTH",      &mConfigVec[2].mTimeDepthThres,  NULL, 'n'},
+        {"I_LEVEL_MAX_CAPACITY",    &mConfigVec[2].mMaxNumThres,     NULL, 'n'},
+        {"D_LEVEL_TIME_DEPTH",      &mConfigVec[3].mTimeDepthThres,  NULL, 'n'},
+        {"D_LEVEL_MAX_CAPACITY",    &mConfigVec[3].mMaxNumThres,     NULL, 'n'},
+        {"V_LEVEL_TIME_DEPTH",      &mConfigVec[4].mTimeDepthThres,  NULL, 'n'},
+        {"V_LEVEL_MAX_CAPACITY",    &mConfigVec[4].mMaxNumThres,     NULL, 'n'},
+    };
+    loc_read_conf(LOC_PATH_GPS_CONF_STR, log_buff_config_table,
+            sizeof(log_buff_config_table)/sizeof(log_buff_config_table[0]));
+    registerSignalHandler();
+}
+
+void LogBuffer::append(string& data, int level, uint64_t timestamp) {
+    lock_guard<mutex> guard(mLock);
+    pair<uint64_t, string> item(timestamp, data);
+    mLogList.append(item, level);
+    mConfigVec[level].mCurrentSize++;
+
+    while ((timestamp - mLogList.front(level).first) > mConfigVec[level].mTimeDepthThres ||
+            mConfigVec[level].mCurrentSize > mConfigVec[level].mMaxNumThres) {
+        mLogList.pop(level);
+        mConfigVec[level].mCurrentSize--;
+    }
+}
+
+//Dump the log buffer of specific level, level = -1 to dump all the levels in log buffer.
+void LogBuffer::dump(std::function<void(stringstream&)> log, int level) {
+    lock_guard<mutex> guard(mLock);
+    list<pair<pair<uint64_t, string>, int>> li;
+    if (-1 == level) {
+        li = mLogList.dump();
+    } else {
+        li = mLogList.dump(level);
+    }
+    ALOGE("Begining of dump, buffer size: %d", (int)li.size());
+    stringstream ln;
+    ln << "dump log buffer, level[" << level << "]" << ", buffer size: " << li.size() << endl;
+    log(ln);
+    for_each (li.begin(), li.end(), [&, this](const pair<pair<uint64_t, string>, int> &item){
+        stringstream line;
+        line << "["<<item.first.first << "] ";
+        line << "Level " << mLevelMap[item.second] << ": ";
+        line << item.first.second << endl;
+        if (log != nullptr) {
+            log(line);
+        }
+    });
+    ALOGE("End of dump");
+}
+
+void LogBuffer::dumpToAdbLogcat() {
+    dump([](stringstream& line){
+        ALOGE("%s", line.str().c_str());
+    });
+}
+
+void LogBuffer::dumpToLogFile(string filePath) {
+    ALOGE("Dump GPS log buffer to file: %s", filePath.c_str());
+    fstream s;
+    s.open(filePath, std::fstream::out | std::fstream::app);
+    dump([&s](stringstream& line){
+        s << line.str();
+    });
+    s.close();
+}
+
+void LogBuffer::flush() {
+    mLogList.flush();
+}
+
+void LogBuffer::registerSignalHandler() {
+    ALOGE("Singal handler registered");
+    mNewSigAction.sa_sigaction = &LogBuffer::signalHandler;
+    mNewSigAction.sa_flags = SA_SIGINFO | SA_RESTART;
+    sigemptyset(&mNewSigAction.sa_mask);
+
+    sigaction(SIGINT, &mNewSigAction, &mOriSigAction[SIGINT]);
+    sigaction(SIGKILL, &mNewSigAction, &mOriSigAction[SIGKILL]);
+    sigaction(SIGSEGV, &mNewSigAction, &mOriSigAction[SIGSEGV]);
+    sigaction(SIGABRT, &mNewSigAction, &mOriSigAction[SIGABRT]);
+    sigaction(SIGTRAP, &mNewSigAction, &mOriSigAction[SIGTRAP]);
+    sigaction(SIGUSR1, &mNewSigAction, &mOriSigAction[SIGUSR1]);
+}
+
+void LogBuffer::signalHandler(const int code, siginfo_t *const si, void *const sc) {
+    ALOGE("[Gnss Log buffer]Singal handler, signal ID: %d", code);
+
+#ifdef USE_GLIB
+    int nptrs;
+    void *buffer[100];
+    char **strings;
+
+    nptrs = backtrace(buffer, sizeof(buffer)/sizeof(*buffer));
+    strings = backtrace_symbols(buffer, nptrs);
+    if (strings != NULL) {
+        timespec tv;
+        clock_gettime(CLOCK_BOOTTIME, &tv);
+        uint64_t elapsedTime = (uint64_t)tv.tv_sec + (uint64_t)tv.tv_nsec/1000000000;
+        for (int i = 0; i < nptrs; i++) {
+            string s(strings[i]);
+            mInstance->append(s, 0, elapsedTime);
+        }
+    }
+#endif
+    //Dump the log buffer to adb logcat
+    mInstance->dumpToAdbLogcat();
+
+    //Dump the log buffer to file
+    time_t now = time(NULL);
+    struct tm *curr_time = localtime(&now);
+    char path[50];
+    snprintf(path, 50, LOG_BUFFER_FILE_PATH "gpslog_%d%d%d-%d%d%d.log",
+            (1900 + curr_time->tm_year), ( 1 + curr_time->tm_mon), curr_time->tm_mday,
+            curr_time->tm_hour, curr_time->tm_min, curr_time->tm_sec);
+
+    mInstance->dumpToLogFile(path);
+
+    //Process won't be terminated if SIGUSR1 is recieved
+    if (code != SIGUSR1) {
+        mOriSigAction[code].sa_sigaction(code, si, sc);
+    }
+}
+
+}
diff --git a/gps/utils/LogBuffer.h b/gps/utils/LogBuffer.h
new file mode 100644
index 0000000..8d90439
--- /dev/null
+++ b/gps/utils/LogBuffer.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOG_BUFFER_H
+#define LOG_BUFFER_H
+
+#include "SkipList.h"
+#include "log_util.h"
+#include <loc_cfg.h>
+#include <loc_pla.h>
+#include <string>
+#include <sstream>
+#include <ostream>
+#include <fstream>
+#include <time.h>
+#include <mutex>
+#include <signal.h>
+#include <thread>
+#include <functional>
+
+//default error level time depth threshold,
+#define TIME_DEPTH_THRESHOLD_MINIMAL_IN_SEC 60
+//default maximum log buffer size
+#define MAXIMUM_NUM_IN_LIST 50
+//file path of dumped log buffer
+#define LOG_BUFFER_FILE_PATH "/data/vendor/location/"
+
+namespace loc_util {
+
+class ConfigsInLevel{
+public:
+    uint32_t mTimeDepthThres;
+    uint32_t mMaxNumThres;
+    int mCurrentSize;
+
+    ConfigsInLevel(uint32_t time, int num, int size):
+        mTimeDepthThres(time), mMaxNumThres(num), mCurrentSize(size) {}
+};
+
+class LogBuffer {
+private:
+    static LogBuffer* mInstance;
+    static struct sigaction mOriSigAction[NSIG];
+    static struct sigaction mNewSigAction;
+    static mutex sLock;
+
+    SkipList<pair<uint64_t, string>> mLogList;
+    vector<ConfigsInLevel> mConfigVec;
+    mutex mLock;
+
+    const vector<string> mLevelMap {"E", "W", "I", "D", "V"};
+
+public:
+    static LogBuffer* getInstance();
+    void append(string& data, int level, uint64_t timestamp);
+    void dump(std::function<void(stringstream&)> log, int level = -1);
+    void dumpToAdbLogcat();
+    void dumpToLogFile(string filePath);
+    void flush();
+private:
+    LogBuffer();
+    void registerSignalHandler();
+    static void signalHandler(const int code, siginfo_t *const si, void *const sc);
+
+};
+
+}
+
+#endif
diff --git a/gps/utils/Makefile.am b/gps/utils/Makefile.am
new file mode 100644
index 0000000..ada504c
--- /dev/null
+++ b/gps/utils/Makefile.am
@@ -0,0 +1,75 @@
+ACLOCAL_AMFLAGS = -I m4
+
+AM_CFLAGS = -Wundef \
+        -MD \
+        -Wno-trigraphs \
+        -g -O0 \
+        -fno-inline \
+        -fno-short-enums \
+        -fpic \
+         -I./ \
+         -std=c++14 \
+         $(LOCPLA_CFLAGS)
+
+libgps_utils_la_h_sources = \
+        msg_q.h \
+        linked_list.h \
+        loc_cfg.h \
+        loc_log.h \
+        loc_target.h \
+        loc_timer.h \
+        MsgTask.h \
+        LocHeap.h \
+        LocThread.h \
+        LocTimer.h \
+        LocIpc.h \
+        SkipList.h\
+        loc_misc_utils.h \
+        loc_nmea.h \
+        gps_extended_c.h \
+        gps_extended.h \
+        loc_gps.h \
+        log_util.h \
+        LocSharedLock.h \
+        LocUnorderedSetMap.h\
+        LocLoggerBase.h
+
+libgps_utils_la_c_sources = \
+        linked_list.c \
+        msg_q.c \
+        loc_cfg.cpp \
+        loc_log.cpp \
+        loc_target.cpp \
+        LocHeap.cpp \
+        LocTimer.cpp \
+        LocThread.cpp \
+        LocIpc.cpp \
+        LogBuffer.cpp \
+        MsgTask.cpp \
+        loc_misc_utils.cpp \
+        loc_nmea.cpp
+
+library_includedir = $(pkgincludedir)
+
+library_include_HEADERS = $(libgps_utils_la_h_sources)
+
+libgps_utils_la_SOURCES = $(libgps_utils_la_c_sources)
+
+if USE_GLIB
+libgps_utils_la_CFLAGS = -DUSE_GLIB $(AM_CFLAGS) @GLIB_CFLAGS@
+libgps_utils_la_LDFLAGS = -lstdc++ -Wl,-z,defs -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
+libgps_utils_la_CPPFLAGS = -DUSE_GLIB $(AM_CFLAGS) $(AM_CPPFLAGS) @GLIB_CFLAGS@
+else
+libgps_utils_la_CFLAGS = $(AM_CFLAGS)
+libgps_utils_la_LDFLAGS = -Wl,-z,defs -lpthread -shared -version-info 1:0:0
+libgps_utils_la_CPPFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS)
+endif
+
+libgps_utils_la_LIBADD = $(CUTILS_LIBS) -ldl
+
+#Create and Install libraries
+lib_LTLIBRARIES = libgps_utils.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = gps-utils.pc
+EXTRA_DIST = $(pkgconfig_DATA)
diff --git a/gps/utils/MsgTask.cpp b/gps/utils/MsgTask.cpp
new file mode 100644
index 0000000..6ef689a
--- /dev/null
+++ b/gps/utils/MsgTask.cpp
@@ -0,0 +1,120 @@
+/* Copyright (c) 2011-2013, 2015, 2017, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_MsgTask"
+
+#include <unistd.h>
+#include <MsgTask.h>
+#include <msg_q.h>
+#include <log_util.h>
+#include <loc_log.h>
+#include <loc_pla.h>
+
+namespace loc_util {
+
+class MTRunnable : public LocRunnable {
+    const void* mQ;
+public:
+    inline MTRunnable(const void* q) : mQ(q) {}
+    virtual ~MTRunnable();
+    // Overrides of LocRunnable methods
+    // This method will be repeated called until it returns false; or
+    // until thread is stopped.
+    virtual bool run() override;
+
+    // The method to be run before thread loop (conditionally repeatedly)
+    // calls run()
+    virtual void prerun() override;
+
+    // to interrupt the run() method and come out of that
+    virtual void interrupt() override;
+};
+
+static void LocMsgDestroy(void* msg) {
+    delete (LocMsg*)msg;
+}
+
+MsgTask::MsgTask(const char* threadName) :
+    mQ(msg_q_init2()), mThread() {
+    mThread.start(threadName, std::make_shared<MTRunnable>(mQ));
+}
+
+void MsgTask::sendMsg(const LocMsg* msg) const {
+    if (msg && this) {
+        msg_q_snd((void*)mQ, (void*)msg, LocMsgDestroy);
+    } else {
+        LOC_LOGE("%s: msg is %p and this is %p",
+                 __func__, msg, this);
+    }
+}
+
+void MsgTask::sendMsg(const std::function<void()> runnable) const {
+    struct RunMsg : public LocMsg {
+        const std::function<void()> mRunnable;
+    public:
+        inline RunMsg(const std::function<void()> runnable) : mRunnable(runnable) {}
+        ~RunMsg() = default;
+        inline virtual void proc() const override { mRunnable(); }
+    };
+    sendMsg(new RunMsg(runnable));
+}
+
+void MTRunnable::interrupt() {
+    msg_q_unblock((void*)mQ);
+}
+
+void MTRunnable::prerun() {
+    // make sure we do not run in background scheduling group
+     set_sched_policy(gettid(), SP_FOREGROUND);
+}
+
+bool MTRunnable::run() {
+    LocMsg* msg;
+    msq_q_err_type result = msg_q_rcv((void*)mQ, (void **)&msg);
+    if (eMSG_Q_SUCCESS != result) {
+        LOC_LOGE("%s:%d] fail receiving msg: %s\n", __func__, __LINE__,
+                 loc_get_msg_q_status(result));
+        return false;
+    }
+
+    msg->log();
+    // there is where each individual msg handling is invoked
+    msg->proc();
+
+    delete msg;
+
+    return true;
+}
+
+MTRunnable::~MTRunnable() {
+    msg_q_flush((void*)mQ);
+    msg_q_destroy((void**)&mQ);
+}
+
+} // namespace loc_util
diff --git a/gps/utils/MsgTask.h b/gps/utils/MsgTask.h
new file mode 100644
index 0000000..a8cce9e
--- /dev/null
+++ b/gps/utils/MsgTask.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2011-2013, 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef __MSG_TASK__
+#define __MSG_TASK__
+
+#include <functional>
+#include <LocThread.h>
+
+namespace loc_util {
+
+struct LocMsg {
+    inline LocMsg() {}
+    inline virtual ~LocMsg() {}
+    virtual void proc() const = 0;
+    inline virtual void log() const {}
+};
+
+class MsgTask {
+    const void* mQ;
+    LocThread mThread;
+public:
+    ~MsgTask() = default;
+    MsgTask(const char* threadName = NULL);
+    void sendMsg(const LocMsg* msg) const;
+    void sendMsg(const std::function<void()> runnable) const;
+};
+
+} //
+
+#endif //__MSG_TASK__
diff --git a/gps/utils/SkipList.h b/gps/utils/SkipList.h
new file mode 100644
index 0000000..afaa1a6
--- /dev/null
+++ b/gps/utils/SkipList.h
@@ -0,0 +1,158 @@
+/* Copyright (c) 2019 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOC_SKIP_LIST_H
+#define LOC_SKIP_LIST_H
+
+#include <stdlib.h>
+#include <list>
+#include <vector>
+#include <iostream>
+#include <algorithm>
+
+using namespace std;
+
+namespace loc_util {
+
+template <typename T,
+         template<typename elem, typename Allocator = std::allocator<elem>> class container = list>
+class SkipNode {
+public:
+    typedef typename container<SkipNode<T, container>>::iterator NodeIterator;
+
+    int mLevel;
+    T mData;
+    NodeIterator mNextInLevel;
+
+    SkipNode(int level, T& data): mLevel(level), mData(data) {}
+};
+
+template <typename T>
+class SkipList {
+    using NodeIterator = typename SkipNode<T>::NodeIterator;
+private:
+    list<SkipNode<T>> mMainList;
+    vector<NodeIterator> mHeadVec;
+    vector<NodeIterator> mTailVec;
+public:
+    SkipList(int totalLevels);
+    void append(T& data, int level);
+    void pop(int level);
+    void pop();
+    T front(int level);
+    int size();
+    void flush();
+    list<pair<T, int>> dump();
+    list<pair<T, int>> dump(int level);
+};
+
+template <typename T>
+SkipList<T>::SkipList(int totalLevels): mHeadVec(totalLevels, mMainList.end()),
+        mTailVec(totalLevels, mMainList.end()) {}
+
+template <typename T>
+void SkipList<T>::append(T& data, int level) {
+    if ( level < 0 || level >= mHeadVec.size()) {
+        return;
+    }
+
+    SkipNode<T> node(level, data);
+    node.mNextInLevel = mMainList.end();
+    mMainList.push_back(node);
+    auto iter = --mMainList.end();
+    if (mHeadVec[level] == mMainList.end()) {
+        mHeadVec[level] = iter;
+    } else {
+        (*mTailVec[level]).mNextInLevel = iter;
+    }
+    mTailVec[level] = iter;
+}
+
+template <typename T>
+void SkipList<T>::pop(int level) {
+    if (mHeadVec[level] == mMainList.end()) {
+        return;
+    }
+
+    if ((*mHeadVec[level]).mNextInLevel == mMainList.end()) {
+        mTailVec[level] = mMainList.end();
+    }
+
+    auto tmp_iter = (*mHeadVec[level]).mNextInLevel;
+    mMainList.erase(mHeadVec[level]);
+    mHeadVec[level] = tmp_iter;
+}
+
+template <typename T>
+void SkipList<T>::pop() {
+    pop(mMainList.front().mLevel);
+}
+
+template <typename T>
+T SkipList<T>::front(int level) {
+    return (*mHeadVec[level]).mData;
+}
+
+template <typename T>
+int SkipList<T>::size() {
+    return mMainList.size();
+}
+
+template <typename T>
+void SkipList<T>::flush() {
+    mMainList.clear();
+    for (int i = 0; i < mHeadVec.size(); i++) {
+        mHeadVec[i] = mMainList.end();
+        mTailVec[i] = mMainList.end();
+    }
+}
+
+template <typename T>
+list<pair<T, int>> SkipList<T>::dump() {
+    list<pair<T, int>> li;
+    for_each(mMainList.begin(), mMainList.end(), [&](SkipNode<T> &item) {
+        li.push_back(make_pair(item.mData, item.mLevel));
+    });
+    return li;
+}
+
+template <typename T>
+list<pair<T, int>> SkipList<T>::dump(int level) {
+    list<pair<T, int>> li;
+    auto head = mHeadVec[level];
+    while (head != mMainList.end()) {
+        li.push_back(make_pair((*head).mData, (*head).mLevel));
+        head = (*head).mNextInLevel;
+    }
+    return li;
+}
+
+}
+
+#endif
diff --git a/gps/utils/configure.ac b/gps/utils/configure.ac
new file mode 100644
index 0000000..2a04f45
--- /dev/null
+++ b/gps/utils/configure.ac
@@ -0,0 +1,92 @@
+# configure.ac -- Autoconf script for gps gps-utils
+#
+# Process this file with autoconf to produce a configure script
+
+# Requires autoconf tool later than 2.61
+AC_PREREQ(2.61)
+# Initialize the gps gps-utils package version 1.0.0
+AC_INIT([gps-utils],1.0.0)
+# Does not strictly follow GNU Coding standards
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+# Disables auto rebuilding of configure, Makefile.ins
+AM_MAINTAINER_MODE
+# Verifies the --srcdir is correct by checking for the path
+AC_CONFIG_SRCDIR([Makefile.am])
+# defines some macros variable to be included by source
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+AC_PROG_LIBTOOL
+AC_PROG_CXX
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_AWK
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+PKG_PROG_PKG_CONFIG
+
+AC_ARG_WITH([external_ap],
+    AC_HELP_STRING([--with-external_ap=@<:@dir@:>@],
+        [Using External Application Processor]),
+    [],
+    with_external_ap=no)
+
+if test "x$with_external_ap" != "xno"; then
+    CPPFLAGS="${CPPFLAGS} -DFEATURE_EXTERNAL_AP"
+else
+    # Checks for libraries.
+    PKG_CHECK_MODULES([CUTILS], [libcutils])
+    AC_SUBST([CUTILS_CFLAGS])
+    AC_SUBST([CUTILS_LIBS])
+fi
+
+AC_ARG_WITH([core_includes],
+      AC_HELP_STRING([--with-core-includes=@<:@dir@:>@],
+         [Specify the location of the core headers]),
+      [core_incdir=$withval],
+      with_core_includes=no)
+
+if test "x$with_core_includes" != "xno"; then
+   CPPFLAGS="${CPPFLAGS} -I${core_incdir}"
+fi
+
+AC_ARG_WITH([locpla_includes],
+      AC_HELP_STRING([--with-locpla-includes=@<:@dir@:>@],
+         [specify the path to locpla-includes in loc-pla_git.bb]),
+      [locpla_incdir=$withval],
+      with_locpla_includes=no)
+
+if test "x$with_locpla_includes" != "xno"; then
+   AC_SUBST(LOCPLA_CFLAGS, "-I${locpla_incdir}")
+fi
+
+AC_SUBST([CPPFLAGS])
+
+AC_ARG_WITH([glib],
+      AC_HELP_STRING([--with-glib],
+         [enable glib, building HLOS systems which use glib]))
+
+if (test "x${with_glib}" = "xyes"); then
+        AC_DEFINE(ENABLE_USEGLIB, 1, [Define if HLOS systems uses glib])
+        PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GThread >= 2.16 is required))
+        PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes,
+                                AC_MSG_ERROR(GLib >= 2.16 is required))
+        GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+        GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
+
+        AC_SUBST(GLIB_CFLAGS)
+        AC_SUBST(GLIB_LIBS)
+fi
+
+AM_CONDITIONAL(USE_GLIB, test "x${with_glib}" = "xyes")
+
+AC_CONFIG_FILES([ \
+        Makefile \
+        gps-utils.pc
+        ])
+
+AC_OUTPUT
diff --git a/gps/utils/gps-utils.pc.in b/gps/utils/gps-utils.pc.in
new file mode 100644
index 0000000..a988731
--- /dev/null
+++ b/gps/utils/gps-utils.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: gps-utils
+Description: QTI GPS Location utils
+Version: @VERSION
+Libs: -L${libdir} -lgps_utils
+Cflags: -I${includedir}/gps-utils
diff --git a/gps/utils/gps_extended.h b/gps/utils/gps_extended.h
new file mode 100644
index 0000000..2455629
--- /dev/null
+++ b/gps/utils/gps_extended.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GPS_EXTENDED_H
+#define GPS_EXTENDED_H
+
+/**
+ * @file
+ * @brief C++ declarations for GPS types
+ */
+
+#include <gps_extended_c.h>
+#if defined(USE_GLIB) || defined(OFF_TARGET)
+#include <string.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+
+struct LocPosMode
+{
+    LocPositionMode mode;
+    LocGpsPositionRecurrence recurrence;
+    uint32_t min_interval;
+    uint32_t preferred_accuracy;
+    uint32_t preferred_time;
+    bool share_position;
+    char credentials[14];
+    char provider[8];
+    GnssPowerMode powerMode;
+    uint32_t timeBetweenMeasurements;
+    LocPosMode(LocPositionMode m, LocGpsPositionRecurrence recr,
+               uint32_t gap, uint32_t accu, uint32_t time,
+               bool sp, const char* cred, const char* prov,
+               GnssPowerMode pMode = GNSS_POWER_MODE_INVALID,
+               uint32_t tbm = 0) :
+        mode(m), recurrence(recr),
+        min_interval(gap < GPS_MIN_POSSIBLE_FIX_INTERVAL_MS ?
+                     GPS_MIN_POSSIBLE_FIX_INTERVAL_MS : gap),
+        preferred_accuracy(accu), preferred_time(time),
+        share_position(sp), powerMode(pMode),
+        timeBetweenMeasurements(tbm) {
+        memset(credentials, 0, sizeof(credentials));
+        memset(provider, 0, sizeof(provider));
+        if (NULL != cred) {
+            memcpy(credentials, cred, sizeof(credentials)-1);
+        }
+        if (NULL != prov) {
+            memcpy(provider, prov, sizeof(provider)-1);
+        }
+    }
+
+    inline LocPosMode() :
+        mode(LOC_POSITION_MODE_MS_BASED),
+        recurrence(LOC_GPS_POSITION_RECURRENCE_PERIODIC),
+        min_interval(GPS_DEFAULT_FIX_INTERVAL_MS),
+        preferred_accuracy(50), preferred_time(120000),
+        share_position(true), powerMode(GNSS_POWER_MODE_INVALID),
+        timeBetweenMeasurements(GPS_DEFAULT_FIX_INTERVAL_MS) {
+        memset(credentials, 0, sizeof(credentials));
+        memset(provider, 0, sizeof(provider));
+    }
+
+    inline bool equals(const LocPosMode &anotherMode) const
+    {
+        return anotherMode.mode == mode &&
+            anotherMode.recurrence == recurrence &&
+            anotherMode.min_interval == min_interval &&
+            anotherMode.preferred_accuracy == preferred_accuracy &&
+            anotherMode.preferred_time == preferred_time &&
+            anotherMode.powerMode == powerMode &&
+            anotherMode.timeBetweenMeasurements == timeBetweenMeasurements &&
+            !strncmp(anotherMode.credentials, credentials, sizeof(credentials)-1) &&
+            !strncmp(anotherMode.provider, provider, sizeof(provider)-1);
+    }
+
+    void logv() const;
+};
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* GPS_EXTENDED_H */
+
diff --git a/gps/utils/gps_extended_c.h b/gps/utils/gps_extended_c.h
new file mode 100644
index 0000000..f368975
--- /dev/null
+++ b/gps/utils/gps_extended_c.h
@@ -0,0 +1,2429 @@
+/* Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GPS_EXTENDED_C_H
+#define GPS_EXTENDED_C_H
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <loc_gps.h>
+#include <LocationAPI.h>
+
+struct timespec32_t {
+  uint32_t  tv_sec;   /* seconds */
+  uint32_t  tv_nsec;  /* and nanoseconds */
+};
+
+
+/**
+ * @file
+ * @brief C++ declarations for GPS types
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** Location has valid source information. */
+#define LOCATION_HAS_SOURCE_INFO   0x0020
+/** LocGpsLocation has valid "is indoor?" flag */
+#define LOC_GPS_LOCATION_HAS_IS_INDOOR   0x0040
+/** LocGpsLocation has valid floor number */
+#define LOC_GPS_LOCATION_HAS_FLOOR_NUMBER   0x0080
+/** LocGpsLocation has valid map URL*/
+#define LOC_GPS_LOCATION_HAS_MAP_URL   0x0100
+/** LocGpsLocation has valid map index */
+#define LOC_GPS_LOCATION_HAS_MAP_INDEX   0x0200
+
+#define GNSS_INVALID_JAMMER_IND 0x7FFFFFFF
+
+/** Sizes for indoor fields */
+#define GPS_LOCATION_MAP_URL_SIZE 400
+#define GPS_LOCATION_MAP_INDEX_SIZE 16
+
+/** Position source is ULP */
+#define ULP_LOCATION_IS_FROM_HYBRID   0x0001
+/** Position source is GNSS only */
+#define ULP_LOCATION_IS_FROM_GNSS     0x0002
+/** Position is from a Geofence Breach Event */
+#define ULP_LOCATION_IS_FROM_GEOFENCE 0X0004
+/** Position is from Hardware FLP */
+#define ULP_LOCATION_IS_FROM_HW_FLP   0x0008
+/** Position is from NLP */
+#define ULP_LOCATION_IS_FROM_NLP      0x0010
+/** Position is from external DR solution*/
+#define ULP_LOCATION_IS_FROM_EXT_DR   0X0020
+/** Raw GNSS position fixes */
+#define ULP_LOCATION_IS_FROM_GNSS_RAW   0X0040
+
+typedef uint32_t LocSvInfoSource;
+/** SVinfo source is GNSS/DR */
+#define ULP_SVINFO_IS_FROM_GNSS       ((LocSvInfoSource)0x0001)
+/** Raw SVinfo from GNSS */
+#define ULP_SVINFO_IS_FROM_DR         ((LocSvInfoSource)0x0002)
+
+#define ULP_MIN_INTERVAL_INVALID 0xffffffff
+#define ULP_MAX_NMEA_STRING_SIZE 201
+
+/*Emergency SUPL*/
+#define LOC_GPS_NI_TYPE_EMERGENCY_SUPL    4
+
+#define LOC_AGPS_CERTIFICATE_MAX_LENGTH 2000
+#define LOC_AGPS_CERTIFICATE_MAX_SLOTS 10
+
+/* TBM Threshold for tracking in background power mode : in millis */
+#define TRACKING_TBM_THRESHOLD_MILLIS 480000
+
+/**  Maximum number of satellites in an ephemeris report.  */
+#define GNSS_EPHEMERIS_LIST_MAX_SIZE_V02 32
+
+typedef uint32_t LocPosTechMask;
+#define LOC_POS_TECH_MASK_DEFAULT ((LocPosTechMask)0x00000000)
+#define LOC_POS_TECH_MASK_SATELLITE ((LocPosTechMask)0x00000001)
+#define LOC_POS_TECH_MASK_CELLID ((LocPosTechMask)0x00000002)
+#define LOC_POS_TECH_MASK_WIFI ((LocPosTechMask)0x00000004)
+#define LOC_POS_TECH_MASK_SENSORS ((LocPosTechMask)0x00000008)
+#define LOC_POS_TECH_MASK_REFERENCE_LOCATION ((LocPosTechMask)0x00000010)
+#define LOC_POS_TECH_MASK_INJECTED_COARSE_POSITION ((LocPosTechMask)0x00000020)
+#define LOC_POS_TECH_MASK_AFLT ((LocPosTechMask)0x00000040)
+#define LOC_POS_TECH_MASK_HYBRID ((LocPosTechMask)0x00000080)
+#define LOC_POS_TECH_MASK_PPE ((LocPosTechMask)0x00000100)
+#define LOC_POS_TECH_MASK_VEH ((LocPosTechMask)0x00000200)
+#define LOC_POS_TECH_MASK_VIS ((LocPosTechMask)0x00000400)
+
+
+enum loc_registration_mask_status {
+    LOC_REGISTRATION_MASK_ENABLED,
+    LOC_REGISTRATION_MASK_DISABLED,
+    LOC_REGISTRATION_MASK_SET
+};
+
+typedef enum {
+    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_CONSTELLATION_ENABLEMENT_V02, /**< Support constellation enablement */
+    LOC_SUPPORTED_FEATURE_AGPM_V02, /**< Support AGPM feature */
+    LOC_SUPPORTED_FEATURE_XTRA_INTEGRITY, /**< Support XTRA integrity */
+    LOC_SUPPORTED_FEATURE_FDCL_2, /**< Support FDCL V2 */
+    LOC_SUPPORTED_FEATURE_LOCATION_PRIVACY, /**< Support location privacy */
+    LOC_SUPPORTED_FEATURE_NAVIC, /**< Support NAVIC constellation */
+    LOC_SUPPORTED_FEATURE_MEASUREMENTS_CORRECTION, /**< Support measurements correction */
+    LOC_SUPPORTED_FEATURE_ROBUST_LOCATION, /**<  Support Robust Location feature */
+    LOC_SUPPORTED_FEATURE_EDGNSS /**< Support precise location dgnss */
+} loc_supported_feature_enum;
+
+typedef struct {
+    /** set to sizeof(UlpLocation) */
+    uint32_t          size;
+    LocGpsLocation     gpsLocation;
+    /* Provider indicator for HYBRID or GPS */
+    uint16_t        position_source;
+    LocPosTechMask  tech_mask;
+    bool            unpropagatedPosition;
+} UlpLocation;
+
+typedef struct {
+    /** set to sizeof(UlpNmea) */
+    uint32_t          size;
+    char            nmea_str[ULP_MAX_NMEA_STRING_SIZE];
+    unsigned int    len;
+} UlpNmea;
+
+
+/** AGPS type */
+typedef int8_t AGpsExtType;
+#define LOC_AGPS_TYPE_INVALID       -1
+#define LOC_AGPS_TYPE_ANY           0
+#define LOC_AGPS_TYPE_SUPL          1
+#define LOC_AGPS_TYPE_C2K           2
+#define LOC_AGPS_TYPE_WWAN_ANY      3
+#define LOC_AGPS_TYPE_WIFI          4
+#define LOC_AGPS_TYPE_SUPL_ES       5
+
+/** SSID length */
+#define SSID_BUF_SIZE (32+1)
+
+typedef int16_t AGpsBearerType;
+#define AGPS_APN_BEARER_INVALID     0
+#define AGPS_APN_BEARER_IPV4        1
+#define AGPS_APN_BEARER_IPV6        2
+#define AGPS_APN_BEARER_IPV4V6      3
+
+typedef uint32_t LocApnTypeMask;
+/**<  Denotes APN type for Default/Internet traffic  */
+#define LOC_APN_TYPE_MASK_DEFAULT   ((LocApnTypeMask)0x00000001)
+/**<  Denotes  APN type for IP Multimedia Subsystem  */
+#define LOC_APN_TYPE_MASK_IMS       ((LocApnTypeMask)0x00000002)
+/**<  Denotes APN type for Multimedia Messaging Service  */
+#define LOC_APN_TYPE_MASK_MMS       ((LocApnTypeMask)0x00000004)
+/**<  Denotes APN type for Dial Up Network  */
+#define LOC_APN_TYPE_MASK_DUN       ((LocApnTypeMask)0x00000008)
+/**<  Denotes APN type for Secure User Plane Location  */
+#define LOC_APN_TYPE_MASK_SUPL      ((LocApnTypeMask)0x00000010)
+/**<  Denotes APN type for High Priority Mobile Data  */
+#define LOC_APN_TYPE_MASK_HIPRI     ((LocApnTypeMask)0x00000020)
+/**<  Denotes APN type for over the air administration  */
+#define LOC_APN_TYPE_MASK_FOTA      ((LocApnTypeMask)0x00000040)
+/**<  Denotes APN type for Carrier Branded Services  */
+#define LOC_APN_TYPE_MASK_CBS       ((LocApnTypeMask)0x00000080)
+/**<  Denotes APN type for Initial Attach  */
+#define LOC_APN_TYPE_MASK_IA        ((LocApnTypeMask)0x00000100)
+/**<  Denotes APN type for emergency  */
+#define LOC_APN_TYPE_MASK_EMERGENCY ((LocApnTypeMask)0x00000200)
+
+typedef uint32_t AGpsTypeMask;
+#define AGPS_ATL_TYPE_SUPL       ((AGpsTypeMask)0x00000001)
+#define AGPS_ATL_TYPE_SUPL_ES   ((AGpsTypeMask)0x00000002)
+#define AGPS_ATL_TYPE_WWAN       ((AGpsTypeMask)0x00000004)
+
+typedef struct {
+    void* statusV4Cb;
+    AGpsTypeMask atlType;
+} AgpsCbInfo;
+
+typedef struct {
+    void* visibilityControlCb;
+    void* isInEmergencySession;
+} NfwCbInfo;
+
+/** GPS extended callback structure. */
+typedef struct {
+    /** set to sizeof(LocGpsCallbacks) */
+    uint32_t      size;
+    loc_gps_set_capabilities set_capabilities_cb;
+    loc_gps_acquire_wakelock acquire_wakelock_cb;
+    loc_gps_release_wakelock release_wakelock_cb;
+    loc_gps_create_thread create_thread_cb;
+    loc_gps_request_utc_time request_utc_time_cb;
+} GpsExtCallbacks;
+
+/** Callback to report the xtra server url to the client.
+ *  The client should use this url when downloading xtra unless overwritten
+ *  in the gps.conf file
+ */
+typedef void (* report_xtra_server)(const char*, const char*, const char*);
+
+/** Callback structure for the XTRA interface. */
+typedef struct {
+    loc_gps_xtra_download_request download_request_cb;
+    loc_gps_create_thread create_thread_cb;
+    report_xtra_server report_xtra_server_cb;
+} GpsXtraExtCallbacks;
+
+/** Represents the status of AGPS. */
+typedef struct {
+    /** set to sizeof(AGpsExtStatus) */
+    uint32_t          size;
+
+    AGpsExtType type;
+    LocAGpsStatusValue status;
+    uint32_t        ipv4_addr;
+    struct sockaddr_storage addr;
+    char            ssid[SSID_BUF_SIZE];
+    char            password[SSID_BUF_SIZE];
+} AGpsExtStatus;
+
+/** Callback with AGPS status information.
+ *  Can only be called from a thread created by create_thread_cb.
+ */
+typedef void (* agps_status_extended)(AGpsExtStatus* status);
+
+/** Callback structure for the AGPS interface. */
+typedef struct {
+    agps_status_extended status_cb;
+    loc_gps_create_thread create_thread_cb;
+} AGpsExtCallbacks;
+
+
+typedef void (*loc_ni_notify_callback)(LocGpsNiNotification *notification, bool esEnalbed);
+/** GPS NI callback structure. */
+typedef struct
+{
+    /**
+     * Sends the notification request from HAL to GPSLocationProvider.
+     */
+    loc_ni_notify_callback notify_cb;
+} GpsNiExtCallbacks;
+
+typedef enum loc_server_type {
+    LOC_AGPS_CDMA_PDE_SERVER,
+    LOC_AGPS_CUSTOM_PDE_SERVER,
+    LOC_AGPS_MPC_SERVER,
+    LOC_AGPS_SUPL_SERVER,
+    LOC_AGPS_MO_SUPL_SERVER
+} LocServerType;
+
+typedef enum loc_position_mode_type {
+    LOC_POSITION_MODE_INVALID = -1,
+    LOC_POSITION_MODE_STANDALONE = 0,
+    LOC_POSITION_MODE_MS_BASED,
+    LOC_POSITION_MODE_MS_ASSISTED,
+    LOC_POSITION_MODE_RESERVED_1,
+    LOC_POSITION_MODE_RESERVED_2,
+    LOC_POSITION_MODE_RESERVED_3,
+    LOC_POSITION_MODE_RESERVED_4,
+    LOC_POSITION_MODE_RESERVED_5
+
+} LocPositionMode;
+
+/**
+ * @brief Minimum allowed value for fix interval.
+ *
+ * This value is a sanity limit in GPS framework. The hardware has own internal
+ * limits that may not match this value
+ *
+ * @sa GPS_DEFAULT_FIX_INTERVAL_MS
+ */
+
+#define GPS_MIN_POSSIBLE_FIX_INTERVAL_MS 100
+/**
+ * @brief Default value for fix interval.
+ *
+ * This value is used by default whenever appropriate.
+ *
+ * @sa GPS_MIN_POSSIBLE_FIX_INTERVAL_MS
+ */
+#define GPS_DEFAULT_FIX_INTERVAL_MS      1000
+
+/** Flags to indicate which values are valid in a GpsLocationExtended. */
+typedef uint64_t GpsLocationExtendedFlags;
+/** GpsLocationExtended has valid pdop, hdop, vdop. */
+#define GPS_LOCATION_EXTENDED_HAS_DOP 0x0001
+/** GpsLocationExtended has valid altitude mean sea level. */
+#define GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL 0x0002
+/** UlpLocation has valid magnetic deviation. */
+#define GPS_LOCATION_EXTENDED_HAS_MAG_DEV 0x0004
+/** UlpLocation has valid mode indicator. */
+#define GPS_LOCATION_EXTENDED_HAS_MODE_IND 0x0008
+/** GpsLocationExtended has valid vertical uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_VERT_UNC 0x0010
+/** GpsLocationExtended has valid speed uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_SPEED_UNC 0x0020
+/** GpsLocationExtended has valid heading uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_BEARING_UNC 0x0040
+/** GpsLocationExtended has valid horizontal reliability */
+#define GPS_LOCATION_EXTENDED_HAS_HOR_RELIABILITY 0x0080
+/** GpsLocationExtended has valid vertical reliability */
+#define GPS_LOCATION_EXTENDED_HAS_VERT_RELIABILITY 0x0100
+/** GpsLocationExtended has valid Horizontal Elliptical Uncertainty (Semi-Major Axis) */
+#define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MAJOR 0x0200
+/** GpsLocationExtended has valid Horizontal Elliptical Uncertainty (Semi-Minor Axis) */
+#define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_MINOR 0x0400
+/** GpsLocationExtended has valid Elliptical Horizontal Uncertainty Azimuth */
+#define GPS_LOCATION_EXTENDED_HAS_HOR_ELIP_UNC_AZIMUTH 0x0800
+/** GpsLocationExtended has valid gnss sv used in position data */
+#define GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA 0x1000
+/** GpsLocationExtended has valid navSolutionMask */
+#define GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK 0x2000
+/** GpsLocationExtended has valid LocPosTechMask */
+#define GPS_LOCATION_EXTENDED_HAS_POS_TECH_MASK   0x4000
+/** GpsLocationExtended has valid LocSvInfoSource */
+#define GPS_LOCATION_EXTENDED_HAS_SV_SOURCE_INFO   0x8000
+/** GpsLocationExtended has valid position dynamics data */
+#define GPS_LOCATION_EXTENDED_HAS_POS_DYNAMICS_DATA   0x10000
+/** GpsLocationExtended has GPS Time */
+#define GPS_LOCATION_EXTENDED_HAS_GPS_TIME   0x20000
+/** GpsLocationExtended has Extended Dilution of Precision */
+#define GPS_LOCATION_EXTENDED_HAS_EXT_DOP   0x40000
+/** GpsLocationExtended has North standard deviation */
+#define GPS_LOCATION_EXTENDED_HAS_NORTH_STD_DEV   0x80000
+/** GpsLocationExtended has East standard deviation*/
+#define GPS_LOCATION_EXTENDED_HAS_EAST_STD_DEV   0x100000
+/** GpsLocationExtended has North Velocity */
+#define GPS_LOCATION_EXTENDED_HAS_NORTH_VEL   0x200000
+/** GpsLocationExtended has East Velocity */
+#define GPS_LOCATION_EXTENDED_HAS_EAST_VEL   0x400000
+/** GpsLocationExtended has up Velocity */
+#define GPS_LOCATION_EXTENDED_HAS_UP_VEL   0x800000
+/** GpsLocationExtended has North Velocity Uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_NORTH_VEL_UNC   0x1000000
+/** GpsLocationExtended has East Velocity Uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_EAST_VEL_UNC   0x2000000
+/** GpsLocationExtended has up Velocity Uncertainty */
+#define GPS_LOCATION_EXTENDED_HAS_UP_VEL_UNC   0x4000000
+/** GpsLocationExtended has Clock Bias */
+#define GPS_LOCATION_EXTENDED_HAS_CLOCK_BIAS   0x8000000
+/** GpsLocationExtended has Clock Bias std deviation*/
+#define GPS_LOCATION_EXTENDED_HAS_CLOCK_BIAS_STD_DEV   0x10000000
+/** GpsLocationExtended has Clock drift*/
+#define GPS_LOCATION_EXTENDED_HAS_CLOCK_DRIFT   0x20000000
+/** GpsLocationExtended has Clock drift std deviation**/
+#define GPS_LOCATION_EXTENDED_HAS_CLOCK_DRIFT_STD_DEV    0x40000000
+/** GpsLocationExtended has leap seconds **/
+#define GPS_LOCATION_EXTENDED_HAS_LEAP_SECONDS           0x80000000
+/** GpsLocationExtended has time uncertainty **/
+#define GPS_LOCATION_EXTENDED_HAS_TIME_UNC               0x100000000
+/** GpsLocationExtended has heading rate  **/
+#define GPS_LOCATION_EXTENDED_HAS_HEADING_RATE           0x200000000
+/** GpsLocationExtended has multiband signals  **/
+#define GPS_LOCATION_EXTENDED_HAS_MULTIBAND              0x400000000
+/** GpsLocationExtended has sensor calibration confidence */
+#define GPS_LOCATION_EXTENDED_HAS_CALIBRATION_CONFIDENCE 0x800000000
+/** GpsLocationExtended has sensor calibration status */
+#define GPS_LOCATION_EXTENDED_HAS_CALIBRATION_STATUS     0x1000000000
+/** GpsLocationExtended has the engine type that produced this
+ *  position, the bit mask will only be set when there are two
+ *  or more position engines running in the system */
+#define GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_TYPE       0x2000000000
+ /** GpsLocationExtended has the engine mask that indicates the
+  *     set of engines contribute to the fix. */
+#define GPS_LOCATION_EXTENDED_HAS_OUTPUT_ENG_MASK              0x4000000000
+/** GpsLocationExtended has dgnss correction source */
+#define GPS_LOCATION_EXTENDED_HAS_DGNSS_CORRECTION_SOURCE_TYPE 0x8000000000
+/** GpsLocationExtended has dgnss correction source ID */
+#define GPS_LOCATION_EXTENDED_HAS_DGNSS_CORRECTION_SOURCE_ID   0x10000000000
+/** GpsLocationExtended has dgnss constellation usage   */
+#define GPS_LOCATION_EXTENDED_HAS_DGNSS_CONSTELLATION_USAGE    0x20000000000
+/** GpsLocationExtended has dgnss ref station Id */
+#define GPS_LOCATION_EXTENDED_HAS_DGNSS_REF_STATION_ID         0x40000000000
+/** GpsLocationExtended has dgnss data age */
+#define GPS_LOCATION_EXTENDED_HAS_DGNSS_DATA_AGE               0x80000000000
+ /** GpsLocationExtended has the conformityIndex computed from
+  *  robust location feature. */
+#define GPS_LOCATION_EXTENDED_HAS_CONFORMITY_INDEX            0x100000000000
+ /** GpsLocationExtended has the llaVRPased. */
+#define GPS_LOCATION_EXTENDED_HAS_LLA_VRP_BASED                0x200000000000
+/** GpsLocationExtended has the velocityVRPased. */
+#define GPS_LOCATION_EXTENDED_HAS_ENU_VELOCITY_LLA_VRP_BASED   0x400000000000
+/** GpsLocationExtended has upperTriangleFullCovMatrix. */
+#define GPS_LOCATION_EXTENDED_HAS_UPPER_TRIANGLE_FULL_COV_MATRIX 0x800000000000
+/** GpsLocationExtended has drSolutionStatusMask. */
+#define GPS_LOCATION_EXTENDED_HAS_DR_SOLUTION_STATUS_MASK        0x1000000000000
+/** GpsLocationExtended has altitudeAssumed. */
+#define GPS_LOCATION_EXTENDED_HAS_ALTITUDE_ASSUMED               0x2000000000000
+
+typedef uint32_t LocNavSolutionMask;
+/* Bitmask to specify whether SBAS ionospheric correction is used  */
+#define LOC_NAV_MASK_SBAS_CORRECTION_IONO ((LocNavSolutionMask)0x0001)
+/* Bitmask to specify whether SBAS fast correction is used  */
+#define LOC_NAV_MASK_SBAS_CORRECTION_FAST ((LocNavSolutionMask)0x0002)
+/**<  Bitmask to specify whether SBAS long-tem correction is used  */
+#define LOC_NAV_MASK_SBAS_CORRECTION_LONG ((LocNavSolutionMask)0x0004)
+/**<  Bitmask to specify whether SBAS integrity information is used  */
+#define LOC_NAV_MASK_SBAS_INTEGRITY ((LocNavSolutionMask)0x0008)
+/**<  Bitmask to specify whether Position Report is DGNSS corrected  */
+#define LOC_NAV_MASK_DGNSS_CORRECTION ((LocNavSolutionMask)0x0010)
+/**<  Bitmask to specify whether Position Report is RTK corrected   */
+#define LOC_NAV_MASK_RTK_CORRECTION ((LocNavSolutionMask)0x0020)
+/**<  Bitmask to specify whether Position Report is PPP corrected   */
+#define LOC_NAV_MASK_PPP_CORRECTION ((LocNavSolutionMask)0x0040)
+/**<  Bitmask to specify whether Position Report is RTK fixed corrected   */
+#define LOC_NAV_MASK_RTK_FIXED_CORRECTION ((LocNavSolutionMask)0x0080)
+/**<  Bitmask specifying whether only SBAS corrected SVs are used for the fix */
+#define LOC_NAV_MASK_ONLY_SBAS_CORRECTED_SV_USED ((LocNavSolutionMask)0x0100)
+
+typedef uint32_t LocPosDataMask;
+/* Bitmask to specify whether Navigation data has Forward Acceleration  */
+#define LOC_NAV_DATA_HAS_LONG_ACCEL ((LocPosDataMask)0x0001)
+/* Bitmask to specify whether Navigation data has Sideward Acceleration */
+#define LOC_NAV_DATA_HAS_LAT_ACCEL ((LocPosDataMask)0x0002)
+/* Bitmask to specify whether Navigation data has Vertical Acceleration */
+#define LOC_NAV_DATA_HAS_VERT_ACCEL ((LocPosDataMask)0x0004)
+/* Bitmask to specify whether Navigation data has Heading Rate */
+#define LOC_NAV_DATA_HAS_YAW_RATE ((LocPosDataMask)0x0008)
+/* Bitmask to specify whether Navigation data has Body pitch */
+#define LOC_NAV_DATA_HAS_PITCH ((LocPosDataMask)0x0010)
+/* Bitmask to specify whether Navigation data has Forward Acceleration Unc  */
+#define LOC_NAV_DATA_HAS_LONG_ACCEL_UNC ((LocPosDataMask)0x0020)
+/* Bitmask to specify whether Navigation data has Sideward Acceleration Unc*/
+#define LOC_NAV_DATA_HAS_LAT_ACCEL_UNC ((LocPosDataMask)0x0040)
+/* Bitmask to specify whether Navigation data has Vertical Acceleration Unc*/
+#define LOC_NAV_DATA_HAS_VERT_ACCEL_UNC ((LocPosDataMask)0x0080)
+/* Bitmask to specify whether Navigation data has Heading Rate Unc*/
+#define LOC_NAV_DATA_HAS_YAW_RATE_UNC ((LocPosDataMask)0x0100)
+/* Bitmask to specify whether Navigation data has Body pitch Unc*/
+#define LOC_NAV_DATA_HAS_PITCH_UNC ((LocPosDataMask)0x0200)
+
+typedef uint32_t GnssAdditionalSystemInfoMask;
+/* Bitmask to specify whether Tauc is valid */
+#define GNSS_ADDITIONAL_SYSTEMINFO_HAS_TAUC ((GnssAdditionalSystemInfoMask)0x0001)
+/* Bitmask to specify whether leapSec is valid */
+#define GNSS_ADDITIONAL_SYSTEMINFO_HAS_LEAP_SEC ((GnssAdditionalSystemInfoMask)0x0002)
+
+
+/** GPS PRN Range */
+#define GPS_SV_PRN_MIN      1
+#define GPS_SV_PRN_MAX      32
+#define GLO_SV_PRN_MIN      65
+#define GLO_SV_PRN_MAX      96
+#define SBAS_SV_PRN_MIN     120
+#define SBAS_SV_PRN_MAX     191
+#define QZSS_SV_PRN_MIN     193
+#define QZSS_SV_PRN_MAX     197
+#define BDS_SV_PRN_MIN      201
+#define BDS_SV_PRN_MAX      263
+#define GAL_SV_PRN_MIN      301
+#define GAL_SV_PRN_MAX      336
+#define NAVIC_SV_PRN_MIN    401
+#define NAVIC_SV_PRN_MAX    414
+#define GLO_SV_PRN_SLOT_UNKNOWN 255
+
+/* Checking svIdOneBase can be set to the corresponding bit in mask */
+#define svFitsMask(mask, svIdOneBase)                 \
+    ((svIdOneBase) >= 1 && (svIdOneBase) <= (sizeof(mask) << 3))
+/* Setting svIdOneBase specific bit in the mask if the bit offset fits */
+#define setSvMask(mask, svIdOneBase)                  \
+    if (svFitsMask(mask, svIdOneBase)) mask |= (1ULL << ((svIdOneBase) - 1))
+
+#define isValInRangeInclusive(val, min, max) ((val) >= (min) && (val) <= (max))
+#define isGloSlotUnknown(val) ((val) == GLO_SV_PRN_SLOT_UNKNOWN)
+
+typedef enum {
+    LOC_RELIABILITY_NOT_SET = 0,
+    LOC_RELIABILITY_VERY_LOW = 1,
+    LOC_RELIABILITY_LOW = 2,
+    LOC_RELIABILITY_MEDIUM = 3,
+    LOC_RELIABILITY_HIGH = 4
+}LocReliability;
+
+typedef enum {
+    LOC_IN_EMERGENCY_UNKNOWN = 0,
+    LOC_IN_EMERGENCY_SET = 1,
+    LOC_IN_EMERGENCY_NOT_SET = 2
+}LocInEmergency;
+
+typedef struct {
+    struct timespec32_t apTimeStamp;
+    /*boottime received from pps-ktimer*/
+    float apTimeStampUncertaintyMs;
+    /* timestamp uncertainty in milli seconds */
+}Gnss_ApTimeStampStructType;
+
+typedef struct {
+    uint64_t gps_sv_used_ids_mask;
+    uint64_t glo_sv_used_ids_mask;
+    uint64_t gal_sv_used_ids_mask;
+    uint64_t bds_sv_used_ids_mask;
+    uint64_t qzss_sv_used_ids_mask;
+    uint64_t navic_sv_used_ids_mask;
+} GnssSvUsedInPosition;
+
+typedef struct {
+    uint64_t gps_l1ca_sv_used_ids_mask;     // GPS L1CA
+    uint64_t gps_l1c_sv_used_ids_mask;      // GPS L1C
+    uint64_t gps_l2_sv_used_ids_mask;       // GPS L2
+    uint64_t gps_l5_sv_used_ids_mask;       // GPS L5
+    uint64_t glo_g1_sv_used_ids_mask;       // GLO G1
+    uint64_t glo_g2_sv_used_ids_mask;       // GLO G2
+    uint64_t gal_e1_sv_used_ids_mask;       // GAL E1
+    uint64_t gal_e5a_sv_used_ids_mask;      // GAL E5A
+    uint64_t gal_e5b_sv_used_ids_mask;      // GAL E5B
+    uint64_t bds_b1i_sv_used_ids_mask;      // BDS B1I
+    uint64_t bds_b1c_sv_used_ids_mask;      // BDS B1C
+    uint64_t bds_b2i_sv_used_ids_mask;      // BDS B2I
+    uint64_t bds_b2ai_sv_used_ids_mask;     // BDS B2AI
+    uint64_t qzss_l1ca_sv_used_ids_mask;    // QZSS L1CA
+    uint64_t qzss_l1s_sv_used_ids_mask;     // QZSS L1S
+    uint64_t qzss_l2_sv_used_ids_mask;      // QZSS L2
+    uint64_t qzss_l5_sv_used_ids_mask;      // QZSS L5
+    uint64_t sbas_l1_sv_used_ids_mask;      // SBAS L1
+    uint64_t bds_b2aq_sv_used_ids_mask;     // BDS B2AQ
+} GnssSvMbUsedInPosition;
+
+/* Body Frame parameters */
+typedef struct {
+    /** Contains Body frame LocPosDataMask bits. */
+   uint32_t        bodyFrameDatamask;
+   /* Forward Acceleration in body frame (m/s2)*/
+   float           longAccel;
+   /** Uncertainty of Forward Acceleration in body frame */
+   float           longAccelUnc;
+   /* Sideward Acceleration in body frame (m/s2)*/
+   float           latAccel;
+   /** Uncertainty of Side-ward Acceleration in body frame */
+   float           latAccelUnc;
+   /* Vertical Acceleration in body frame (m/s2)*/
+   float           vertAccel;
+   /** Uncertainty of Vertical Acceleration in body frame */
+   float           vertAccelUnc;
+   /* Heading Rate (Radians/second) */
+   float           yawRate;
+   /** Uncertainty of Heading Rate */
+   float           yawRateUnc;
+   /* Body pitch (Radians) */
+   float           pitch;
+   /** Uncertainty of Body pitch */
+   float           pitchRadUnc;
+}LocPositionDynamics;
+
+typedef struct {
+
+  /**  Position dilution of precision.
+       Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+  float PDOP;
+
+  /**  Horizontal dilution of precision.
+       Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+  float HDOP;
+
+  /**  Vertical dilution of precision.
+       Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+  float VDOP;
+
+  /**  geometric  dilution of precision.
+       Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+  float GDOP;
+
+  /**  time dilution of precision.
+       Range: 1 (highest accuracy) to 50 (lowest accuracy) */
+  float TDOP;
+}LocExtDOP;
+
+/* GPS Time structure */
+typedef struct {
+
+  /**<   Current GPS week as calculated from midnight, Jan. 6, 1980. \n
+       - Units: Weeks */
+  uint16_t gpsWeek;
+
+  /**<   Amount of time into the current GPS week. \n
+       - Units: Milliseconds */
+  uint32_t gpsTimeOfWeekMs;
+}GPSTimeStruct;
+
+typedef uint8_t CarrierPhaseAmbiguityType;
+#define CARRIER_PHASE_AMBIGUITY_RESOLUTION_NONE ((CarrierPhaseAmbiguityType)0)
+#define CARRIER_PHASE_AMBIGUITY_RESOLUTION_FLOAT ((CarrierPhaseAmbiguityType)1)
+#define CARRIER_PHASE_AMBIGUITY_RESOLUTION_FIXED ((CarrierPhaseAmbiguityType)2)
+
+
+typedef enum {
+  LOC_DGNSS_CORR_SOURCE_TYPE_INVALID = 0, /**<  Invalid DGNSS correction source type \n */
+  LOC_DGNSS_CORR_SOURCE_TYPE_RTCM = 1, /**<  DGNSS correction source type RTCM \n */
+  LOC_DGNSS_CORR_SOURCE_TYPE_3GPP = 2, /**<  DGNSS correction source type 3GPP \n */
+}LocDgnssCorrectionSourceType;
+
+typedef uint16_t GnssMeasUsageStatusBitMask;
+/** Used in fix */
+#define GNSS_MEAS_USED_IN_PVT ((GnssMeasUsageStatusBitMask)0x00000001ul)
+/** Measurement is Bad */
+#define GNSS_MEAS_USAGE_STATUS_BAD_MEAS ((GnssMeasUsageStatusBitMask)0x00000002ul)
+/** Measurement has too low C/N */
+#define GNSS_MEAS_USAGE_STATUS_CNO_TOO_LOW ((GnssMeasUsageStatusBitMask)0x00000004ul)
+/** Measurement has too low elevation */
+#define GNSS_MEAS_USAGE_STATUS_ELEVATION_TOO_LOW ((GnssMeasUsageStatusBitMask)0x00000008ul)
+/** No ephemeris available for this measurement */
+#define GNSS_MEAS_USAGE_STATUS_NO_EPHEMERIS ((GnssMeasUsageStatusBitMask)0x00000010ul)
+/** No corrections available for the measurement */
+#define GNSS_MEAS_USAGE_STATUS_NO_CORRECTIONS ((GnssMeasUsageStatusBitMask)0x00000020ul)
+/** Corrections has timed out for the measurement */
+#define GNSS_MEAS_USAGE_STATUS_CORRECTION_TIMEOUT ((GnssMeasUsageStatusBitMask)0x00000040ul)
+/** Measurement is unhealthy */
+#define GNSS_MEAS_USAGE_STATUS_UNHEALTHY ((GnssMeasUsageStatusBitMask)0x00000080ul)
+/** Configuration is disabled for this measurement */
+#define GNSS_MEAS_USAGE_STATUS_CONFIG_DISABLED ((GnssMeasUsageStatusBitMask)0x00000100ul)
+/** Measurement not used for other reasons */
+#define GNSS_MEAS_USAGE_STATUS_OTHER ((GnssMeasUsageStatusBitMask)0x00000200ul)
+
+/** Flags to indicate valid fields in epMeasUsageInfo */
+typedef uint16_t GnssMeasUsageInfoValidityMask;
+#define GNSS_PSEUDO_RANGE_RESIDUAL_VALID        ((GnssMeasUsageInfoValidityMask)0x00000001ul)
+#define GNSS_DOPPLER_RESIDUAL_VALID             ((GnssMeasUsageInfoValidityMask)0x00000002ul)
+#define GNSS_CARRIER_PHASE_RESIDUAL_VALID       ((GnssMeasUsageInfoValidityMask)0x00000004ul)
+#define GNSS_CARRIER_PHASE_AMBIGUITY_TYPE_VALID ((GnssMeasUsageInfoValidityMask)0x00000008ul)
+
+typedef uint16_t GnssSvPolyStatusMask;
+#define GNSS_SV_POLY_SRC_ALM_CORR_V02 ((GnssSvPolyStatusMask)0x01)
+#define GNSS_SV_POLY_GLO_STR4_V02 ((GnssSvPolyStatusMask)0x02)
+#define GNSS_SV_POLY_DELETE_V02 ((GnssSvPolyStatusMask)0x04)
+#define GNSS_SV_POLY_SRC_GAL_FNAV_OR_INAV_V02 ((GnssSvPolyStatusMask)0x08)
+typedef uint16_t GnssSvPolyStatusMaskValidity;
+#define GNSS_SV_POLY_SRC_ALM_CORR_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x01)
+#define GNSS_SV_POLY_GLO_STR4_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x02)
+#define GNSS_SV_POLY_DELETE_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x04)
+#define GNSS_SV_POLY_SRC_GAL_FNAV_OR_INAV_VALID_V02 ((GnssSvPolyStatusMaskValidity)0x08)
+
+typedef struct {
+    /** Specifies GNSS signal type
+        Mandatory Field*/
+    GnssSignalTypeMask gnssSignalType;
+    /** Specifies GNSS Constellation Type
+        Mandatory Field*/
+    Gnss_LocSvSystemEnumType gnssConstellation;
+    /**  Unique SV Identifier.
+     *   SV Range for supported constellation is specified as below:
+     *    - For GPS:     1 to 32
+     *    - For GLONASS: 65 to 96
+     *    - For SBAS:    120 to 158 and 183 to 191
+     *    - For QZSS:    193 to 197
+     *    - For BDS:     201 to 263
+     *    - For GAL:     301 to 336
+     *    - For NAVIC:   401 to 414 */
+    uint16_t gnssSvId;
+    /** GLONASS frequency number + 7.
+        Valid only for a GLONASS system and
+        is to be ignored for all other systems.
+        Range: 1 to 14 */
+    uint8_t gloFrequency;
+    /** Carrier phase ambiguity type. */
+    CarrierPhaseAmbiguityType carrierPhaseAmbiguityType;
+    /** Validity mask */
+    GnssMeasUsageStatusBitMask measUsageStatusMask;
+    /** Specifies measurement usage status
+        Mandatory Field*/
+    GnssMeasUsageInfoValidityMask validityMask;
+    /** Computed pseudorange residual.
+        Unit: Meters */
+    float pseudorangeResidual;
+    /** Computed doppler residual.
+        Unit: Meters/sec*/
+    float dopplerResidual;
+    /** Computed carrier phase residual.
+        Unit: Cycles*/
+    float carrierPhaseResidual;
+    /** Carrier phase ambiguity value.
+        Unit: Cycles*/
+    float carrierPhasAmbiguity;
+} GpsMeasUsageInfo;
+
+#define COV_MATRIX_SIZE 12
+/** Represents gps location extended. */
+typedef struct {
+    /** set to sizeof(GpsLocationExtended) */
+    uint32_t          size;
+    /** Contains GpsLocationExtendedFlags bits. */
+    uint64_t        flags;
+    /** Contains the Altitude wrt mean sea level */
+    float           altitudeMeanSeaLevel;
+    /** Contains Position Dilusion of Precision. */
+    float           pdop;
+    /** Contains Horizontal Dilusion of Precision. */
+    float           hdop;
+    /** Contains Vertical Dilusion of Precision. */
+    float           vdop;
+    /** Contains Magnetic Deviation. */
+    float           magneticDeviation;
+    /** vertical uncertainty in meters */
+    float           vert_unc;
+    /** speed uncertainty in m/s */
+    float           speed_unc;
+    /** heading uncertainty in degrees (0 to 359.999) */
+    float           bearing_unc;
+    /** horizontal reliability. */
+    LocReliability  horizontal_reliability;
+    /** vertical reliability. */
+    LocReliability  vertical_reliability;
+    /*  Horizontal Elliptical Uncertainty (Semi-Major Axis) */
+    float           horUncEllipseSemiMajor;
+    /*  Horizontal Elliptical Uncertainty (Semi-Minor Axis) */
+    float           horUncEllipseSemiMinor;
+    /*    Elliptical Horizontal Uncertainty Azimuth */
+    float           horUncEllipseOrientAzimuth;
+
+    Gnss_ApTimeStampStructType               timeStamp;
+    /** Gnss sv used in position data */
+    GnssSvUsedInPosition gnss_sv_used_ids;
+    /** Gnss sv used in position data for multiband */
+    GnssSvMbUsedInPosition gnss_mb_sv_used_ids;
+    /** Nav solution mask to indicate sbas corrections */
+    LocNavSolutionMask  navSolutionMask;
+    /** Position technology used in computing this fix */
+    LocPosTechMask tech_mask;
+    /** SV Info source used in computing this fix */
+    LocSvInfoSource sv_source;
+    /** Body Frame Dynamics: 4wayAcceleration and pitch set with validity */
+    GnssLocationPositionDynamics bodyFrameData;
+    /** GPS Time */
+    GPSTimeStruct gpsTime;
+    GnssSystemTime gnssSystemTime;
+    /** Dilution of precision associated with this position*/
+    LocExtDOP extDOP;
+    /** North standard deviation.
+        Unit: Meters */
+    float northStdDeviation;
+    /** East standard deviation.
+        Unit: Meters */
+    float eastStdDeviation;
+    /** North Velocity.
+        Unit: Meters/sec */
+    float northVelocity;
+    /** East Velocity.
+        Unit: Meters/sec */
+    float eastVelocity;
+    /** Up Velocity.
+        Unit: Meters/sec */
+    float upVelocity;
+    /** North Velocity standard deviation.
+        Unit: Meters/sec */
+    float northVelocityStdDeviation;
+    /** East Velocity standard deviation.
+        Unit: Meters/sec */
+    float eastVelocityStdDeviation;
+    /** Up Velocity standard deviation
+        Unit: Meters/sec */
+    float upVelocityStdDeviation;
+    /** Estimated clock bias. Unit: Nano seconds */
+    float clockbiasMeter;
+    /** Estimated clock bias std deviation. Unit: Nano seconds */
+    float clockBiasStdDeviationMeter;
+    /** Estimated clock drift. Unit: Meters/sec */
+    float clockDrift;
+    /** Estimated clock drift std deviation. Unit: Meters/sec */
+    float clockDriftStdDeviation;
+    /** Number of valid reference stations. Range:[0-4] */
+    uint8_t numValidRefStations;
+    /** Reference station(s) number */
+    uint16_t referenceStation[4];
+    /** Number of measurements received for use in fix.
+        Shall be used as maximum index in-to svUsageInfo[].
+        Set to 0, if svUsageInfo reporting is not supported.
+        Range: 0-EP_GNSS_MAX_MEAS */
+    uint8_t numOfMeasReceived;
+    /** Measurement Usage Information */
+    GpsMeasUsageInfo measUsageInfo[GNSS_SV_MAX];
+    /** Leap Seconds */
+    uint8_t leapSeconds;
+    /** Time uncertainty in milliseconds   */
+    float timeUncMs;
+    /** Heading Rate is in NED frame.
+        Range: 0 to 359.999. 946
+        Unit: Degrees per Seconds */
+    float headingRateDeg;
+    /** Sensor calibration confidence percent. Range: 0 - 100 */
+    uint8_t calibrationConfidence;
+    DrCalibrationStatusMask calibrationStatus;
+    /** location engine type. When the fix. when the type is set to
+        LOC_ENGINE_SRC_FUSED, the fix is the propagated/aggregated
+        reports from all engines running on the system (e.g.:
+        DR/SPE/PPE). To check which location engine contributes to
+        the fused output, check for locOutputEngMask. */
+    LocOutputEngineType locOutputEngType;
+    /** when loc output eng type is set to fused, this field
+        indicates the set of engines contribute to the fix. */
+    PositioningEngineMask locOutputEngMask;
+
+    /**  DGNSS Correction Source for position report: RTCM, 3GPP
+     *   etc. */
+    LocDgnssCorrectionSourceType dgnssCorrectionSourceType;
+
+    /**  If DGNSS is used, the SourceID is a 32bit number identifying
+     *   the DGNSS source ID */
+    uint32_t dgnssCorrectionSourceID;
+
+    /** If DGNSS is used, which constellation was DGNSS used for to
+     *  produce the pos report. */
+    GnssConstellationTypeMask dgnssConstellationUsage;
+
+    /** If DGNSS is used, DGNSS Reference station ID used for
+     *  position report */
+    uint16_t dgnssRefStationId;
+
+    /**  If DGNSS is used, DGNSS data age in milli-seconds  */
+    uint32_t dgnssDataAgeMsec;
+
+    /** When robust location is enabled, this field
+     * will how well the various input data considered for
+     * navigation solution conform to expectations.
+     * Range: 0 (least conforming) to 1 (most conforming) */
+    float conformityIndex;
+    GnssLocationPositionDynamicsExt bodyFrameDataExt;
+    /** VRR-based latitude/longitude/altitude */
+    LLAInfo llaVRPBased;
+    /** VRR-based east, north, and up velocity */
+    float enuVelocityVRPBased[3];
+    /** Upper triangle elements of full matrix of position and
+        velocity estimate in ECEF
+
+         The full covariance matrix of PPE position
+         (x, y, z in ECEF, in the unit of meters) estimate is a 3x3 matrix
+            | px,x  px,y  px,z |
+            | py,x  py,y  py,z |
+            | pz,x  pz,y  pz,z |
+
+         The full covariance matrix of PPE velocity
+         (vx,vy, vz in ECEF, in the unit of m/s) estimate is a 3x3 matrix
+            | pvx,vx  pvx,vy  pvx,vz |
+            | pvy,vx  pvy,vy  pvy,vz |
+            | pvz,vx  pvz,vy  pvz,vz |
+
+        upperTriangleFullCovMatrix =
+          { px,x, px,y, px,z, py,y, py,z, pz,z, pvx,vx, pvx,vy, pvx,vz, pvy,vy, pvy,vz, pvz,vz}
+        Uint: px,x, px,y, px,z, py,y, py,z, pz,z is in meter
+              pvx,vx, pvx,vy, pvx,vz, pvy,vy, pvy,vz, pvz,vz is in meters/seconds
+    */
+    float upperTriangleFullCovMatrix[COV_MATRIX_SIZE];
+    DrSolutionStatusMask drSolutionStatusMask;
+    /** When this field is valid, it will indicates whether altitude
+     *  is assumed or calculated.
+     *  false: Altitude is calculated.
+     *  true:  Altitude is assumed; there may not be enough
+     *         satellites to determine the precise altitude. */
+    bool altitudeAssumed;
+} GpsLocationExtended;
+
+// struct that contains complete position info from engine
+typedef struct {
+    UlpLocation location;
+    GpsLocationExtended locationExtended;
+    enum loc_sess_status sessionStatus;
+} EngineLocationInfo;
+
+// Nmea sentence types mask
+typedef uint32_t NmeaSentenceTypesMask;
+#define LOC_NMEA_MASK_GGA_V02   ((NmeaSentenceTypesMask)0x00000001) /**<  Enable GGA type  */
+#define LOC_NMEA_MASK_RMC_V02   ((NmeaSentenceTypesMask)0x00000002) /**<  Enable RMC type  */
+#define LOC_NMEA_MASK_GSV_V02   ((NmeaSentenceTypesMask)0x00000004) /**<  Enable GSV type  */
+#define LOC_NMEA_MASK_GSA_V02   ((NmeaSentenceTypesMask)0x00000008) /**<  Enable GSA type  */
+#define LOC_NMEA_MASK_VTG_V02   ((NmeaSentenceTypesMask)0x00000010) /**<  Enable VTG type  */
+#define LOC_NMEA_MASK_PQXFI_V02 ((NmeaSentenceTypesMask)0x00000020) /**<  Enable PQXFI type  */
+#define LOC_NMEA_MASK_PSTIS_V02 ((NmeaSentenceTypesMask)0x00000040) /**<  Enable PSTIS type  */
+#define LOC_NMEA_MASK_GLGSV_V02 ((NmeaSentenceTypesMask)0x00000080) /**<  Enable GLGSV type  */
+#define LOC_NMEA_MASK_GNGSA_V02 ((NmeaSentenceTypesMask)0x00000100) /**<  Enable GNGSA type  */
+#define LOC_NMEA_MASK_GNGNS_V02 ((NmeaSentenceTypesMask)0x00000200) /**<  Enable GNGNS type  */
+#define LOC_NMEA_MASK_GARMC_V02 ((NmeaSentenceTypesMask)0x00000400) /**<  Enable GARMC type  */
+#define LOC_NMEA_MASK_GAGSV_V02 ((NmeaSentenceTypesMask)0x00000800) /**<  Enable GAGSV type  */
+#define LOC_NMEA_MASK_GAGSA_V02 ((NmeaSentenceTypesMask)0x00001000) /**<  Enable GAGSA type  */
+#define LOC_NMEA_MASK_GAVTG_V02 ((NmeaSentenceTypesMask)0x00002000) /**<  Enable GAVTG type  */
+#define LOC_NMEA_MASK_GAGGA_V02 ((NmeaSentenceTypesMask)0x00004000) /**<  Enable GAGGA type  */
+#define LOC_NMEA_MASK_PQGSA_V02 ((NmeaSentenceTypesMask)0x00008000) /**<  Enable PQGSA type  */
+#define LOC_NMEA_MASK_PQGSV_V02 ((NmeaSentenceTypesMask)0x00010000) /**<  Enable PQGSV type  */
+#define LOC_NMEA_MASK_DEBUG_V02 ((NmeaSentenceTypesMask)0x00020000) /**<  Enable DEBUG type  */
+#define LOC_NMEA_MASK_GPDTM_V02 ((NmeaSentenceTypesMask)0x00040000) /**<  Enable GPDTM type  */
+#define LOC_NMEA_MASK_GNGGA_V02 ((NmeaSentenceTypesMask)0x00080000) /**<  Enable GNGGA type  */
+#define LOC_NMEA_MASK_GNRMC_V02 ((NmeaSentenceTypesMask)0x00100000) /**<  Enable GNRMC type  */
+#define LOC_NMEA_MASK_GNVTG_V02 ((NmeaSentenceTypesMask)0x00200000) /**<  Enable GNVTG type  */
+#define LOC_NMEA_MASK_GAGNS_V02 ((NmeaSentenceTypesMask)0x00400000) /**<  Enable GAGNS type  */
+#define LOC_NMEA_MASK_GBGGA_V02 ((NmeaSentenceTypesMask)0x00800000) /**<  Enable GBGGA type  */
+#define LOC_NMEA_MASK_GBGSA_V02 ((NmeaSentenceTypesMask)0x01000000) /**<  Enable GBGSA type  */
+#define LOC_NMEA_MASK_GBGSV_V02 ((NmeaSentenceTypesMask)0x02000000) /**<  Enable GBGSV type  */
+#define LOC_NMEA_MASK_GBRMC_V02 ((NmeaSentenceTypesMask)0x04000000) /**<  Enable GBRMC type  */
+#define LOC_NMEA_MASK_GBVTG_V02 ((NmeaSentenceTypesMask)0x08000000) /**<  Enable GBVTG type  */
+#define LOC_NMEA_MASK_GQGSV_V02 ((NmeaSentenceTypesMask)0x10000000) /**<  Enable GQGSV type  */
+#define LOC_NMEA_MASK_GIGSV_V02 ((NmeaSentenceTypesMask)0x20000000) /**<  Enable GIGSV type  */
+#define LOC_NMEA_MASK_GNDTM_V02 ((NmeaSentenceTypesMask)0x40000000) /**<  Enable GNDTM type  */
+#define LOC_NMEA_MASK_TAGBLOCK_V02 ((NmeaSentenceTypesMask)0x80000000) /**< Enable TAGBLOCK type */
+
+
+// all bitmasks of general supported NMEA sentenses - debug is not part of this
+#define LOC_NMEA_ALL_GENERAL_SUPPORTED_MASK  (LOC_NMEA_MASK_GGA_V02 | LOC_NMEA_MASK_RMC_V02 | \
+              LOC_NMEA_MASK_GSV_V02 | LOC_NMEA_MASK_GSA_V02 | LOC_NMEA_MASK_VTG_V02 | \
+        LOC_NMEA_MASK_PQXFI_V02 | LOC_NMEA_MASK_PSTIS_V02 | LOC_NMEA_MASK_GLGSV_V02 | \
+        LOC_NMEA_MASK_GNGSA_V02 | LOC_NMEA_MASK_GNGNS_V02 | LOC_NMEA_MASK_GARMC_V02 | \
+        LOC_NMEA_MASK_GAGSV_V02 | LOC_NMEA_MASK_GAGSA_V02 | LOC_NMEA_MASK_GAVTG_V02 | \
+        LOC_NMEA_MASK_GAGGA_V02 | LOC_NMEA_MASK_PQGSA_V02 | LOC_NMEA_MASK_PQGSV_V02 | \
+        LOC_NMEA_MASK_GPDTM_V02 | LOC_NMEA_MASK_GNGGA_V02 | LOC_NMEA_MASK_GNRMC_V02 | \
+        LOC_NMEA_MASK_GNVTG_V02 | LOC_NMEA_MASK_GAGNS_V02 | LOC_NMEA_MASK_GBGGA_V02 | \
+        LOC_NMEA_MASK_GBGSA_V02 | LOC_NMEA_MASK_GBGSV_V02 | LOC_NMEA_MASK_GBRMC_V02 | \
+        LOC_NMEA_MASK_GBVTG_V02 | LOC_NMEA_MASK_GQGSV_V02 | LOC_NMEA_MASK_GIGSV_V02 | \
+        LOC_NMEA_MASK_GNDTM_V02)
+
+typedef enum {
+  LOC_ENG_IF_REQUEST_SENDER_ID_QUIPC = 0,
+  LOC_ENG_IF_REQUEST_SENDER_ID_MSAPM,
+  LOC_ENG_IF_REQUEST_SENDER_ID_MSAPU,
+  LOC_ENG_IF_REQUEST_SENDER_ID_GPSONE_DAEMON,
+  LOC_ENG_IF_REQUEST_SENDER_ID_MODEM,
+  LOC_ENG_IF_REQUEST_SENDER_ID_UNKNOWN
+} loc_if_req_sender_id_e_type;
+
+
+#define smaller_of(a, b) (((a) > (b)) ? (b) : (a))
+#define MAX_APN_LEN 100
+
+// This will be overridden by the individual adapters
+// if necessary.
+#define DEFAULT_IMPL(rtv)                                     \
+{                                                             \
+    LOC_LOGD("%s: default implementation invoked", __func__); \
+    return rtv;                                               \
+}
+
+enum loc_api_adapter_err {
+    LOC_API_ADAPTER_ERR_SUCCESS             = 0,
+    LOC_API_ADAPTER_ERR_GENERAL_FAILURE     = 1,
+    LOC_API_ADAPTER_ERR_UNSUPPORTED         = 2,
+    LOC_API_ADAPTER_ERR_INVALID_HANDLE      = 4,
+    LOC_API_ADAPTER_ERR_INVALID_PARAMETER   = 5,
+    LOC_API_ADAPTER_ERR_ENGINE_BUSY         = 6,
+    LOC_API_ADAPTER_ERR_PHONE_OFFLINE       = 7,
+    LOC_API_ADAPTER_ERR_TIMEOUT             = 8,
+    LOC_API_ADAPTER_ERR_SERVICE_NOT_PRESENT = 9,
+    LOC_API_ADAPTER_ERR_INTERNAL            = 10,
+
+    /* equating engine down to phone offline, as they are the same errror */
+    LOC_API_ADAPTER_ERR_ENGINE_DOWN         = LOC_API_ADAPTER_ERR_PHONE_OFFLINE,
+    LOC_API_ADAPTER_ERR_FAILURE             = 101,
+    LOC_API_ADAPTER_ERR_UNKNOWN
+};
+
+enum loc_api_adapter_event_index {
+    LOC_API_ADAPTER_REPORT_POSITION = 0,               // Position report comes in loc_parsed_position_s_type
+    LOC_API_ADAPTER_REPORT_SATELLITE,                  // Satellite in view report
+    LOC_API_ADAPTER_REPORT_NMEA_1HZ,                   // NMEA report at 1HZ rate
+    LOC_API_ADAPTER_REPORT_NMEA_POSITION,              // NMEA report at position report rate
+    LOC_API_ADAPTER_REQUEST_NI_NOTIFY_VERIFY,          // NI notification/verification request
+    LOC_API_ADAPTER_REQUEST_ASSISTANCE_DATA,           // Assistance data, eg: time, predicted orbits request
+    LOC_API_ADAPTER_REQUEST_LOCATION_SERVER,           // Request for location server
+    LOC_API_ADAPTER_REPORT_IOCTL,                      // Callback report for loc_ioctl
+    LOC_API_ADAPTER_REPORT_STATUS,                     // Misc status report: eg, engine state
+    LOC_API_ADAPTER_REQUEST_WIFI,                      //
+    LOC_API_ADAPTER_SENSOR_STATUS,                     //
+    LOC_API_ADAPTER_REQUEST_TIME_SYNC,                 //
+    LOC_API_ADAPTER_REPORT_SPI,                        //
+    LOC_API_ADAPTER_REPORT_NI_GEOFENCE,                //
+    LOC_API_ADAPTER_GEOFENCE_GEN_ALERT,                //
+    LOC_API_ADAPTER_REPORT_GENFENCE_BREACH,            //
+    LOC_API_ADAPTER_PEDOMETER_CTRL,                    //
+    LOC_API_ADAPTER_MOTION_CTRL,                       //
+    LOC_API_ADAPTER_REQUEST_WIFI_AP_DATA,              // Wifi ap data
+    LOC_API_ADAPTER_BATCH_FULL,                        // Batching on full
+    LOC_API_ADAPTER_BATCHED_POSITION_REPORT,           // Batching on fix
+    LOC_API_ADAPTER_BATCHED_GENFENCE_BREACH_REPORT,    //
+    LOC_API_ADAPTER_GNSS_MEASUREMENT_REPORT,           // GNSS Measurement Report
+    LOC_API_ADAPTER_GNSS_SV_POLYNOMIAL_REPORT,         // GNSS SV Polynomial Report
+    LOC_API_ADAPTER_GDT_UPLOAD_BEGIN_REQ,              // GDT upload start request
+    LOC_API_ADAPTER_GDT_UPLOAD_END_REQ,                // GDT upload end request
+    LOC_API_ADAPTER_GNSS_MEASUREMENT,                  // GNSS Measurement report
+    LOC_API_ADAPTER_REQUEST_TIMEZONE,                  // Timezone injection request
+    LOC_API_ADAPTER_REPORT_GENFENCE_DWELL_REPORT,      // Geofence dwell report
+    LOC_API_ADAPTER_REQUEST_SRN_DATA,                  // request srn data from AP
+    LOC_API_ADAPTER_REQUEST_POSITION_INJECTION,        // Position injection request
+    LOC_API_ADAPTER_BATCH_STATUS,                      // batch status
+    LOC_API_ADAPTER_FDCL_SERVICE_REQ,                  // FDCL service request
+    LOC_API_ADAPTER_REPORT_UNPROPAGATED_POSITION,      // Unpropagated Position report
+    LOC_API_ADAPTER_BS_OBS_DATA_SERVICE_REQ,           // BS observation data request
+    LOC_API_ADAPTER_GNSS_SV_EPHEMERIS_REPORT,          // GNSS SV Ephemeris Report
+    LOC_API_ADAPTER_LOC_SYSTEM_INFO,                   // Location system info event
+    LOC_API_ADAPTER_GNSS_NHZ_MEASUREMENT_REPORT,       // GNSS SV nHz measurement report
+    LOC_API_ADAPTER_EVENT_REPORT_INFO,                 // Event report info
+    LOC_API_ADAPTER_LATENCY_INFORMATION_REPORT,       // Latency information report
+    LOC_API_ADAPTER_EVENT_MAX
+};
+
+#define LOC_API_ADAPTER_BIT_PARSED_POSITION_REPORT           (1ULL<<LOC_API_ADAPTER_REPORT_POSITION)
+#define LOC_API_ADAPTER_BIT_SATELLITE_REPORT                 (1ULL<<LOC_API_ADAPTER_REPORT_SATELLITE)
+#define LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT                  (1ULL<<LOC_API_ADAPTER_REPORT_NMEA_1HZ)
+#define LOC_API_ADAPTER_BIT_NMEA_POSITION_REPORT             (1ULL<<LOC_API_ADAPTER_REPORT_NMEA_POSITION)
+#define LOC_API_ADAPTER_BIT_NI_NOTIFY_VERIFY_REQUEST         (1ULL<<LOC_API_ADAPTER_REQUEST_NI_NOTIFY_VERIFY)
+#define LOC_API_ADAPTER_BIT_ASSISTANCE_DATA_REQUEST          (1ULL<<LOC_API_ADAPTER_REQUEST_ASSISTANCE_DATA)
+#define LOC_API_ADAPTER_BIT_LOCATION_SERVER_REQUEST          (1ULL<<LOC_API_ADAPTER_REQUEST_LOCATION_SERVER)
+#define LOC_API_ADAPTER_BIT_IOCTL_REPORT                     (1ULL<<LOC_API_ADAPTER_REPORT_IOCTL)
+#define LOC_API_ADAPTER_BIT_STATUS_REPORT                    (1ULL<<LOC_API_ADAPTER_REPORT_STATUS)
+#define LOC_API_ADAPTER_BIT_REQUEST_WIFI                     (1ULL<<LOC_API_ADAPTER_REQUEST_WIFI)
+#define LOC_API_ADAPTER_BIT_SENSOR_STATUS                    (1ULL<<LOC_API_ADAPTER_SENSOR_STATUS)
+#define LOC_API_ADAPTER_BIT_REQUEST_TIME_SYNC                (1ULL<<LOC_API_ADAPTER_REQUEST_TIME_SYNC)
+#define LOC_API_ADAPTER_BIT_REPORT_SPI                       (1ULL<<LOC_API_ADAPTER_REPORT_SPI)
+#define LOC_API_ADAPTER_BIT_REPORT_NI_GEOFENCE               (1ULL<<LOC_API_ADAPTER_REPORT_NI_GEOFENCE)
+#define LOC_API_ADAPTER_BIT_GEOFENCE_GEN_ALERT               (1ULL<<LOC_API_ADAPTER_GEOFENCE_GEN_ALERT)
+#define LOC_API_ADAPTER_BIT_REPORT_GENFENCE_BREACH           (1ULL<<LOC_API_ADAPTER_REPORT_GENFENCE_BREACH)
+#define LOC_API_ADAPTER_BIT_BATCHED_GENFENCE_BREACH_REPORT   (1ULL<<LOC_API_ADAPTER_BATCHED_GENFENCE_BREACH_REPORT)
+#define LOC_API_ADAPTER_BIT_PEDOMETER_CTRL                   (1ULL<<LOC_API_ADAPTER_PEDOMETER_CTRL)
+#define LOC_API_ADAPTER_BIT_MOTION_CTRL                      (1ULL<<LOC_API_ADAPTER_MOTION_CTRL)
+#define LOC_API_ADAPTER_BIT_REQUEST_WIFI_AP_DATA             (1ULL<<LOC_API_ADAPTER_REQUEST_WIFI_AP_DATA)
+#define LOC_API_ADAPTER_BIT_BATCH_FULL                       (1ULL<<LOC_API_ADAPTER_BATCH_FULL)
+#define LOC_API_ADAPTER_BIT_BATCHED_POSITION_REPORT          (1ULL<<LOC_API_ADAPTER_BATCHED_POSITION_REPORT)
+#define LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT_REPORT          (1ULL<<LOC_API_ADAPTER_GNSS_MEASUREMENT_REPORT)
+#define LOC_API_ADAPTER_BIT_GNSS_SV_POLYNOMIAL_REPORT        (1ULL<<LOC_API_ADAPTER_GNSS_SV_POLYNOMIAL_REPORT)
+#define LOC_API_ADAPTER_BIT_GDT_UPLOAD_BEGIN_REQ             (1ULL<<LOC_API_ADAPTER_GDT_UPLOAD_BEGIN_REQ)
+#define LOC_API_ADAPTER_BIT_GDT_UPLOAD_END_REQ               (1ULL<<LOC_API_ADAPTER_GDT_UPLOAD_END_REQ)
+#define LOC_API_ADAPTER_BIT_GNSS_MEASUREMENT                 (1ULL<<LOC_API_ADAPTER_GNSS_MEASUREMENT)
+#define LOC_API_ADAPTER_BIT_REQUEST_TIMEZONE                 (1ULL<<LOC_API_ADAPTER_REQUEST_TIMEZONE)
+#define LOC_API_ADAPTER_BIT_REPORT_GENFENCE_DWELL            (1ULL<<LOC_API_ADAPTER_REPORT_GENFENCE_DWELL_REPORT)
+#define LOC_API_ADAPTER_BIT_REQUEST_SRN_DATA                 (1ULL<<LOC_API_ADAPTER_REQUEST_SRN_DATA)
+#define LOC_API_ADAPTER_BIT_POSITION_INJECTION_REQUEST       (1ULL<<LOC_API_ADAPTER_REQUEST_POSITION_INJECTION)
+#define LOC_API_ADAPTER_BIT_BATCH_STATUS                     (1ULL<<LOC_API_ADAPTER_BATCH_STATUS)
+#define LOC_API_ADAPTER_BIT_FDCL_SERVICE_REQ                 (1ULL<<LOC_API_ADAPTER_FDCL_SERVICE_REQ)
+#define LOC_API_ADAPTER_BIT_PARSED_UNPROPAGATED_POSITION_REPORT (1ULL<<LOC_API_ADAPTER_REPORT_UNPROPAGATED_POSITION)
+#define LOC_API_ADAPTER_BIT_BS_OBS_DATA_SERVICE_REQ          (1ULL<<LOC_API_ADAPTER_BS_OBS_DATA_SERVICE_REQ)
+#define LOC_API_ADAPTER_BIT_GNSS_SV_EPHEMERIS_REPORT         (1ULL<<LOC_API_ADAPTER_GNSS_SV_EPHEMERIS_REPORT)
+#define LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO                  (1ULL<<LOC_API_ADAPTER_LOC_SYSTEM_INFO)
+#define LOC_API_ADAPTER_BIT_GNSS_NHZ_MEASUREMENT             (1ULL<<LOC_API_ADAPTER_GNSS_NHZ_MEASUREMENT_REPORT)
+#define LOC_API_ADAPTER_BIT_EVENT_REPORT_INFO                (1ULL<<LOC_API_ADAPTER_EVENT_REPORT_INFO)
+#define LOC_API_ADAPTER_BIT_LATENCY_INFORMATION              (1ULL<<LOC_API_ADAPTER_LATENCY_INFORMATION_REPORT)
+
+typedef uint64_t LOC_API_ADAPTER_EVENT_MASK_T;
+
+typedef enum loc_api_adapter_msg_to_check_supported {
+    LOC_API_ADAPTER_MESSAGE_LOCATION_BATCHING,               // Batching 1.0
+    LOC_API_ADAPTER_MESSAGE_BATCHED_GENFENCE_BREACH,         // Geofence Batched Breach
+    LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_TRACKING,          // DBT 2.0
+    LOC_API_ADAPTER_MESSAGE_ADAPTIVE_LOCATION_BATCHING,      // Batching 1.5
+    LOC_API_ADAPTER_MESSAGE_DISTANCE_BASE_LOCATION_BATCHING, // Batching 2.0
+    LOC_API_ADAPTER_MESSAGE_UPDATE_TBF_ON_THE_FLY,           // Updating Tracking TBF On The Fly
+    LOC_API_ADAPTER_MESSAGE_OUTDOOR_TRIP_BATCHING,           // Outdoor Trip Batching
+
+    LOC_API_ADAPTER_MESSAGE_MAX
+} LocCheckingMessagesID;
+
+typedef int IzatDevId_t;
+
+typedef uint32_t LOC_GPS_LOCK_MASK;
+#define isGpsLockNone(lock) ((lock) == 0)
+#define isGpsLockMO(lock) ((lock) & ((LOC_GPS_LOCK_MASK)1))
+#define isGpsLockMT(lock) ((lock) & ((LOC_GPS_LOCK_MASK)2))
+#define isGpsLockAll(lock) (((lock) & ((LOC_GPS_LOCK_MASK)3)) == 3)
+
+/* ***********************************************
+**  Satellite Measurement and Satellite Polynomial
+**  structure definitions
+** ***********************************************
+*/
+#define GNSS_SV_POLY_VELOCITY_COEF_MAX_SIZE         12
+#define GNSS_SV_POLY_XYZ_0_TH_ORDER_COEFF_MAX_SIZE  3
+#define GNSS_SV_POLY_XYZ_N_TH_ORDER_COEFF_MAX_SIZE  9
+#define GNSS_SV_POLY_SV_CLKBIAS_COEFF_MAX_SIZE      4
+/** Max number of GNSS SV measurement */
+#define GNSS_LOC_SV_MEAS_LIST_MAX_SIZE              128
+
+enum ulp_gnss_sv_measurement_valid_flags{
+
+    ULP_GNSS_SV_MEAS_GPS_TIME = 0,
+    ULP_GNSS_SV_MEAS_PSUEDO_RANGE,
+    ULP_GNSS_SV_MEAS_MS_IN_WEEK,
+    ULP_GNSS_SV_MEAS_SUB_MSEC,
+    ULP_GNSS_SV_MEAS_CARRIER_PHASE,
+    ULP_GNSS_SV_MEAS_DOPPLER_SHIFT,
+    ULP_GNSS_SV_MEAS_CNO,
+    ULP_GNSS_SV_MEAS_LOSS_OF_LOCK,
+
+    ULP_GNSS_SV_MEAS_MAX_VALID_FLAGS
+};
+
+#define ULP_GNSS_SV_MEAS_BIT_GPS_TIME        (1<<ULP_GNSS_SV_MEAS_GPS_TIME)
+#define ULP_GNSS_SV_MEAS_BIT_PSUEDO_RANGE    (1<<ULP_GNSS_SV_MEAS_PSUEDO_RANGE)
+#define ULP_GNSS_SV_MEAS_BIT_MS_IN_WEEK      (1<<ULP_GNSS_SV_MEAS_MS_IN_WEEK)
+#define ULP_GNSS_SV_MEAS_BIT_SUB_MSEC        (1<<ULP_GNSS_SV_MEAS_SUB_MSEC)
+#define ULP_GNSS_SV_MEAS_BIT_CARRIER_PHASE   (1<<ULP_GNSS_SV_MEAS_CARRIER_PHASE)
+#define ULP_GNSS_SV_MEAS_BIT_DOPPLER_SHIFT   (1<<ULP_GNSS_SV_MEAS_DOPPLER_SHIFT)
+#define ULP_GNSS_SV_MEAS_BIT_CNO             (1<<ULP_GNSS_SV_MEAS_CNO)
+#define ULP_GNSS_SV_MEAS_BIT_LOSS_OF_LOCK    (1<<ULP_GNSS_SV_MEAS_LOSS_OF_LOCK)
+
+enum ulp_gnss_sv_poly_valid_flags{
+
+    ULP_GNSS_SV_POLY_GLO_FREQ = 0,
+    ULP_GNSS_SV_POLY_T0,
+    ULP_GNSS_SV_POLY_IODE,
+    ULP_GNSS_SV_POLY_FLAG,
+    ULP_GNSS_SV_POLY_POLYCOEFF_XYZ0,
+    ULP_GNSS_SV_POLY_POLYCOEFF_XYZN,
+    ULP_GNSS_SV_POLY_POLYCOEFF_OTHER,
+    ULP_GNSS_SV_POLY_SV_POSUNC,
+    ULP_GNSS_SV_POLY_IONODELAY,
+    ULP_GNSS_SV_POLY_IONODOT,
+    ULP_GNSS_SV_POLY_SBAS_IONODELAY,
+    ULP_GNSS_SV_POLY_SBAS_IONODOT,
+    ULP_GNSS_SV_POLY_TROPODELAY,
+    ULP_GNSS_SV_POLY_ELEVATION,
+    ULP_GNSS_SV_POLY_ELEVATIONDOT,
+    ULP_GNSS_SV_POLY_ELEVATIONUNC,
+    ULP_GNSS_SV_POLY_VELO_COEFF,
+    ULP_GNSS_SV_POLY_ENHANCED_IOD,
+    ULP_GNSS_SV_POLY_GPS_ISC_L1CA,
+    ULP_GNSS_SV_POLY_GPS_ISC_L2C,
+    ULP_GNSS_SV_POLY_GPS_ISC_L5I5,
+    ULP_GNSS_SV_POLY_GPS_ISC_L5Q5,
+    ULP_GNSS_SV_POLY_GPS_TGD,
+    ULP_GNSS_SV_POLY_GLO_TGD_G1G2,
+    ULP_GNSS_SV_POLY_BDS_TGD_B1,
+    ULP_GNSS_SV_POLY_BDS_TGD_B2,
+    ULP_GNSS_SV_POLY_BDS_TGD_B2A,
+    ULP_GNSS_SV_POLY_BDS_ISC_B2A,
+    ULP_GNSS_SV_POLY_GAL_BGD_E1E5A,
+    ULP_GNSS_SV_POLY_GAL_BGD_E1E5B,
+    ULP_GNSS_SV_POLY_NAVIC_TGD_L5
+};
+
+#define ULP_GNSS_SV_POLY_BIT_GLO_FREQ               (1<<ULP_GNSS_SV_POLY_GLO_FREQ)
+#define ULP_GNSS_SV_POLY_BIT_T0                     (1<<ULP_GNSS_SV_POLY_T0)
+#define ULP_GNSS_SV_POLY_BIT_IODE                   (1<<ULP_GNSS_SV_POLY_IODE)
+#define ULP_GNSS_SV_POLY_BIT_FLAG                   (1<<ULP_GNSS_SV_POLY_FLAG)
+#define ULP_GNSS_SV_POLY_BIT_POLYCOEFF_XYZ0         (1<<ULP_GNSS_SV_POLY_POLYCOEFF_XYZ0)
+#define ULP_GNSS_SV_POLY_BIT_POLYCOEFF_XYZN         (1<<ULP_GNSS_SV_POLY_POLYCOEFF_XYZN)
+#define ULP_GNSS_SV_POLY_BIT_POLYCOEFF_OTHER        (1<<ULP_GNSS_SV_POLY_POLYCOEFF_OTHER)
+#define ULP_GNSS_SV_POLY_BIT_SV_POSUNC              (1<<ULP_GNSS_SV_POLY_SV_POSUNC)
+#define ULP_GNSS_SV_POLY_BIT_IONODELAY              (1<<ULP_GNSS_SV_POLY_IONODELAY)
+#define ULP_GNSS_SV_POLY_BIT_IONODOT                (1<<ULP_GNSS_SV_POLY_IONODOT)
+#define ULP_GNSS_SV_POLY_BIT_SBAS_IONODELAY         (1<<ULP_GNSS_SV_POLY_SBAS_IONODELAY)
+#define ULP_GNSS_SV_POLY_BIT_SBAS_IONODOT           (1<<ULP_GNSS_SV_POLY_SBAS_IONODOT)
+#define ULP_GNSS_SV_POLY_BIT_TROPODELAY             (1<<ULP_GNSS_SV_POLY_TROPODELAY)
+#define ULP_GNSS_SV_POLY_BIT_ELEVATION              (1<<ULP_GNSS_SV_POLY_ELEVATION)
+#define ULP_GNSS_SV_POLY_BIT_ELEVATIONDOT           (1<<ULP_GNSS_SV_POLY_ELEVATIONDOT)
+#define ULP_GNSS_SV_POLY_BIT_ELEVATIONUNC           (1<<ULP_GNSS_SV_POLY_ELEVATIONUNC)
+#define ULP_GNSS_SV_POLY_BIT_VELO_COEFF             (1<<ULP_GNSS_SV_POLY_VELO_COEFF)
+#define ULP_GNSS_SV_POLY_BIT_ENHANCED_IOD           (1<<ULP_GNSS_SV_POLY_ENHANCED_IOD)
+#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L1CA           (1<<ULP_GNSS_SV_POLY_GPS_ISC_L1CA)
+#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L2C            (1<<ULP_GNSS_SV_POLY_GPS_ISC_L2C)
+#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L5I5           (1<<ULP_GNSS_SV_POLY_GPS_ISC_L5I5)
+#define ULP_GNSS_SV_POLY_BIT_GPS_ISC_L5Q5           (1<<ULP_GNSS_SV_POLY_GPS_ISC_L5Q5)
+#define ULP_GNSS_SV_POLY_BIT_GPS_TGD                (1<<ULP_GNSS_SV_POLY_GPS_TGD)
+#define ULP_GNSS_SV_POLY_BIT_GLO_TGD_G1G2           (1<<ULP_GNSS_SV_POLY_GLO_TGD_G1G2)
+#define ULP_GNSS_SV_POLY_BIT_BDS_TGD_B1             (1<<ULP_GNSS_SV_POLY_BDS_TGD_B1)
+#define ULP_GNSS_SV_POLY_BIT_BDS_TGD_B2             (1<<ULP_GNSS_SV_POLY_BDS_TGD_B2)
+#define ULP_GNSS_SV_POLY_BIT_BDS_TGD_B2A            (1<<ULP_GNSS_SV_POLY_BDS_TGD_B2A)
+#define ULP_GNSS_SV_POLY_BIT_BDS_ISC_B2A            (1<<ULP_GNSS_SV_POLY_BDS_ISC_B2A)
+#define ULP_GNSS_SV_POLY_BIT_GAL_BGD_E1E5A          (1<<ULP_GNSS_SV_POLY_GAL_BGD_E1E5A)
+#define ULP_GNSS_SV_POLY_BIT_GAL_BGD_E1E5B          (1<<ULP_GNSS_SV_POLY_GAL_BGD_E1E5B)
+#define ULP_GNSS_SV_POLY_BIT_NAVIC_TGD_L5           (1<<ULP_GNSS_SV_POLY_NAVIC_TGD_L5)
+
+typedef enum
+{
+    GNSS_LOC_FREQ_SOURCE_INVALID = 0,
+    /**< Source of the frequency is invalid */
+    GNSS_LOC_FREQ_SOURCE_EXTERNAL = 1,
+    /**< Source of the frequency is from external injection */
+    GNSS_LOC_FREQ_SOURCE_PE_CLK_REPORT = 2,
+    /**< Source of the frequency is from Navigation engine */
+    GNSS_LOC_FREQ_SOURCE_UNKNOWN = 3
+    /**< Source of the frequency is unknown */
+} Gnss_LocSourceofFreqEnumType;
+
+typedef struct
+{
+    uint32_t                          size;
+    float                           clockDrift;
+    /**< Receiver clock Drift \n
+         - Units: meter per sec \n
+    */
+    float                           clockDriftUnc;
+    /**< Receiver clock Drift uncertainty \n
+         - Units: meter per sec \n
+    */
+    Gnss_LocSourceofFreqEnumType    sourceOfFreq;
+}Gnss_LocRcvrClockFrequencyInfoStructType;
+
+typedef struct
+{
+    uint32_t      size;
+    uint8_t     leapSec;
+    /**< GPS time leap second delta to UTC time  \n
+         - Units: sec \n
+       */
+    uint8_t     leapSecUnc;
+    /**< Uncertainty for GPS leap second \n
+         - Units: sec \n
+       */
+}Gnss_LeapSecondInfoStructType;
+
+typedef enum
+{
+   GNSS_LOC_SYS_TIME_BIAS_VALID                = 0x01,
+   /**< System time bias valid */
+   GNSS_LOC_SYS_TIME_BIAS_UNC_VALID            = 0x02,
+   /**< System time bias uncertainty valid */
+}Gnss_LocInterSystemBiasValidMaskType;
+
+typedef struct
+{
+    uint32_t          size;
+    uint32_t        validMask;
+    /* Validity mask as per Gnss_LocInterSystemBiasValidMaskType */
+
+    float           timeBias;
+    /**< System-1 to System-2 Time Bias  \n
+        - Units: msec \n
+    */
+    float           timeBiasUnc;
+    /**< System-1 to System-2 Time Bias uncertainty  \n
+        - Units: msec \n
+    */
+} Gnss_InterSystemBiasStructType;
+
+
+typedef struct {
+
+  uint32_t    size;
+
+  uint8_t   systemRtc_valid;
+  /**<   Validity indicator for System RTC */
+
+  uint64_t  systemRtcMs;
+  /**<   Platform system RTC value \n
+        - Units: msec \n
+        */
+
+}Gnss_LocGnssTimeExtStructType;
+
+typedef enum
+{
+    GNSS_LOC_MEAS_STATUS_NULL                    = 0x00000000,
+    /**< No information state */
+    GNSS_LOC_MEAS_STATUS_SM_VALID                = 0x00000001,
+    /**< Code phase is known */
+    GNSS_LOC_MEAS_STATUS_SB_VALID                = 0x00000002,
+    /**< Sub-bit time is known */
+    GNSS_LOC_MEAS_STATUS_MS_VALID                = 0x00000004,
+    /**< Satellite time is known */
+    GNSS_LOC_MEAS_STATUS_BE_CONFIRM              = 0x00000008,
+    /**< Bit edge is confirmed from signal   */
+    GNSS_LOC_MEAS_STATUS_VELOCITY_VALID          = 0x00000010,
+    /**< Satellite Doppler measured */
+    GNSS_LOC_MEAS_STATUS_VELOCITY_FINE           = 0x00000020,
+    /**< TRUE: Fine Doppler measured, FALSE: Coarse Doppler measured */
+    GNSS_LOC_MEAS_STATUS_LP_VALID                = 0x00000040,
+    /**<  TRUE/FALSE -- Lock Point is valid/invalid */
+    GNSS_LOC_MEAS_STATUS_LP_POS_VALID            = 0x00000080,
+    /**<  TRUE/FALSE -- Lock Point is positive/negative */
+    GNSS_LOC_MEAS_STATUS_FROM_RNG_DIFF           = 0x00000200,
+    /**< Range update from Satellite differences */
+    GNSS_LOC_MEAS_STATUS_FROM_VE_DIFF            = 0x00000400,
+    /**< Doppler update from Satellite differences */
+    GNSS_LOC_MEAS_STATUS_DONT_USE_X              = 0x00000800,
+    /**< Don't use measurement if bit is set */
+    GNSS_LOC_MEAS_STATUS_DONT_USE_M              = 0x00001000,
+    /**< Don't use measurement if bit is set */
+    GNSS_LOC_MEAS_STATUS_DONT_USE_D              = 0x00002000,
+    /**< Don't use measurement if bit is set */
+    GNSS_LOC_MEAS_STATUS_DONT_USE_S              = 0x00004000,
+    /**< Don't use measurement if bit is set */
+    GNSS_LOC_MEAS_STATUS_DONT_USE_P              = 0x00008000,
+    /**< Don't use measurement if bit is set */
+    GNSS_LOC_MEAS_STATUS_GNSS_FRESH_MEAS         = 0x08000000
+    /**< TRUE -- Fresh GNSS measurement observed in last second    */
+}Gnss_LocSvMeasStatusMaskType;
+
+typedef struct
+{
+    uint32_t              size;
+    uint32_t            svMs;
+    /**<  Satellite time milisecond.\n
+          For GPS, BDS, GAL range of 0 thru (604800000-1) \n
+          For GLONASS range of 0 thru (86400000-1) \n
+          Valid when PD_LOC_MEAS_STATUS_MS_VALID bit is set in measurement status \n
+          Note: All SV times in the current measurement block are alredy propagated to common reference time epoch. \n
+            - Units: msec \n
+       */
+    float               svSubMs;
+    /**<Satellite time sub-millisecond. \n
+        Total SV Time = svMs + svSubMs \n
+        - Units: msec \n
+       */
+    float               svTimeUncMs;
+    /**<  Satellite Time uncertainty \n
+          - Units: msec \n
+       */
+    float               dopplerShift;
+    /**< Satellite Doppler \n
+            - Units: meter per sec \n
+       */
+    float               dopplerShiftUnc;
+    /**< Satellite Doppler uncertainty\n
+            - Units: meter per sec \n
+       */
+}Gnss_LocSVTimeSpeedStructType;
+
+typedef enum
+{
+  GNSS_SV_STATE_IDLE = 0,
+  GNSS_SV_STATE_SEARCH = 1,
+  GNSS_SV_STATE_SEARCH_VERIFY = 2,
+  GNSS_SV_STATE_BIT_EDGE = 3,
+  GNSS_SV_STATE_VERIFY_TRACK = 4,
+  GNSS_SV_STATE_TRACK = 5,
+  GNSS_SV_STATE_RESTART = 6,
+  GNSS_SV_STATE_DPO_TRACK = 7
+} Gnss_LocSVStateEnumType;
+
+typedef enum
+{
+  GNSS_LOC_SVINFO_MASK_HAS_EPHEMERIS   = 0x01,
+  /**< Ephemeris is available for this SV */
+  GNSS_LOC_SVINFO_MASK_HAS_ALMANAC     = 0x02
+  /**< Almanac is available for this SV */
+}Gnss_LocSvInfoMaskT;
+
+typedef enum
+{
+  GNSS_LOC_SV_SRCH_STATUS_IDLE      = 1,
+    /**< SV is not being actively processed */
+  GNSS_LOC_SV_SRCH_STATUS_SEARCH    = 2,
+    /**< The system is searching for this SV */
+  GNSS_LOC_SV_SRCH_STATUS_TRACK     = 3
+    /**< SV is being tracked */
+}Gnss_LocSvSearchStatusEnumT;
+
+typedef uint32_t LocSvDgnssMeasStatusMask;
+#define LOC_MASK_DGNSS_EPOCH_TIME_VALID      0x1  /**<  DGNSS Epoch time is valid  */
+#define LOC_MASK_DGNSS_MEAS_STATUS_PR_VALID  0x2  /**<  Pseudo Range correction is valid  */
+#define LOC_MASK_DGNSS_MEAS_STATUS_PRR_VALID 0x4  /**<  Pseudo Range rate correction is valid  */
+
+typedef struct {
+  LocSvDgnssMeasStatusMask dgnssMeasStatus;
+  /**<   Bitmask indicating the DGNSS SV measurement status. */
+
+  uint32_t diffDataEpochTimeMsec;
+  /**<   Age of differential data in Milli Seconds with respect to the Measurement time. */
+
+  float prCorrMeters;
+  /**<   Pseudo Range correction in meters. */
+
+  float prrCorrMetersPerSec;
+  /**<  Pseudo Range rate correction in meters per second. */
+} Gnss_LocDgnssSVMeasurement;
+
+typedef struct
+{
+    uint32_t                          size;
+    Gnss_LocSvSystemEnumType        gnssSystem;
+    // 0 signal type mask indicates invalid value
+    GnssSignalTypeMask              gnssSignalTypeMask;
+    uint16_t                        gnssSvId;
+    /** Unique SV Identifier.
+     *  For SV Range of supported constellation, please refer to the
+     *  comment section of gnssSvId in GpsMeasUsageInfo.
+    */
+    uint8_t                         gloFrequency;
+    /**< GLONASS frequency number + 7 \n
+         Valid only for GLONASS System \n
+         Shall be ignored for all other systems \n
+          - Range: 1 to 14 \n
+    */
+    Gnss_LocSvSearchStatusEnumT     svStatus;
+    /**< Satellite search state \n
+        @ENUM()
+    */
+    bool                         healthStatus_valid;
+    /**< SV Health Status validity flag\n
+        - 0: Not valid \n
+        - 1: Valid \n
+    */
+    uint8_t                         healthStatus;
+    /**< Health status.
+         \begin{itemize1}
+         \item    Range: 0 to 1; 0 = unhealthy, \n 1 = healthy, 2 = unknown
+         \vspace{-0.18in} \end{itemize1}
+    */
+    Gnss_LocSvInfoMaskT             svInfoMask;
+    /**< Indicates whether almanac and ephemeris information is available. \n
+        @MASK()
+    */
+    uint64_t                        measurementStatus;
+    /**< Bitmask indicating SV measurement status.
+        Valid bitmasks: \n
+        If any MSB bit in 0xFFC0000000000000 DONT_USE is set, the measurement
+        must not be used by the client.
+        @MASK()
+    */
+    uint16_t                        CNo;
+    /**< Carrier to Noise ratio  \n
+        - Units: 0.1 dBHz \n
+    */
+    uint16_t                          gloRfLoss;
+    /**< GLONASS Rf loss reference to Antenna. \n
+         - Units: dB, Scale: 0.1 \n
+    */
+    bool                         lossOfLock;
+    /**< Loss of signal lock indicator  \n
+         - 0: Signal in continuous track \n
+         - 1: Signal not in track \n
+    */
+    int16_t                         measLatency;
+    /**< Age of the measurement. Positive value means measurement precedes ref time. \n
+         - Units: msec \n
+    */
+    Gnss_LocSVTimeSpeedStructType   svTimeSpeed;
+    /**< Unfiltered SV Time and Speed information
+    */
+    float                           dopplerAccel;
+    /**< Satellite Doppler Accelertion\n
+         - Units: Hz/s \n
+    */
+    bool                         multipathEstValid;
+    /**< Multipath estimate validity flag\n
+        - 0: Multipath estimate not valid \n
+        - 1: Multipath estimate valid \n
+    */
+    float                           multipathEstimate;
+    /**< Estimate of multipath in measurement\n
+         - Units: Meters \n
+    */
+    bool                         fineSpeedValid;
+    /**< Fine speed validity flag\n
+         - 0: Fine speed not valid \n
+         - 1: Fine speed valid \n
+    */
+    float                           fineSpeed;
+    /**< Carrier phase derived speed \n
+         - Units: m/s \n
+    */
+    bool                         fineSpeedUncValid;
+    /**< Fine speed uncertainty validity flag\n
+         - 0: Fine speed uncertainty not valid \n
+         - 1: Fine speed uncertainty valid \n
+    */
+    float                           fineSpeedUnc;
+    /**< Carrier phase derived speed \n
+        - Units: m/s \n
+    */
+    bool                         carrierPhaseValid;
+    /**< Carrier Phase measurement validity flag\n
+         - 0: Carrier Phase not valid \n
+         - 1: Carrier Phase valid \n
+    */
+    double                          carrierPhase;
+    /**< Carrier phase measurement [L1 cycles] \n
+    */
+    bool                         cycleSlipCountValid;
+     /**< Cycle slup count validity flag\n
+         - 0: Not valid \n
+         - 1: Valid \n
+    */
+    uint8_t                         cycleSlipCount;
+    /**< Increments when a CSlip is detected */
+
+    bool                         svDirectionValid;
+    /**< Validity flag for SV direction */
+
+    float                           svAzimuth;
+    /**< Satellite Azimuth
+        - Units: radians \n
+    */
+    float                           svElevation;
+    /**< Satellite Elevation
+        - Units: radians \n
+    */
+    uint64_t                        validMeasStatusMask;
+    /**< Bitmask indicating SV measurement status Validity.
+        Valid bitmasks: \n
+        If any MSB bit in 0xFFC0000000000000 DONT_USE is set, the measurement
+        must not be used by the client.
+        @MASK()
+    */
+    bool                         carrierPhaseUncValid;
+    /**< Validity flag for SV direction */
+
+    float                           carrierPhaseUnc;
+
+    /** < DGNSS Measurements Report for SVs */
+    Gnss_LocDgnssSVMeasurement   dgnssSvMeas;
+} Gnss_SVMeasurementStructType;
+
+
+typedef uint64_t GpsSvMeasHeaderFlags;
+#define GNSS_SV_MEAS_HEADER_HAS_LEAP_SECOND                   0x000000001
+#define GNSS_SV_MEAS_HEADER_HAS_CLOCK_FREQ                    0x000000002
+#define GNSS_SV_MEAS_HEADER_HAS_AP_TIMESTAMP                  0x000000004
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_GLO_INTER_SYSTEM_BIAS     0x000000008
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_BDS_INTER_SYSTEM_BIAS     0x000000010
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_GAL_INTER_SYSTEM_BIAS     0x000000020
+#define GNSS_SV_MEAS_HEADER_HAS_BDS_GLO_INTER_SYSTEM_BIAS     0x000000040
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_GLO_INTER_SYSTEM_BIAS     0x000000080
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_BDS_INTER_SYSTEM_BIAS     0x000000100
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_SYSTEM_TIME               0x000000200
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_SYSTEM_TIME               0x000000400
+#define GNSS_SV_MEAS_HEADER_HAS_BDS_SYSTEM_TIME               0x000000800
+#define GNSS_SV_MEAS_HEADER_HAS_QZSS_SYSTEM_TIME              0x000001000
+#define GNSS_SV_MEAS_HEADER_HAS_GLO_SYSTEM_TIME               0x000002000
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_SYSTEM_TIME_EXT           0x000004000
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_SYSTEM_TIME_EXT           0x000008000
+#define GNSS_SV_MEAS_HEADER_HAS_BDS_SYSTEM_TIME_EXT           0x000010000
+#define GNSS_SV_MEAS_HEADER_HAS_QZSS_SYSTEM_TIME_EXT          0x000020000
+#define GNSS_SV_MEAS_HEADER_HAS_GLO_SYSTEM_TIME_EXT           0x000040000
+#define GNSS_SV_MEAS_HEADER_HAS_GPSL1L5_TIME_BIAS             0x000080000
+#define GNSS_SV_MEAS_HEADER_HAS_GALE1E5A_TIME_BIAS            0x000100000
+#define GNSS_SV_MEAS_HEADER_HAS_BDSB1IB2A_TIME_BIAS           0x000200000
+#define GNSS_SV_MEAS_HEADER_HAS_GPS_NAVIC_INTER_SYSTEM_BIAS   0x000400000
+#define GNSS_SV_MEAS_HEADER_HAS_GAL_NAVIC_INTER_SYSTEM_BIAS   0x000800000
+#define GNSS_SV_MEAS_HEADER_HAS_GLO_NAVIC_INTER_SYSTEM_BIAS   0x001000000
+#define GNSS_SV_MEAS_HEADER_HAS_BDS_NAVIC_INTER_SYSTEM_BIAS   0x002000000
+#define GNSS_SV_MEAS_HEADER_HAS_NAVIC_SYSTEM_TIME             0x004000000
+#define GNSS_SV_MEAS_HEADER_HAS_NAVIC_SYSTEM_TIME_EXT         0x008000000
+#define GNSS_SV_MEAS_HEADER_HAS_DGNSS_CORRECTION_SOURCE_TYPE  0x010000000
+#define GNSS_SV_MEAS_HEADER_HAS_DGNSS_CORRECTION_SOURCE_ID    0x020000000
+#define GNSS_SV_MEAS_HEADER_HAS_DGNSS_REF_STATION_ID          0x040000000
+#define GNSS_SV_MEAS_HEADER_HAS_REF_COUNT_TICKS               0x080000000
+#define GNSS_SV_MEAS_HEADER_HAS_GPSL1L2C_TIME_BIAS            0x100000000
+#define GNSS_SV_MEAS_HEADER_HAS_GLOG1G2_TIME_BIAS             0x200000000
+#define GNSS_SV_MEAS_HEADER_HAS_BDSB1IB1C_TIME_BIAS           0x400000000
+#define GNSS_SV_MEAS_HEADER_HAS_GALE1E5B_TIME_BIAS            0x800000000
+
+typedef struct
+{
+    uint32_t                                      size;
+    // see defines in GNSS_SV_MEAS_HEADER_HAS_XXX_XXX
+    uint64_t                                    flags;
+
+    Gnss_LeapSecondInfoStructType               leapSec;
+
+    Gnss_LocRcvrClockFrequencyInfoStructType    clockFreq;   /* Freq */
+
+    Gnss_ApTimeStampStructType                  apBootTimeStamp;
+
+    Gnss_InterSystemBiasStructType              gpsGloInterSystemBias;
+    Gnss_InterSystemBiasStructType              gpsBdsInterSystemBias;
+    Gnss_InterSystemBiasStructType              gpsGalInterSystemBias;
+    Gnss_InterSystemBiasStructType              bdsGloInterSystemBias;
+    Gnss_InterSystemBiasStructType              galGloInterSystemBias;
+    Gnss_InterSystemBiasStructType              galBdsInterSystemBias;
+    Gnss_InterSystemBiasStructType              gpsNavicInterSystemBias;
+    Gnss_InterSystemBiasStructType              galNavicInterSystemBias;
+    Gnss_InterSystemBiasStructType              gloNavicInterSystemBias;
+    Gnss_InterSystemBiasStructType              bdsNavicInterSystemBias;
+    Gnss_InterSystemBiasStructType              gpsL1L5TimeBias;
+    Gnss_InterSystemBiasStructType              galE1E5aTimeBias;
+    Gnss_InterSystemBiasStructType              bdsB1iB2aTimeBias;
+    Gnss_InterSystemBiasStructType              gpsL1L2cTimeBias;
+    Gnss_InterSystemBiasStructType              gloG1G2TimeBias;
+    Gnss_InterSystemBiasStructType              bdsB1iB1cTimeBias;
+    Gnss_InterSystemBiasStructType              galE1E5bTimeBias;
+
+    GnssSystemTimeStructType                    gpsSystemTime;
+    GnssSystemTimeStructType                    galSystemTime;
+    GnssSystemTimeStructType                    bdsSystemTime;
+    GnssSystemTimeStructType                    qzssSystemTime;
+    GnssSystemTimeStructType                    navicSystemTime;
+    GnssGloTimeStructType                       gloSystemTime;
+
+    /** GPS system RTC time information. */
+    Gnss_LocGnssTimeExtStructType               gpsSystemTimeExt;
+    /** GAL system RTC time information. */
+    Gnss_LocGnssTimeExtStructType               galSystemTimeExt;
+    /** BDS system RTC time information. */
+    Gnss_LocGnssTimeExtStructType               bdsSystemTimeExt;
+    /** QZSS system RTC time information. */
+    Gnss_LocGnssTimeExtStructType               qzssSystemTimeExt;
+    /** GLONASS system RTC time information. */
+    Gnss_LocGnssTimeExtStructType               gloSystemTimeExt;
+    /** NAVIC system RTC time information. */
+    Gnss_LocGnssTimeExtStructType               navicSystemTimeExt;
+
+    /** Receiver tick at frame count */
+    uint64_t                                    refCountTicks;
+
+    /** DGNSS corrections source type RTCM, 3GPP etc, if DGNSS was
+     *  used for these measurements. */
+    LocDgnssCorrectionSourceType                dgnssCorrectionSourceType;
+
+    /** DGNSS SourceID: 32bit number identifying the DGNSS source
+     *  ID, if DGNSS was used for these measurements. */
+    uint32_t                                    dgnssCorrectionSourceID;
+
+    /** DGNSS Ref station ID: 32bit number identifying the DGNSS
+     *  ref station ID, if DGNSS was used for these measurements. */
+    uint16_t                                    dgnssRefStationId;
+} GnssSvMeasurementHeader;
+
+typedef struct {
+    uint32_t                        size;
+    bool                          isNhz;
+    GnssSvMeasurementHeader       svMeasSetHeader;
+    uint32_t                      svMeasCount;
+    Gnss_SVMeasurementStructType  svMeas[GNSS_LOC_SV_MEAS_LIST_MAX_SIZE];
+
+} GnssSvMeasurementSet;
+
+typedef struct {
+    uint32_t size;                  // set to sizeof(GnssMeasurements)
+    GnssSvMeasurementSet            gnssSvMeasurementSet;
+    GnssMeasurementsNotification    gnssMeasNotification;
+} GnssMeasurements;
+
+typedef enum
+{
+   GNSS_SV_POLY_COEFF_VALID             = 0x01,
+   /**< SV position in orbit coefficients are valid */
+   GNSS_SV_POLY_IONO_VALID              = 0x02,
+   /**< Iono estimates are valid */
+
+   GNSS_SV_POLY_TROPO_VALID             = 0x04,
+   /**< Tropo estimates are valid */
+
+   GNSS_SV_POLY_ELEV_VALID              = 0x08,
+   /**< Elevation, rate, uncertainty are valid */
+
+   GNSS_SV_POLY_SRC_ALM_CORR            = 0x10,
+   /**< Polynomials based on XTRA */
+
+   GNSS_SV_POLY_SBAS_IONO_VALID         = 0x20,
+   /**< SBAS IONO and rate are valid */
+
+   GNSS_SV_POLY_GLO_STR4                = 0x40
+   /**< GLONASS String 4 has been received */
+} Gnss_SvPolyStatusMaskType;
+
+typedef struct {
+    uint32_t      size;
+    uint16_t     gnssSvId;
+    /** Unique SV Identifier.
+     *  For SV Range of supported constellation, please refer to the
+     *  comment section of gnssSvId in GpsMeasUsageInfo.
+    */
+    int8_t      freqNum;
+    /** Freq index, only valid if u_SysInd is GLO */
+
+    GnssSvPolyStatusMaskValidity svPolyStatusMaskValidity;
+    GnssSvPolyStatusMask         svPolyStatusMask;
+
+    uint32_t    is_valid;
+
+    uint16_t     iode;
+    /* Ephemeris reference time
+       GPS:Issue of Data Ephemeris used [unitless].
+       GLO: Tb 7-bit, refer to ICD02
+    */
+    double      T0;
+    /* Reference time for polynominal calculations
+       GPS: Secs in week.
+       GLO: Full secs since Jan/01/96
+    */
+    double      polyCoeffXYZ0[GNSS_SV_POLY_XYZ_0_TH_ORDER_COEFF_MAX_SIZE];
+    /* C0X, C0Y, C0Z */
+    double      polyCoefXYZN[GNSS_SV_POLY_XYZ_N_TH_ORDER_COEFF_MAX_SIZE];
+    /* C1X, C2X ... C2Z, C3Z */
+    float       polyCoefOther[GNSS_SV_POLY_SV_CLKBIAS_COEFF_MAX_SIZE];
+    /* C0T, C1T, C2T, C3T */
+    float       svPosUnc;       /* SV position uncertainty [m]. */
+    float       ionoDelay;    /* Ionospheric delay at d_T0 [m]. */
+    float       ionoDot;      /* Iono delay rate [m/s].  */
+    float       sbasIonoDelay;/* SBAS Ionospheric delay at d_T0 [m]. */
+    float       sbasIonoDot;  /* SBAS Iono delay rate [m/s].  */
+    float       tropoDelay;   /* Tropospheric delay [m]. */
+    float       elevation;    /* Elevation [rad] at d_T0 */
+    float       elevationDot;      /* Elevation rate [rad/s] */
+    float       elevationUnc;      /* SV elevation [rad] uncertainty */
+    double      velCoef[GNSS_SV_POLY_VELOCITY_COEF_MAX_SIZE];
+    /* Coefficients of velocity poly */
+    uint32_t    enhancedIOD;    /*  Enhanced Reference Time */
+    float gpsIscL1ca;
+    float gpsIscL2c;
+    float gpsIscL5I5;
+    float gpsIscL5Q5;
+    float gpsTgd;
+    float gloTgdG1G2;
+    float bdsTgdB1;
+    float bdsTgdB2;
+    float bdsTgdB2a;
+    float bdsIscB2a;
+    float galBgdE1E5a;
+    float galBgdE1E5b;
+    float navicTgdL5;
+} GnssSvPolynomial;
+
+typedef enum {
+    GNSS_EPH_ACTION_UPDATE_SRC_UNKNOWN_V02 = 0, /**<Update ephemeris. Source of ephemeris is unknown  */
+    GNSS_EPH_ACTION_UPDATE_SRC_OTA_V02         = 1, /**<Update ephemeris. Source of ephemeris is OTA  */
+    GNSS_EPH_ACTION_UPDATE_SRC_NETWORK_V02     = 2, /**<Update ephemeris. Source of ephemeris is Network  */
+    GNSS_EPH_ACTION_UPDATE_MAX_V02         = 999, /**<Max value for update ephemeris action. DO NOT USE  */
+    GNSS_EPH_ACTION_DELETE_SRC_UNKNOWN_V02 = 1000, /**<Delete previous ephemeris from unknown source  */
+    GNSS_EPH_ACTION_DELETE_SRC_NETWORK_V02 = 1001, /**<Delete previous ephemeris from network  */
+    GNSS_EPH_ACTION_DELETE_SRC_OTA_V02     = 1002, /**<Delete previous ephemeris from OTA  */
+    GNSS_EPH_ACTION_DELETE_MAX_V02     = 1999, /**<Max value for delete ephemeris action. DO NOT USE  */
+} GnssEphAction;
+
+typedef enum {
+    GAL_EPH_SIGNAL_SRC_UNKNOWN_V02 = 0, /**<  GALILEO signal is unknown  */
+    GAL_EPH_SIGNAL_SRC_E1B_V02     = 1, /**<  GALILEO signal is E1B  */
+    GAL_EPH_SIGNAL_SRC_E5A_V02     = 2, /**<  GALILEO signal is E5A  */
+    GAL_EPH_SIGNAL_SRC_E5B_V02     = 3, /**<  GALILEO signal is E5B  */
+} GalEphSignalSource;
+
+typedef struct {
+    uint16_t gnssSvId;
+    /** Unique SV Identifier.
+     *  For SV Range of supported constellation, please refer to the
+     *  comment section of gnssSvId in GpsMeasUsageInfo.
+     */
+
+    GnssEphAction updateAction;
+    /**<   Specifies the action and source of ephemeris. \n
+    - Type: int32 enum */
+
+    uint16_t IODE;
+    /**<   Issue of data ephemeris used (unit-less). \n
+        GPS: IODE 8 bits.\n
+        BDS: AODE 5 bits. \n
+        GAL: SIS IOD 10 bits. \n
+        - Type: uint16
+        - Units: Unit-less */
+
+    double aSqrt;
+    /**<   Square root of semi-major axis. \n
+      - Type: double
+      - Units: Square Root of Meters */
+
+    double deltaN;
+    /**<   Mean motion difference from computed value. \n
+      - Type: double
+      - Units: Radians/Second */
+
+    double m0;
+    /**<   Mean anomaly at reference time. \n
+      - Type: double
+      - Units: Radians */
+
+    double eccentricity;
+    /**<   Eccentricity . \n
+      - Type: double
+      - Units: Unit-less */
+
+    double omega0;
+    /**<   Longitude of ascending node of orbital plane at the weekly epoch. \n
+      - Type: double
+      - Units: Radians */
+
+    double i0;
+    /**<   Inclination angle at reference time. \n
+      - Type: double
+      - Units: Radians */
+
+    double omega;
+    /**<   Argument of Perigee. \n
+      - Type: double
+      - Units: Radians */
+
+    double omegaDot;
+    /**<   Rate of change of right ascension. \n
+      - Type: double
+      - Units: Radians/Second */
+
+    double iDot;
+    /**<   Rate of change of inclination angle. \n
+      - Type: double
+      - Units: Radians/Second */
+
+    double cUc;
+    /**<   Amplitude of the cosine harmonic correction term to the argument of latitude. \n
+      - Type: double
+      - Units: Radians */
+
+    double cUs;
+    /**<   Amplitude of the sine harmonic correction term to the argument of latitude. \n
+      - Type: double
+      - Units: Radians */
+
+    double cRc;
+    /**<   Amplitude of the cosine harmonic correction term to the orbit radius. \n
+      - Type: double
+      - Units: Meters */
+
+    double cRs;
+    /**<   Amplitude of the sine harmonic correction term to the orbit radius. \n
+      - Type: double
+      - Units: Meters */
+
+    double cIc;
+    /**<   Amplitude of the cosine harmonic correction term to the angle of inclination. \n
+      - Type: double
+      - Units: Radians */
+
+    double cIs;
+    /**<   Amplitude of the sine harmonic correction term to the angle of inclination. \n
+      - Type: double
+      - Units: Radians */
+
+    uint32_t toe;
+    /**<   Reference time of ephemeris. \n
+      - Type: uint32
+      - Units: Seconds */
+
+    uint32_t toc;
+    /**<   Clock data reference time of week.  \n
+      - Type: uint32
+      - Units: Seconds */
+
+    double af0;
+    /**<   Clock bias correction coefficient. \n
+      - Type: double
+      - Units: Seconds */
+
+    double af1;
+    /**<   Clock drift coefficient. \n
+      - Type: double
+      - Units: Seconds/Second */
+
+    double af2;
+    /**<   Clock drift rate correction coefficient. \n
+      - Type: double
+      - Units: Seconds/Seconds^2 */
+
+} GnssEphCommon;
+
+/* GPS Navigation Model Info */
+typedef struct {
+    GnssEphCommon commonEphemerisData;
+    /**<   Common ephemeris data.   */
+
+    uint8_t signalHealth;
+    /**<   Signal health. \n
+         Bit 0 : L5 Signal Health. \n
+         Bit 1 : L2 Signal Health. \n
+         Bit 2 : L1 Signal Health. \n
+         - Type: uint8
+         - Values: 3 bit mask of signal health, where set bit indicates unhealthy signal */
+
+    uint8_t URAI;
+    /**<   User Range Accuracy Index. \n
+         - Type: uint8
+         - Units: Unit-less */
+
+    uint8_t codeL2;
+    /**<   Indicates which codes are commanded ON for the L2 channel (2-bits). \n
+         - Type: uint8
+         Valid Values: \n
+         - 00 : Reserved
+         - 01 : P code ON
+         - 10 : C/A code ON */
+
+    uint8_t dataFlagL2P;
+    /**<   L2 P-code indication flag. \n
+         - Type: uint8
+         - Value 1 indicates that the Nav data stream was commanded OFF on the P-code of the L2 channel. */
+
+    double tgd;
+    /**<   Time of group delay. \n
+         - Type: double
+         - Units: Seconds */
+
+    uint8_t fitInterval;
+    /**<   Indicates the curve-fit interval used by the CS. \n
+         - Type: uint8
+         Valid Values:
+         - 0 : Four hours
+         - 1 : Greater than four hours */
+
+    uint16_t IODC;
+    /**<   Issue of Data, Clock. \n
+         - Type: uint16
+         - Units: Unit-less */
+} GpsEphemeris;
+
+/* GLONASS Navigation Model Info */
+typedef struct {
+
+    uint16_t gnssSvId;
+    /**<   GNSS SV ID.
+       - Type: uint16
+       - Range: 65 to 96 if known. When the slot number to SV ID mapping is unknown, set to 255 */
+
+    GnssEphAction updateAction;
+    /**<   Specifies the action and source of ephemeris. \n
+    - Type: int32 enum */
+
+    uint8_t bnHealth;
+    /**<   SV health flags. \n
+       - Type: uint8
+       Valid Values: \n
+    - 0 : Healthy
+    - 1 : Unhealthy */
+
+    uint8_t lnHealth;
+    /**<   Ln SV health flags. GLONASS-M. \n
+       - Type: uint8
+       Valid Values: \n
+    - 0 : Healthy
+    - 1 : Unhealthy */
+
+    uint8_t tb;
+    /**<   Index of a time interval within current day according to UTC(SU) + 03 hours 00 min. \n
+       - Type: uint8
+       - Units: Unit-less */
+
+    uint8_t ft;
+    /**<   SV accuracy index. \n
+       - Type: uint8
+       - Units: Unit-less */
+
+    uint8_t gloM;
+    /**<   GLONASS-M flag. \n
+       - Type: uint8
+       Valid Values: \n
+    - 0 : GLONASS
+    - 1 : GLONASS-M */
+
+    uint8_t enAge;
+    /**<   Characterizes "Age" of current information. \n
+       - Type: uint8
+       - Units: Days */
+
+    uint8_t gloFrequency;
+    /**<   GLONASS frequency number + 8. \n
+       - Type: uint8
+       - Range: 1 to 14
+    */
+
+    uint8_t p1;
+    /**<   Time interval between two adjacent values of tb parameter. \n
+       - Type: uint8
+       - Units: Minutes */
+
+    uint8_t p2;
+    /**<   Flag of oddness ("1") or evenness ("0") of the value of tb \n
+       for intervals 30 or 60 minutes. \n
+       - Type: uint8 */
+
+    float deltaTau;
+    /**<   Time difference between navigation RF signal transmitted in L2 sub-band \n
+       and aviation RF signal transmitted in L1 sub-band. \n
+       - Type: floating point
+       - Units: Seconds */
+
+    double position[3];
+    /**<   Satellite XYZ position. \n
+       - Type: array of doubles
+       - Units: Meters */
+
+    double velocity[3];
+    /**<   Satellite XYZ velocity. \n
+       - Type: array of doubles
+       - Units: Meters/Second */
+
+    double acceleration[3];
+    /**<   Satellite XYZ sola-luni acceleration. \n
+       - Type: array of doubles
+       - Units: Meters/Second^2 */
+
+    float tauN;
+    /**<   Satellite clock correction relative to GLONASS time. \n
+       - Type: floating point
+       - Units: Seconds */
+
+    float gamma;
+    /**<   Relative deviation of predicted carrier frequency value \n
+       from nominal value at the instant tb. \n
+       - Type: floating point
+       - Units: Unit-less */
+
+    double toe;
+    /**<   Complete ephemeris time, including N4, NT and Tb. \n
+       [(N4-1)*1461 + (NT-1)]*86400 + tb*900 \n
+       - Type: double
+       - Units: Seconds */
+
+    uint16_t nt;
+    /**<   Current date, calendar number of day within four-year interval. \n
+       Starting from the 1-st of January in a leap year. \n
+       - Type: uint16
+       - Units: Days */
+} GlonassEphemeris;
+
+/* BDS Navigation Model Info */
+typedef struct {
+
+    GnssEphCommon commonEphemerisData;
+    /**<   Common ephemeris data.   */
+
+    uint8_t svHealth;
+    /**<   Satellite health information applied to both B1 and B2 (SatH1). \n
+       - Type: uint8
+       Valid Values: \n
+       - 0 : Healthy
+       - 1 : Unhealthy */
+
+    uint8_t AODC;
+    /**<   Age of data clock. \n
+       - Type: uint8
+       - Units: Hours */
+
+    double tgd1;
+    /**<   Equipment group delay differential on B1 signal. \n
+       - Type: double
+       - Units: Nano-Seconds */
+
+    double tgd2;
+    /**<   Equipment group delay differential on B2 signal. \n
+       - Type: double
+       - Units: Nano-Seconds */
+
+    uint8_t URAI;
+    /**<   User range accuracy index (4-bits). \n
+       - Type: uint8
+       - Units: Unit-less */
+} BdsEphemeris;
+
+/* GALIELO Navigation Model Info */
+typedef struct {
+
+    GnssEphCommon commonEphemerisData;
+    /**<   Common ephemeris data.   */
+
+    GalEphSignalSource dataSourceSignal;
+    /**<   Galileo Signal Source. \n
+    Valid Values: \n
+      - GAL_EPH_SIGNAL_SRC_UNKNOWN (0) --  GALILEO signal is unknown
+      - GAL_EPH_SIGNAL_SRC_E1B (1) --  GALILEO signal is E1B
+      - GAL_EPH_SIGNAL_SRC_E5A (2) --  GALILEO signal is E5A
+      - GAL_EPH_SIGNAL_SRC_E5B (3) --  GALILEO signal is E5B  */
+
+    uint8_t sisIndex;
+    /**<   Signal-in-space index for dual frequency E1-E5b/E5a depending on dataSignalSource. \n
+       - Type: uint8
+       - Units: Unit-less */
+
+    double bgdE1E5a;
+    /**<   E1-E5a Broadcast group delay from F/Nav (E5A). \n
+       - Type: double
+       - Units: Seconds */
+
+    double bgdE1E5b;
+    /**<   E1-E5b Broadcast group delay from I/Nav (E1B or E5B). \n
+       For E1B or E5B signal, both bgdE1E5a and bgdE1E5b are valid. \n
+       For E5A signal, only bgdE1E5a is valid. \n
+       Signal source identified using dataSignalSource. \n
+       - Type: double
+       - Units: Seconds */
+
+    uint8_t svHealth;
+    /**<   SV health status of signal identified by dataSourceSignal. \n
+       - Type: uint8
+       Valid Values: \n
+       - 0 : Healthy
+       - 1 : Unhealthy */
+} GalileoEphemeris;
+
+/** GPS Navigation model for each SV */
+typedef struct {
+    uint16_t numOfEphemeris;
+    GpsEphemeris gpsEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} GpsEphemerisResponse;
+
+/** GLONASS Navigation model for each SV */
+typedef struct {
+    uint16_t numOfEphemeris;
+    GlonassEphemeris gloEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} GlonassEphemerisResponse;
+
+/** BDS Navigation model for each SV */
+typedef struct {
+    uint16_t numOfEphemeris;
+    BdsEphemeris bdsEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} BdsEphemerisResponse;
+
+/** GALILEO Navigation model for each SV */
+typedef struct {
+    uint16_t numOfEphemeris;
+    GalileoEphemeris galEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} GalileoEphemerisResponse;
+
+/** QZSS Navigation model for each SV */
+typedef struct {
+    uint16_t numOfEphemeris;
+    GpsEphemeris qzssEphemerisData[GNSS_EPHEMERIS_LIST_MAX_SIZE_V02];
+} QzssEphemerisResponse;
+
+
+typedef struct {
+    /** Indicates GNSS Constellation Type
+        Mandatory field */
+    Gnss_LocSvSystemEnumType gnssConstellation;
+
+    /** GPS System Time of the ephemeris report */
+    bool isSystemTimeValid;
+    GnssSystemTimeStructType systemTime;
+
+    union {
+       /** GPS Ephemeris */
+       GpsEphemerisResponse gpsEphemeris;
+       /** GLONASS Ephemeris */
+       GlonassEphemerisResponse glonassEphemeris;
+       /** BDS Ephemeris */
+       BdsEphemerisResponse bdsEphemeris;
+       /** GALILEO Ephemeris */
+       GalileoEphemerisResponse galileoEphemeris;
+       /** QZSS Ephemeris */
+       QzssEphemerisResponse qzssEphemeris;
+    } ephInfo;
+} GnssSvEphemerisReport;
+
+typedef struct {
+    /** GPS System Time of the iono model report */
+    bool isSystemTimeValid;
+    GnssSystemTimeStructType systemTime;
+
+    /** Indicates GNSS Constellation Type */
+    Gnss_LocSvSystemEnumType gnssConstellation;
+
+    float alpha0;
+    /**<   Klobuchar Model Parameter Alpha 0.
+         - Type: float
+         - Unit: Seconds
+    */
+
+    float alpha1;
+    /**<   Klobuchar Model Parameter Alpha 1.
+         - Type: float
+         - Unit: Seconds / Semi-Circle
+    */
+
+    float alpha2;
+    /**<   Klobuchar Model Parameter Alpha 2.
+         - Type: float
+         - Unit: Seconds / Semi-Circle^2
+    */
+
+    float alpha3;
+    /**<   Klobuchar Model Parameter Alpha 3.
+         - Type: float
+         - Unit: Seconds / Semi-Circle^3
+    */
+
+    float beta0;
+    /**<   Klobuchar Model Parameter Beta 0.
+         - Type: float
+         - Unit: Seconds
+    */
+
+    float beta1;
+    /**<   Klobuchar Model Parameter Beta 1.
+         - Type: float
+         - Unit: Seconds / Semi-Circle
+    */
+
+    float beta2;
+    /**<   Klobuchar Model Parameter Beta 2.
+         - Type: float
+         - Unit: Seconds / Semi-Circle^2
+    */
+
+    float beta3;
+    /**<   Klobuchar Model Parameter Beta 3.
+         - Type: float
+         - Unit: Seconds / Semi-Circle^3
+    */
+} GnssKlobucharIonoModel;
+
+typedef struct {
+        /** GPS System Time of the report */
+    bool isSystemTimeValid;
+    GnssSystemTimeStructType systemTime;
+
+    GnssAdditionalSystemInfoMask validityMask;
+    double tauC;
+    int8_t leapSec;
+} GnssAdditionalSystemInfo;
+
+/* Various Short Range Node Technology type*/
+typedef enum {
+    SRN_AP_DATA_TECH_TYPE_NONE,
+    SRN_AP_DATA_TECH_TYPE_BT,
+    SRN_AP_DATA_TECH_TYPE_BTLE,
+    SRN_AP_DATA_TECH_TYPE_NFC,
+    SRN_AP_DATA_TECH_TYPE_MOBILE_CODE,
+    SRN_AP_DATA_TECH_TYPE_OTHER
+} Gnss_SrnTech;
+
+/* Mac Address type requested by modem */
+typedef enum {
+    SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_INVALID, /* No valid mac address type send */
+    SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_PUBLIC, /* SRN AP MAC Address type PUBLIC  */
+    SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_PRIVATE, /* SRN AP MAC Address type PRIVATE  */
+    SRN_AP_DATA_PUBLIC_MAC_ADDR_TYPE_OTHER, /* SRN AP MAC Address type OTHER  */
+}Gnss_Srn_MacAddr_Type;
+
+typedef struct
+{
+    uint32_t                 size;
+    Gnss_SrnTech           srnTechType; /* SRN Technology type in request */
+    bool                   srnRequest; /* scan - start(true) or stop(false) */
+    bool                   e911Mode; /* If in E911 emergency */
+    Gnss_Srn_MacAddr_Type  macAddrType; /* SRN AP MAC Address type */
+} GnssSrnDataReq;
+
+/* 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.
+ */
+struct AGnssExtStatusIpV4 {
+    AGpsExtType         type;
+    LocApnTypeMask      apnTypeMask;
+    LocAGpsStatusValue  status;
+    /*
+     * 32-bit IPv4 address.
+     */
+    uint32_t            ipV4Addr;
+};
+
+/*
+ * Represents the status of AGNSS augmented to support IPv6.
+ */
+struct AGnssExtStatusIpV6 {
+    AGpsExtType         type;
+    LocApnTypeMask      apnTypeMask;
+    LocAGpsStatusValue  status;
+    /*
+     * 128-bit IPv6 address.
+     */
+    uint8_t             ipV6Addr[16];
+};
+
+/*
+* Represents the the Nfw Notification structure
+*/
+#define GNSS_MAX_NFW_APP_STRING_LEN 64
+#define GNSS_MAX_NFW_STRING_LEN  20
+
+typedef enum {
+    GNSS_NFW_CTRL_PLANE = 0,
+    GNSS_NFW_SUPL = 1,
+    GNSS_NFW_IMS = 10,
+    GNSS_NFW_SIM = 11,
+    GNSS_NFW_OTHER_PROTOCOL_STACK = 100
+} GnssNfwProtocolStack;
+
+typedef enum {
+    GNSS_NFW_CARRIER = 0,
+    GNSS_NFW_OEM = 10,
+    GNSS_NFW_MODEM_CHIPSET_VENDOR = 11,
+    GNSS_NFW_GNSS_CHIPSET_VENDOR = 12,
+    GNSS_NFW_OTHER_CHIPSET_VENDOR = 13,
+    GNSS_NFW_AUTOMOBILE_CLIENT = 20,
+    GNSS_NFW_OTHER_REQUESTOR = 100
+} GnssNfwRequestor;
+
+typedef enum {
+    GNSS_NFW_REJECTED = 0,
+    GNSS_NFW_ACCEPTED_NO_LOCATION_PROVIDED = 1,
+    GNSS_NFW_ACCEPTED_LOCATION_PROVIDED = 2,
+} GnssNfwResponseType;
+
+typedef struct {
+    char                    proxyAppPackageName[GNSS_MAX_NFW_APP_STRING_LEN];
+    GnssNfwProtocolStack    protocolStack;
+    char                    otherProtocolStackName[GNSS_MAX_NFW_STRING_LEN];
+    GnssNfwRequestor        requestor;
+    char                    requestorId[GNSS_MAX_NFW_STRING_LEN];
+    GnssNfwResponseType     responseType;
+    bool                    inEmergencyMode;
+    bool                    isCachedLocation;
+} GnssNfwNotification;
+
+typedef uint16_t GnssMeasurementCorrectionsCapabilitiesMask;
+typedef enum {
+    GNSS_MEAS_CORR_LOS_SATS            = 1 << 0,
+    GNSS_MEAS_CORR_EXCESS_PATH_LENGTH  = 1 << 1,
+    GNSS_MEAS_CORR_REFLECTING_PLANE    = 1 << 2,
+} GnssMeasurementCorrectionsCapabilities;
+
+/* Represents GNSS NMEA Report Rate Configuration */
+typedef enum {
+    GNSS_NMEA_REPORT_RATE_UNKNOWN  = 0,
+    GNSS_NMEA_REPORT_RATE_1HZ  = 1,
+    GNSS_NMEA_REPORT_RATE_NHZ  = 2
+} GnssNMEARptRate;
+
+/* ODCPI Request Info */
+enum OdcpiRequestType {
+    ODCPI_REQUEST_TYPE_START,
+    ODCPI_REQUEST_TYPE_STOP
+};
+struct OdcpiRequestInfo {
+    uint32_t size;
+    OdcpiRequestType type;
+    uint32_t tbfMillis;
+    bool isEmergencyMode;
+};
+/* Callback to send ODCPI request to framework */
+typedef std::function<void(const OdcpiRequestInfo& request)> OdcpiRequestCallback;
+
+/* ODCPI callback priorities*/
+enum OdcpiPrioritytype {
+    ODCPI_HANDLER_PRIORITY_LOW,
+    ODCPI_HANDLER_PRIORITY_HIGH
+};
+
+/*
+ * Callback with AGNSS(IpV4) status information.
+ *
+ * @param status Will be of type AGnssExtStatusIpV4.
+ */
+typedef void (*AgnssStatusIpV4Cb)(AGnssExtStatusIpV4 status);
+
+/*
+* Callback with AGNSS(IpV6) status information.
+*
+* @param status Will be of type AGnssExtStatusIpV6.
+*/
+typedef void (*AgnssStatusIpV6Cb)(AGnssExtStatusIpV6 status);
+
+/*
+* Callback with NFW information.
+*/
+typedef void(*NfwStatusCb)(GnssNfwNotification notification);
+typedef bool(*IsInEmergencySession)(void);
+
+enum AntennaInfoStatus {
+    ANTENNA_INFO_SUCCESS = 0,
+    ANTENNA_INFO_ERROR_ALREADY_INIT = 1,
+    ANTENNA_INFO_ERROR_GENERIC = 2
+};
+
+/*
+* Callback with Measurement corrections information.
+*/
+typedef void(*measCorrSetCapabilitiesCb)(GnssMeasurementCorrectionsCapabilitiesMask capabilities);
+
+/*
+ * Callback with AGNSS(IpV6) status information.
+ *
+ * @param status Will be of type AGnssExtStatusIpV6.
+ */
+typedef void (*AgnssStatusIpV6Cb)(AGnssExtStatusIpV6 status);
+
+/*
+* Callback with Antenna information.
+*/
+typedef void(*antennaInfoCb)(std::vector<GnssAntennaInformation> gnssAntennaInformations);
+
+/* Constructs for interaction with loc_net_iface library */
+typedef void (*LocAgpsOpenResultCb)(bool isSuccess, AGpsExtType agpsType, const char* apn,
+        AGpsBearerType bearerType, void* userDataPtr);
+
+typedef void (*LocAgpsCloseResultCb)(bool isSuccess, AGpsExtType agpsType, void* userDataPtr);
+
+enum PowerStateType {
+    POWER_STATE_UNKNOWN = 0,
+    POWER_STATE_SUSPEND = 1,
+    POWER_STATE_RESUME  = 2,
+    POWER_STATE_SHUTDOWN = 3
+};
+
+/* Shared resources of LocIpc */
+#define LOC_IPC_HAL                    "/dev/socket/location/socket_hal"
+#define LOC_IPC_XTRA                   "/dev/socket/location/xtra/socket_xtra"
+
+#define SOCKET_DIR_LOCATION            "/dev/socket/location/"
+#define SOCKET_DIR_EHUB                "/dev/socket/location/ehub/"
+#define SOCKET_TO_LOCATION_HAL_DAEMON  "/dev/socket/loc_client/hal_daemon"
+
+#define SOCKET_LOC_CLIENT_DIR          "/dev/socket/loc_client/"
+#define EAP_LOC_CLIENT_DIR             "/data/vendor/location/extap_locclient/"
+
+#define LOC_CLIENT_NAME_PREFIX         "toclient"
+// Please note that the socket name for all location hal daemon client need
+// to start with LOC_CLIENT_NAME_PREFIX so that upon hal daemon restarts,
+// every client can get the notification that hal daemon has restarted.
+#define LOC_INTAPI_NAME_PREFIX         LOC_CLIENT_NAME_PREFIX "_intapi"
+
+typedef uint64_t NetworkHandle;
+#define NETWORK_HANDLE_UNKNOWN  ~0
+#define MAX_NETWORK_HANDLES 10
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* GPS_EXTENDED_C_H */
diff --git a/gps/utils/linked_list.c b/gps/utils/linked_list.c
new file mode 100644
index 0000000..02e1463
--- /dev/null
+++ b/gps/utils/linked_list.c
@@ -0,0 +1,325 @@
+/* Copyright (c) 2011, 2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_TAG "LocSvc_utils_ll"
+
+#include "linked_list.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <loc_pla.h>
+#include <log_util.h>
+
+typedef struct list_element {
+   struct list_element* next;
+   struct list_element* prev;
+   void* data_ptr;
+   void (*dealloc_func)(void*);
+}list_element;
+
+typedef struct list_state {
+   list_element* p_head;
+   list_element* p_tail;
+} list_state;
+
+/* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */
+
+/*===========================================================================
+
+  FUNCTION:   linked_list_init
+
+  ===========================================================================*/
+linked_list_err_type linked_list_init(void** list_data)
+{
+   if( list_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+      return eLINKED_LIST_INVALID_PARAMETER;
+   }
+
+   list_state* tmp_list;
+   tmp_list = (list_state*)calloc(1, sizeof(list_state));
+   if( tmp_list == NULL )
+   {
+      LOC_LOGE("%s: Unable to allocate space for list!\n", __FUNCTION__);
+      return eLINKED_LIST_FAILURE_GENERAL;
+   }
+
+   tmp_list->p_head = NULL;
+   tmp_list->p_tail = NULL;
+
+   *list_data = tmp_list;
+
+   return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+  FUNCTION:   linked_list_destroy
+
+  ===========================================================================*/
+linked_list_err_type linked_list_destroy(void** list_data)
+{
+   if( list_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+      return eLINKED_LIST_INVALID_HANDLE;
+   }
+
+   list_state* p_list = (list_state*)*list_data;
+
+   linked_list_flush(p_list);
+
+   free(*list_data);
+   *list_data = NULL;
+
+   return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+  FUNCTION:   linked_list_add
+
+  ===========================================================================*/
+linked_list_err_type linked_list_add(void* list_data, void *data_obj, void (*dealloc)(void*))
+{
+   if( list_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+      return eLINKED_LIST_INVALID_HANDLE;
+   }
+
+   if( data_obj == NULL )
+   {
+      LOC_LOGE("%s: Invalid input parameter!\n", __FUNCTION__);
+      return eLINKED_LIST_INVALID_PARAMETER;
+   }
+
+   list_state* p_list = (list_state*)list_data;
+   list_element* elem = (list_element*)malloc(sizeof(list_element));
+   if( elem == NULL )
+   {
+      LOC_LOGE("%s: Memory allocation failed\n", __FUNCTION__);
+      return eLINKED_LIST_FAILURE_GENERAL;
+   }
+
+   /* Copy data to newly created element */
+   elem->data_ptr = data_obj;
+   elem->next = NULL;
+   elem->prev = NULL;
+   elem->dealloc_func = dealloc;
+
+   /* Replace head element */
+   list_element* tmp = p_list->p_head;
+   p_list->p_head = elem;
+   /* Point next to the previous head element */
+   p_list->p_head->next = tmp;
+
+   if( tmp != NULL )
+   {
+      tmp->prev = p_list->p_head;
+   }
+   else
+   {
+      p_list->p_tail = p_list->p_head;
+   }
+
+   return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+  FUNCTION:   linked_list_remove
+
+  ===========================================================================*/
+linked_list_err_type linked_list_remove(void* list_data, void **data_obj)
+{
+   if( list_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+      return eLINKED_LIST_INVALID_HANDLE;
+   }
+
+   if( data_obj == NULL )
+   {
+      LOC_LOGE("%s: Invalid input parameter!\n", __FUNCTION__);
+      return eLINKED_LIST_INVALID_PARAMETER;
+   }
+
+   list_state* p_list = (list_state*)list_data;
+   if( p_list->p_tail == NULL )
+   {
+      return eLINKED_LIST_UNAVAILABLE_RESOURCE;
+   }
+
+   list_element* tmp = p_list->p_tail;
+
+   /* Replace tail element */
+   p_list->p_tail = tmp->prev;
+
+   if( p_list->p_tail != NULL )
+   {
+      p_list->p_tail->next = NULL;
+   }
+   else
+   {
+      p_list->p_head = p_list->p_tail;
+   }
+
+   /* Copy data to output param */
+   *data_obj = tmp->data_ptr;
+
+   /* Free allocated list element */
+   free(tmp);
+
+   return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+  FUNCTION:   linked_list_empty
+
+  ===========================================================================*/
+int linked_list_empty(void* list_data)
+{
+   if( list_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+      return (int)eLINKED_LIST_INVALID_HANDLE;
+   }
+   else
+   {
+      list_state* p_list = (list_state*)list_data;
+      return p_list->p_head == NULL ? 1 : 0;
+   }
+}
+
+/*===========================================================================
+
+  FUNCTION:   linked_list_flush
+
+  ===========================================================================*/
+linked_list_err_type linked_list_flush(void* list_data)
+{
+   if( list_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
+      return eLINKED_LIST_INVALID_HANDLE;
+   }
+
+   list_state* p_list = (list_state*)list_data;
+
+   /* Remove all dynamically allocated elements */
+   while( p_list->p_head != NULL )
+   {
+      list_element* tmp = p_list->p_head->next;
+
+      /* Free data pointer if told to do so. */
+      if( p_list->p_head->dealloc_func != NULL )
+      {
+         p_list->p_head->dealloc_func(p_list->p_head->data_ptr);
+      }
+
+      /* Free list element */
+      free(p_list->p_head);
+
+      p_list->p_head = tmp;
+   }
+
+   p_list->p_tail = NULL;
+
+   return eLINKED_LIST_SUCCESS;
+}
+
+/*===========================================================================
+
+  FUNCTION:   linked_list_search
+
+  ===========================================================================*/
+linked_list_err_type linked_list_search(void* list_data, void **data_p,
+                                        bool (*equal)(void* data_0, void* data),
+                                        void* data_0, bool rm_if_found)
+{
+   if( list_data == NULL || NULL == equal )
+   {
+      LOC_LOGE("%s: Invalid list parameter! list_data %p equal %p\n",
+               __FUNCTION__, list_data, equal);
+      return eLINKED_LIST_INVALID_HANDLE;
+   }
+
+   list_state* p_list = (list_state*)list_data;
+   if( p_list->p_tail == NULL )
+   {
+      return eLINKED_LIST_UNAVAILABLE_RESOURCE;
+   }
+
+   list_element* tmp = p_list->p_head;
+
+   if (NULL != data_p) {
+     *data_p = NULL;
+   }
+
+   while (NULL != tmp) {
+     if ((*equal)(data_0, tmp->data_ptr)) {
+       if (NULL != data_p) {
+         *data_p = tmp->data_ptr;
+       }
+
+       if (rm_if_found) {
+         if (NULL == tmp->prev) {
+           p_list->p_head = tmp->next;
+         } else {
+           tmp->prev->next = tmp->next;
+         }
+
+         if (NULL == tmp->next) {
+           p_list->p_tail = tmp->prev;
+         } else {
+           tmp->next->prev = tmp->prev;
+         }
+
+         tmp->prev = tmp->next = NULL;
+
+         // dealloc data if it is not copied out && caller
+         // has given us a dealloc function pointer.
+         if (NULL == data_p && NULL != tmp->dealloc_func) {
+             tmp->dealloc_func(tmp->data_ptr);
+         }
+         free(tmp);
+       }
+
+       tmp = NULL;
+     } else {
+       tmp = tmp->next;
+     }
+   }
+
+   return eLINKED_LIST_SUCCESS;
+}
+
diff --git a/gps/utils/linked_list.h b/gps/utils/linked_list.h
new file mode 100644
index 0000000..0b33ecb
--- /dev/null
+++ b/gps/utils/linked_list.h
@@ -0,0 +1,219 @@
+/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __LINKED_LIST_H__
+#define __LINKED_LIST_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+/** Linked List Return Codes */
+typedef enum
+{
+  eLINKED_LIST_SUCCESS                             = 0,
+     /**< Request was successful. */
+  eLINKED_LIST_FAILURE_GENERAL                     = -1,
+     /**< Failed because of a general failure. */
+  eLINKED_LIST_INVALID_PARAMETER                   = -2,
+     /**< Failed because the request contained invalid parameters. */
+  eLINKED_LIST_INVALID_HANDLE                      = -3,
+     /**< Failed because an invalid handle was specified. */
+  eLINKED_LIST_UNAVAILABLE_RESOURCE                = -4,
+     /**< Failed because an there were not enough resources. */
+  eLINKED_LIST_INSUFFICIENT_BUFFER                 = -5,
+     /**< Failed because an the supplied buffer was too small. */
+  eLINKED_LIST_EMPTY                               = -6
+     /**< Failed because list is empty. */
+}linked_list_err_type;
+
+/*===========================================================================
+FUNCTION    linked_list_init
+
+DESCRIPTION
+   Initializes internal structures for linked list.
+
+   list_data: State of list to be initialized.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_init(void** list_data);
+
+/*===========================================================================
+FUNCTION    linked_list_destroy
+
+DESCRIPTION
+   Destroys internal structures for linked list.
+
+   p_list_data: State of list to be destroyed.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_destroy(void** list_data);
+
+/*===========================================================================
+FUNCTION    linked_list_add
+
+DESCRIPTION
+   Adds an element to the head of the linked list. The passed in data pointer
+   is not modified or freed. Passed in data_obj is expected to live throughout
+   the use of the linked_list (i.e. data is not allocated internally)
+
+   p_list_data:  List to add data to the head of.
+   data_obj:     Pointer to data to add into list
+   dealloc:      Function used to deallocate memory for this element. Pass NULL
+                 if you do not want data deallocated during a flush operation
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_add(void* list_data, void *data_obj, void (*dealloc)(void*));
+
+/*===========================================================================
+FUNCTION    linked_list_remove
+
+DESCRIPTION
+   Retrieves data from the list tail. data_obj is the tail element from the list
+   passed in by linked_list_add.
+
+   p_list_data:  List to remove the tail from.
+   data_obj:     Pointer to data removed from list
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_remove(void* list_data, void **data_obj);
+
+/*===========================================================================
+FUNCTION    linked_list_empty
+
+DESCRIPTION
+   Tells whether the list currently contains any elements
+
+   p_list_data:  List to check if empty.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   0/FALSE : List contains elements
+   1/TRUE  : List is Empty
+   Otherwise look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+int linked_list_empty(void* list_data);
+
+/*===========================================================================
+FUNCTION    linked_list_flush
+
+DESCRIPTION
+   Removes all elements from the list and deallocates them using the provided
+   dealloc function while adding elements.
+
+   p_list_data:  List to remove all elements from.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_flush(void* list_data);
+
+/*===========================================================================
+FUNCTION    linked_list_search
+
+DESCRIPTION
+   Searches for an element in the linked list.
+
+   p_list_data:  List handle.
+   data_p:       to be stored with the data found; NUll if no match.
+                 if data_p passed in as NULL, then no write to it.
+   equal:        Function ptr takes in a list element, and returns
+                 indication if this the one looking for.
+   data_0:       The data being compared against.
+   rm_if_found:  Should data be removed if found?
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+linked_list_err_type linked_list_search(void* list_data, void **data_p,
+                                        bool (*equal)(void* data_0, void* data),
+                                        void* data_0, bool rm_if_found);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __LINKED_LIST_H__ */
diff --git a/gps/utils/loc_cfg.cpp b/gps/utils/loc_cfg.cpp
new file mode 100644
index 0000000..2a89966
--- /dev/null
+++ b/gps/utils/loc_cfg.cpp
@@ -0,0 +1,1140 @@
+/* Copyright (c) 2011-2015, 2018-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_utils_cfg"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <grp.h>
+#include <errno.h>
+#include <loc_cfg.h>
+#include <loc_pla.h>
+#include <loc_target.h>
+#include <loc_misc_utils.h>
+#ifdef USE_GLIB
+#include <glib.h>
+#endif
+#include "log_util.h"
+
+/*=============================================================================
+ *
+ *                          GLOBAL DATA DECLARATION
+ *
+ *============================================================================*/
+
+/* Parameter data */
+static uint32_t DEBUG_LEVEL = 0xff;
+static uint32_t TIMESTAMP = 0;
+static uint32_t DATUM_TYPE = 0;
+static bool sVendorEnhanced = true;
+static uint32_t sLogBufferEnabled = 0;
+
+/* Parameter spec table */
+static const loc_param_s_type loc_param_table[] =
+{
+    {"DEBUG_LEVEL",             &DEBUG_LEVEL,        NULL, 'n'},
+    {"TIMESTAMP",               &TIMESTAMP,          NULL, 'n'},
+    {"DATUM_TYPE",              &DATUM_TYPE,         NULL, 'n'},
+    {"LOG_BUFFER_ENABLED",      &sLogBufferEnabled,  NULL, 'n'},
+};
+static const int loc_param_num = sizeof(loc_param_table) / sizeof(loc_param_s_type);
+
+typedef struct loc_param_v_type
+{
+    char* param_name;
+    char* param_str_value;
+    int param_int_value;
+    double param_double_value;
+}loc_param_v_type;
+
+// Reference below arrays wherever needed to avoid duplicating
+// same conf path string over and again in location code.
+const char LOC_PATH_GPS_CONF[] = LOC_PATH_GPS_CONF_STR;
+const char LOC_PATH_IZAT_CONF[] = LOC_PATH_IZAT_CONF_STR;
+const char LOC_PATH_FLP_CONF[] = LOC_PATH_FLP_CONF_STR;
+const char LOC_PATH_LOWI_CONF[] = LOC_PATH_LOWI_CONF_STR;
+const char LOC_PATH_SAP_CONF[] = LOC_PATH_SAP_CONF_STR;
+const char LOC_PATH_APDR_CONF[] = LOC_PATH_APDR_CONF_STR;
+const char LOC_PATH_XTWIFI_CONF[] = LOC_PATH_XTWIFI_CONF_STR;
+const char LOC_PATH_QUIPC_CONF[] = LOC_PATH_QUIPC_CONF_STR;
+const char LOC_PATH_ANT_CORR[] = LOC_PATH_ANT_CORR_STR;
+const char LOC_PATH_SLIM_CONF[] = LOC_PATH_SLIM_CONF_STR;
+const char LOC_PATH_VPE_CONF[] = LOC_PATH_VPE_CONF_STR;
+
+bool isVendorEnhanced() {
+    return sVendorEnhanced;
+}
+void setVendorEnhanced(bool vendorEnhanced) {
+    sVendorEnhanced = vendorEnhanced;
+}
+
+/*===========================================================================
+FUNCTION loc_get_datum_type
+
+DESCRIPTION
+   get datum type
+
+PARAMETERS:
+   N/A
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   DATUM TYPE
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+int loc_get_datum_type()
+{
+    return DATUM_TYPE;
+}
+
+/*===========================================================================
+FUNCTION loc_set_config_entry
+
+DESCRIPTION
+   Potentially sets a given configuration table entry based on the passed in
+   configuration value. This is done by using a string comparison of the
+   parameter names and those found in the configuration file.
+
+PARAMETERS:
+   config_entry: configuration entry in the table to possibly set
+   config_value: value to store in the entry if the parameter names match
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   None
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+int loc_set_config_entry(const loc_param_s_type* config_entry,
+                        loc_param_v_type* config_value,
+                        uint16_t string_len = LOC_MAX_PARAM_STRING)
+{
+    int ret=-1;
+    if(NULL == config_entry || NULL == config_value)
+    {
+        LOC_LOGE("%s: INVALID config entry or parameter", __FUNCTION__);
+        return ret;
+    }
+
+    if (strcmp(config_entry->param_name, config_value->param_name) == 0 &&
+        config_entry->param_ptr)
+    {
+        switch (config_entry->param_type)
+        {
+        case 's':
+            if (strcmp(config_value->param_str_value, "NULL") == 0)
+            {
+                *((char*)config_entry->param_ptr) = '\0';
+            }
+            else {
+                strlcpy((char*) config_entry->param_ptr,
+                        config_value->param_str_value,
+                        string_len);
+            }
+            /* Log INI values */
+            LOC_LOGD("%s: PARAM %s = %s", __FUNCTION__,
+                     config_entry->param_name, (char*)config_entry->param_ptr);
+
+            if(NULL != config_entry->param_set)
+            {
+                *(config_entry->param_set) = 1;
+            }
+            ret = 0;
+            break;
+        case 'n':
+            *((int *)config_entry->param_ptr) = config_value->param_int_value;
+            /* Log INI values */
+            LOC_LOGD("%s: PARAM %s = %d", __FUNCTION__,
+                     config_entry->param_name, config_value->param_int_value);
+
+            if(NULL != config_entry->param_set)
+            {
+                *(config_entry->param_set) = 1;
+            }
+            ret = 0;
+            break;
+        case 'f':
+            *((double *)config_entry->param_ptr) = config_value->param_double_value;
+            /* Log INI values */
+            LOC_LOGD("%s: PARAM %s = %f", __FUNCTION__,
+                     config_entry->param_name, config_value->param_double_value);
+
+            if(NULL != config_entry->param_set)
+            {
+                *(config_entry->param_set) = 1;
+            }
+            ret = 0;
+            break;
+        default:
+            LOC_LOGE("%s: PARAM %s parameter type must be n, f, or s",
+                     __FUNCTION__, config_entry->param_name);
+        }
+    }
+    return ret;
+}
+
+/*===========================================================================
+FUNCTION loc_fill_conf_item
+
+DESCRIPTION
+   Takes a line of configuration item and sets defined values based on
+   the passed in configuration table. This table maps strings to values to
+   set along with the type of each of these values.
+
+PARAMETERS:
+   input_buf : buffer contanis config item
+   config_table: table definition of strings to places to store information
+   table_length: length of the configuration table
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   0: Number of records in the config_table filled with input_buf
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+int loc_fill_conf_item(char* input_buf,
+                       const loc_param_s_type* config_table,
+                       uint32_t table_length, uint16_t string_len = LOC_MAX_PARAM_STRING)
+{
+    int ret = 0;
+
+    if (input_buf && config_table) {
+        char *lasts;
+        loc_param_v_type config_value;
+        memset(&config_value, 0, sizeof(config_value));
+
+        /* Separate variable and value */
+        config_value.param_name = strtok_r(input_buf, "=", &lasts);
+        /* skip lines that do not contain "=" */
+        if (config_value.param_name) {
+            config_value.param_str_value = strtok_r(NULL, "\0", &lasts);
+
+            /* skip lines that do not contain two operands */
+            if (config_value.param_str_value) {
+                /* Trim leading and trailing spaces */
+                loc_util_trim_space(config_value.param_name);
+                loc_util_trim_space(config_value.param_str_value);
+
+                /* Parse numerical value */
+                if ((strlen(config_value.param_str_value) >=3) &&
+                    (config_value.param_str_value[0] == '0') &&
+                    (tolower(config_value.param_str_value[1]) == 'x'))
+                {
+                    /* hex */
+                    config_value.param_int_value = (int) strtol(&config_value.param_str_value[2],
+                                                                (char**) NULL, 16);
+                }
+                else {
+                    config_value.param_double_value = (double) atof(config_value.param_str_value); /* float */
+                    config_value.param_int_value = atoi(config_value.param_str_value); /* dec */
+                }
+
+                for(uint32_t i = 0; NULL != config_table && i < table_length; i++)
+                {
+                    if(!loc_set_config_entry(&config_table[i], &config_value, string_len)) {
+                        ret += 1;
+                    }
+                }
+            }
+        }
+    }
+
+    return ret;
+}
+
+/*===========================================================================
+FUNCTION loc_read_conf_r_long (repetitive)
+
+DESCRIPTION
+   Reads the specified configuration file and sets defined values based on
+   the passed in configuration table. This table maps strings to values to
+   set along with the type of each of these values.
+   The difference between this and loc_read_conf is that this function returns
+   the file pointer position at the end of filling a config table. Also, it
+   reads a fixed number of parameters at a time which is equal to the length
+   of the configuration table. This functionality enables the caller to
+   repeatedly call the function to read data from the same file.
+
+PARAMETERS:
+   conf_fp : file pointer
+   config_table: table definition of strings to places to store information
+   table_length: length of the configuration table
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   0: Table filled successfully
+   1: No more parameters to read
+  -1: Error filling table
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+int loc_read_conf_r_long(FILE *conf_fp, const loc_param_s_type* config_table,
+                         uint32_t table_length, uint16_t string_len)
+{
+    int ret=0;
+    char input_buf[string_len];  /* declare a char array */
+    unsigned int num_params=table_length;
+
+    if(conf_fp == NULL) {
+        LOC_LOGE("%s:%d]: ERROR: File pointer is NULL\n", __func__, __LINE__);
+        ret = -1;
+        goto err;
+    }
+
+    /* Clear all validity bits */
+    for(uint32_t i = 0; NULL != config_table && i < table_length; i++)
+    {
+        if(NULL != config_table[i].param_set)
+        {
+            *(config_table[i].param_set) = 0;
+        }
+    }
+
+    LOC_LOGD("%s:%d]: num_params: %d\n", __func__, __LINE__, num_params);
+    while(num_params)
+    {
+        if(!fgets(input_buf, string_len, conf_fp)) {
+            LOC_LOGD("%s:%d]: fgets returned NULL\n", __func__, __LINE__);
+            break;
+        }
+
+        num_params -= loc_fill_conf_item(input_buf, config_table, table_length, string_len);
+    }
+
+err:
+    return ret;
+}
+
+/*===========================================================================
+FUNCTION loc_udpate_conf_long
+
+DESCRIPTION
+   Parses the passed in buffer for configuration items, and update the table
+   that is also passed in.
+
+Reads the specified configuration file and sets defined values based on
+   the passed in configuration table. This table maps strings to values to
+   set along with the type of each of these values.
+
+PARAMETERS:
+   conf_data: configuration items in bufferas a string
+   length: strlen(conf_data)
+   config_table: table definition of strings to places to store information
+   table_length: length of the configuration table
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   number of the records in the table that is updated at time of return.
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+int loc_update_conf_long(const char* conf_data, int32_t length,
+                         const loc_param_s_type* config_table,
+                         uint32_t table_length, uint16_t string_len)
+{
+    int ret = -1;
+
+    if (conf_data && length && config_table && table_length) {
+        // make a copy, so we do not tokenize the original data
+        char* conf_copy = (char*)malloc(length+1);
+
+        if (conf_copy != NULL)
+        {
+            memcpy(conf_copy, conf_data, length);
+            // we hard NULL the end of string to be safe
+            conf_copy[length] = 0;
+
+            // start with one record off
+            uint32_t num_params = table_length - 1;
+            char* saveptr = NULL;
+            char* input_buf = strtok_r(conf_copy, "\n", &saveptr);
+            ret = 0;
+
+            LOC_LOGD("%s:%d]: num_params: %d\n", __func__, __LINE__, num_params);
+            while(num_params && input_buf) {
+                ret++;
+                num_params -=
+                        loc_fill_conf_item(input_buf, config_table, table_length, string_len);
+                input_buf = strtok_r(NULL, "\n", &saveptr);
+            }
+            free(conf_copy);
+        }
+    }
+
+    return ret;
+}
+
+/*===========================================================================
+FUNCTION loc_read_conf_long
+
+DESCRIPTION
+   Reads the specified configuration file and sets defined values based on
+   the passed in configuration table. This table maps strings to values to
+   set along with the type of each of these values.
+
+PARAMETERS:
+   conf_file_name: configuration file to read
+   config_table: table definition of strings to places to store information
+   table_length: length of the configuration table
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   None
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+void loc_read_conf_long(const char* conf_file_name, const loc_param_s_type* config_table,
+                        uint32_t table_length, uint16_t string_len)
+{
+    FILE *conf_fp = NULL;
+
+    log_buffer_init(false);
+    if((conf_fp = fopen(conf_file_name, "r")) != NULL)
+    {
+        LOC_LOGD("%s: using %s", __FUNCTION__, conf_file_name);
+        if(table_length && config_table) {
+            loc_read_conf_r_long(conf_fp, config_table, table_length, string_len);
+            rewind(conf_fp);
+        }
+        loc_read_conf_r_long(conf_fp, loc_param_table, loc_param_num, string_len);
+        fclose(conf_fp);
+    }
+    /* Initialize logging mechanism with parsed data */
+    loc_logger_init(DEBUG_LEVEL, TIMESTAMP);
+    log_buffer_init(sLogBufferEnabled);
+    log_tag_level_map_init();
+}
+
+/*=============================================================================
+ *
+ *   Define and Structures for Parsing Location Process Configuration File
+ *
+ *============================================================================*/
+#define MAX_NUM_STRINGS   20
+
+//We can have 8 masks for now
+#define CONFIG_MASK_TARGET_ALL           0X01
+#define CONFIG_MASK_TARGET_FOUND         0X02
+#define CONFIG_MASK_TARGET_CHECK         0X03
+#define CONFIG_MASK_BASEBAND_ALL         0X04
+#define CONFIG_MASK_BASEBAND_FOUND       0X08
+#define CONFIG_MASK_BASEBAND_CHECK       0x0c
+#define CONFIG_MASK_AUTOPLATFORM_ALL     0x10
+#define CONFIG_MASK_AUTOPLATFORM_FOUND   0x20
+#define CONFIG_MASK_AUTOPLATFORM_CHECK   0x30
+#define CONFIG_MASK_SOCID_ALL            0x40
+#define CONFIG_MASK_SOCID_FOUND          0x80
+#define CONFIG_MASK_SOCID_CHECK          0xc0
+
+#define LOC_FEATURE_MASK_GTP_WIFI_BASIC            0x01
+#define LOC_FEATURE_MASK_GTP_WIFI_PREMIUM          0X02
+#define LOC_FEATURE_MASK_GTP_CELL_BASIC            0X04
+#define LOC_FEATURE_MASK_GTP_CELL_PREMIUM          0X08
+#define LOC_FEATURE_MASK_SAP_BASIC                 0x40
+#define LOC_FEATURE_MASK_SAP_PREMIUM               0X80
+#define LOC_FEATURE_MASK_GTP_WAA_BASIC             0X100
+#define LOC_FEATURE_MASK_GTP_MODEM_CELL_BASIC      0X400
+#define LOC_FEATURE_MASK_ODCPI                     0x1000
+#define LOC_FEATURE_MASK_FREE_WIFI_SCAN_INJECT     0x2000
+#define LOC_FEATURE_MASK_SUPL_WIFI                 0x4000
+#define LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO      0x8000
+
+typedef struct {
+    char proc_name[LOC_MAX_PARAM_STRING];
+    char proc_argument[LOC_MAX_PARAM_STRING];
+    char proc_status[LOC_MAX_PARAM_STRING];
+    char group_list[LOC_MAX_PARAM_STRING];
+    unsigned int premium_feature;
+    unsigned int loc_feature_mask;
+    char platform_list[LOC_MAX_PARAM_STRING];
+    char baseband[LOC_MAX_PARAM_STRING];
+    char low_ram_targets[LOC_MAX_PARAM_STRING];
+    char soc_id_list[LOC_MAX_PARAM_STRING];
+    unsigned int sglte_target;
+    char feature_gtp_mode[LOC_MAX_PARAM_STRING];
+    char feature_gtp_waa[LOC_MAX_PARAM_STRING];
+    char feature_sap[LOC_MAX_PARAM_STRING];
+    char feature_odcpi[LOC_MAX_PARAM_STRING];
+    char feature_free_wifi_scan_inject[LOC_MAX_PARAM_STRING];
+    char feature_supl_wifi[LOC_MAX_PARAM_STRING];
+    char feature_wifi_supplicant_info[LOC_MAX_PARAM_STRING];
+    char auto_platform[LOC_MAX_PARAM_STRING];
+    unsigned int vendor_enhanced_process;
+} loc_launcher_conf;
+
+/* process configuration parameters */
+static loc_launcher_conf conf;
+
+/* gps.conf Parameter spec table */
+static const loc_param_s_type gps_conf_parameter_table[] = {
+    {"SGLTE_TARGET",        &conf.sglte_target,           NULL, 'n'},
+};
+
+/* location feature conf, e.g.: izat.conf feature mode table*/
+static const loc_param_s_type loc_feature_conf_table[] = {
+    {"GTP_MODE",              &conf.feature_gtp_mode,               NULL, 's'},
+    {"GTP_WAA",               &conf.feature_gtp_waa,                NULL, 's'},
+    {"SAP",                   &conf.feature_sap,                    NULL, 's'},
+    {"ODCPI",                 &conf.feature_odcpi,                  NULL, 's'},
+    {"FREE_WIFI_SCAN_INJECT", &conf.feature_free_wifi_scan_inject,  NULL, 's'},
+    {"SUPL_WIFI",             &conf.feature_supl_wifi,              NULL, 's'},
+    {"WIFI_SUPPLICANT_INFO",  &conf.feature_wifi_supplicant_info,   NULL, 's'},
+};
+
+/* location process conf, e.g.: izat.conf Parameter spec table */
+static const loc_param_s_type loc_process_conf_parameter_table[] = {
+    {"PROCESS_NAME",               &conf.proc_name,                NULL, 's'},
+    {"PROCESS_ARGUMENT",           &conf.proc_argument,            NULL, 's'},
+    {"PROCESS_STATE",              &conf.proc_status,              NULL, 's'},
+    {"PROCESS_GROUPS",             &conf.group_list,               NULL, 's'},
+    {"PREMIUM_FEATURE",            &conf.premium_feature,          NULL, 'n'},
+    {"IZAT_FEATURE_MASK",          &conf.loc_feature_mask,         NULL, 'n'},
+    {"PLATFORMS",                  &conf.platform_list,            NULL, 's'},
+    {"SOC_IDS",                    &conf.soc_id_list,            NULL, 's'},
+    {"BASEBAND",                   &conf.baseband,                 NULL, 's'},
+    {"LOW_RAM_TARGETS",            &conf.low_ram_targets,          NULL, 's'},
+    {"HARDWARE_TYPE",              &conf.auto_platform,            NULL, 's'},
+    {"VENDOR_ENHANCED_PROCESS",    &conf.vendor_enhanced_process,  NULL, 'n'},
+};
+
+/*===========================================================================
+FUNCTION loc_read_process_conf
+
+DESCRIPTION
+   Parse the specified conf file and return info for the processes defined.
+   The format of the file should conform with izat.conf.
+
+PARAMETERS:
+   conf_file_name: configuration file to read
+   process_count_ptr: pointer to store number of processes defined in the conf file.
+   process_info_table_ptr: pointer to store the process info table.
+
+DEPENDENCIES
+   The file must be in izat.conf format.
+
+RETURN VALUE
+   0: success
+   none-zero: failure
+
+SIDE EFFECTS
+   N/A
+
+NOTES:
+   On success, memory pointed by (*process_info_table_ptr) must be freed.
+===========================================================================*/
+int loc_read_process_conf(const char* conf_file_name, uint32_t * process_count_ptr,
+                          loc_process_info_s_type** process_info_table_ptr) {
+    loc_process_info_s_type *child_proc = nullptr;
+    volatile int i=0;
+    unsigned int j=0;
+    gid_t gid_list[LOC_PROCESS_MAX_NUM_GROUPS];
+    char *split_strings[MAX_NUM_STRINGS];
+    int name_length=0, group_list_length=0, platform_length=0, baseband_length=0, ngroups=0, ret=0;
+    int auto_platform_length = 0, soc_id_list_length=0;
+    int group_index=0, nstrings=0, status_length=0;
+    FILE* conf_fp = nullptr;
+    char platform_name[PROPERTY_VALUE_MAX], baseband_name[PROPERTY_VALUE_MAX];
+    int low_ram_target=0;
+    char autoplatform_name[PROPERTY_VALUE_MAX], socid_value[PROPERTY_VALUE_MAX];
+    unsigned int loc_service_mask=0;
+    unsigned char config_mask = 0;
+    unsigned char proc_list_length=0;
+    int gtp_cell_ap_enabled = 0;
+    char arg_gtp_waa[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--";
+    char arg_gtp_modem_cell[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--";
+    char arg_gtp_wifi[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--";
+    char arg_sap[LOC_PROCESS_MAX_ARG_STR_LENGTH] = "--";
+    char arg_disabled[LOC_PROCESS_MAX_ARG_STR_LENGTH] = LOC_FEATURE_MODE_DISABLED;
+    char arg_basic[LOC_PROCESS_MAX_ARG_STR_LENGTH] = LOC_FEATURE_MODE_BASIC;
+    char arg_premium[LOC_PROCESS_MAX_ARG_STR_LENGTH] = LOC_FEATURE_MODE_PREMIUM;
+
+    if (process_count_ptr == NULL || process_info_table_ptr == NULL) {
+        return -1;
+    }
+
+    //Read gps.conf and fill parameter table
+    UTIL_READ_CONF(LOC_PATH_GPS_CONF, gps_conf_parameter_table);
+
+    //Form argument strings
+    strlcat(arg_gtp_waa, LOC_FEATURE_GTP_WAA, LOC_PROCESS_MAX_ARG_STR_LENGTH-3);
+    strlcat(arg_gtp_modem_cell, LOC_FEATURE_GTP_MODEM_CELL, LOC_PROCESS_MAX_ARG_STR_LENGTH-3);
+    strlcat(arg_gtp_wifi, LOC_FEATURE_GTP_WIFI, LOC_PROCESS_MAX_ARG_STR_LENGTH-3);
+    strlcat(arg_sap, LOC_FEATURE_SAP, LOC_PROCESS_MAX_ARG_STR_LENGTH-3);
+
+    //Get platform name from ro.board.platform property
+    loc_get_platform_name(platform_name, sizeof(platform_name));
+    //Get baseband name from ro.baseband property
+    loc_get_target_baseband(baseband_name, sizeof(baseband_name));
+    //Identify if this is an automotive platform
+    loc_get_auto_platform_name(autoplatform_name,sizeof(autoplatform_name));
+    //Identify if this is a low ram target from ro.config.low_ram property
+    low_ram_target = loc_identify_low_ram_target();
+    // Get the soc-id for this device.
+    loc_get_device_soc_id(socid_value, sizeof(socid_value));
+
+    UTIL_READ_CONF(conf_file_name, loc_feature_conf_table);
+
+    //Set service mask for GTP_MODE
+    if (strcmp(conf.feature_gtp_mode, "DISABLED") == 0) {
+        LOC_LOGD("%s:%d]: GTP MODE DISABLED", __func__, __LINE__);
+    }
+    else if (strcmp(conf.feature_gtp_mode, "LEGACY_WWAN") == 0) {
+        LOC_LOGD("%s:%d]: Setting GTP MODE to mode: LEGACY_WWAN", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_GTP_MODEM_CELL_BASIC;
+    }
+    else if (strcmp(conf.feature_gtp_mode, "SDK") == 0) {
+        LOC_LOGD("%s:%d]: Setting GTP MODE to mode: SDK", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_GTP_WIFI_BASIC;
+    }
+    else if (strcmp(conf.feature_gtp_mode, "SDK_WIFI") == 0) {
+        LOC_LOGD("%s:%d]: Setting GTP MODE to mode: SDK", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_GTP_WIFI_BASIC;
+    }
+    //conf file has a garbage value
+    else {
+        LOC_LOGE("%s:%d]: Unrecognized value for GTP MODE Mode."\
+                 " Setting GTP WIFI to default mode: DISABLED", __func__, __LINE__);
+    }
+    //Set service mask for GTP_WAA
+    if (strcmp(conf.feature_gtp_waa, "BASIC") == 0) {
+      LOC_LOGD("%s:%d]: Setting GTP WAA to mode: BASIC", __func__, __LINE__);
+      loc_service_mask |= LOC_FEATURE_MASK_GTP_WAA_BASIC;
+    }
+    else if (strcmp(conf.feature_gtp_waa, "DISABLED") == 0) {
+      LOC_LOGD("%s:%d]: GTP WAA DISABLED", __func__, __LINE__);
+    }
+    //conf file has a garbage value
+    else {
+      LOC_LOGE("%s:%d]: Unrecognized value for GTP WAA Mode."\
+               " Setting GTP WAA to default mode: DISABLED", __func__, __LINE__);
+    }
+
+    //Set service mask for SAP
+    if(strcmp(conf.feature_sap, "PREMIUM") == 0 ||
+       strcmp(conf.feature_sap, "PREMIUM_ENV_AIDING") == 0) {
+        LOC_LOGD("%s:%d]: Setting SAP to mode: PREMIUM", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_SAP_PREMIUM;
+    }
+    else if (strcmp(conf.feature_sap, "BASIC") == 0) {
+        LOC_LOGD("%s:%d]: Setting SAP to mode: BASIC", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_SAP_BASIC;
+    }
+    else if (strcmp(conf.feature_sap, "MODEM_DEFAULT") == 0) {
+        LOC_LOGD("%s:%d]: Setting SAP to mode: MODEM_DEFAULT", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_SAP_BASIC;
+    }
+    else if (strcmp(conf.feature_sap, "DISABLED") == 0) {
+#ifdef USE_GLIB
+        /* Enable slim_daemon even when SAP is set to DISABLED*/
+        loc_service_mask |= LOC_FEATURE_MASK_SAP_BASIC;
+#else
+        LOC_LOGD("%s:%d]: Setting SAP to mode: DISABLED", __func__, __LINE__);
+#endif
+    }
+    else {
+       LOC_LOGE("%s:%d]: Unrecognized value for SAP Mode."\
+                " Setting SAP to default mode: BASIC", __func__, __LINE__);
+       loc_service_mask |= LOC_FEATURE_MASK_SAP_BASIC;
+    }
+
+    // Set service mask for ODCPI
+    if (strcmp(conf.feature_odcpi, "BASIC") == 0) {
+        LOC_LOGD("%s:%d]: Setting ODCPI to mode: BASIC", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_ODCPI;
+    }
+    else if (strcmp(conf.feature_odcpi, "DISABLED") == 0) {
+        LOC_LOGD("%s:%d]: Setting ODCPI to mode: DISABLED", __func__, __LINE__);
+    }
+    else if (strcmp(conf.feature_odcpi, "PREMIUM") == 0) {
+        LOC_LOGD("%s:%d]: Unrecognized value for ODCPI mode."\
+            "Setting ODCPI to default mode: BASIC", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_ODCPI;
+    }
+
+    // Set service mask for FREE_WIFI_SCAN_INJECT
+    if (strcmp(conf.feature_free_wifi_scan_inject, "BASIC") == 0) {
+        LOC_LOGD("%s:%d]: Setting FREE_WIFI_SCAN_INJECT to mode: BASIC", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_FREE_WIFI_SCAN_INJECT;
+    }
+    else if (strcmp(conf.feature_free_wifi_scan_inject, "DISABLED") == 0) {
+        LOC_LOGD("%s:%d]: Setting FREE_WIFI_SCAN_INJECT to mode: DISABLED", __func__, __LINE__);
+    }
+    else if (strcmp(conf.feature_free_wifi_scan_inject, "PREMIUM") == 0) {
+        LOC_LOGD("%s:%d]: Unrecognized value for FREE_WIFI_SCAN_INJECT mode."\
+            "Setting FREE_WIFI_SCAN_INJECT to default mode: BASIC", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_FREE_WIFI_SCAN_INJECT;
+    }
+
+    // Set service mask for SUPL_WIFI
+    if (strcmp(conf.feature_supl_wifi, "BASIC") == 0) {
+        LOC_LOGD("%s:%d]: Setting SUPL_WIFI to mode: BASIC", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_SUPL_WIFI;
+    }
+    else if (strcmp(conf.feature_supl_wifi, "DISABLED") == 0) {
+        LOC_LOGD("%s:%d]: Setting SUPL_WIFI to mode: DISABLED", __func__, __LINE__);
+    }
+    else if (strcmp(conf.feature_supl_wifi, "PREMIUM") == 0) {
+        LOC_LOGD("%s:%d]: Unrecognized value for SUPL_WIFI mode."\
+            "Setting SUPL_WIFI to default mode: BASIC", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_SUPL_WIFI;
+    }
+
+    // Set service mask for WIFI_SUPPLICANT_INFO
+    if (strcmp(conf.feature_wifi_supplicant_info, "BASIC") == 0) {
+        LOC_LOGD("%s:%d]: Setting WIFI_SUPPLICANT_INFO to mode: BASIC", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO;
+    }
+    else if (strcmp(conf.feature_wifi_supplicant_info, "DISABLED") == 0) {
+        LOC_LOGD("%s:%d]: Setting WIFI_SUPPLICANT_INFO to mode: DISABLED", __func__, __LINE__);
+    }
+    else if (strcmp(conf.feature_wifi_supplicant_info, "PREMIUM") == 0) {
+        LOC_LOGD("%s:%d]: Unrecognized value for WIFI_SUPPLICANT_INFO mode."\
+            "Setting LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO to default mode: BASIC", __func__, __LINE__);
+        loc_service_mask |= LOC_FEATURE_MASK_WIFI_SUPPLICANT_INFO;
+    }
+
+    LOC_LOGD("%s:%d]: loc_service_mask: %x\n", __func__, __LINE__, loc_service_mask);
+
+    if((conf_fp = fopen(conf_file_name, "r")) == NULL) {
+        LOC_LOGE("%s:%d]: Error opening %s %s\n", __func__,
+                 __LINE__, conf_file_name, strerror(errno));
+        ret = -1;
+        goto err;
+    }
+
+    //Parse through the file to find out how many processes are to be launched
+    proc_list_length = 0;
+    do {
+        conf.proc_name[0] = 0;
+        //Here note that the 3rd parameter is passed as 1.
+        //This is so that only the first parameter in the table which is "PROCESS_NAME"
+        //is read. We do not want to read the entire block of parameters at this time
+        //since we are only counting the number of processes to launch.
+        //Therefore, only counting the occurrences of PROCESS_NAME parameter
+        //should suffice
+        if(loc_read_conf_r(conf_fp, loc_process_conf_parameter_table, 1)) {
+            LOC_LOGE("%s:%d]: Unable to read conf file. Failing\n", __func__, __LINE__);
+            ret = -1;
+            goto err;
+        }
+        name_length=(int)strlen(conf.proc_name);
+        if(name_length) {
+            proc_list_length++;
+            LOC_LOGD("Process name:%s", conf.proc_name);
+        }
+    } while(name_length);
+    LOC_LOGD("Process cnt = %d", proc_list_length);
+
+    child_proc = (loc_process_info_s_type *)calloc(proc_list_length, sizeof(loc_process_info_s_type));
+    if(child_proc == NULL) {
+        LOC_LOGE("%s:%d]: ERROR: Malloc returned NULL\n", __func__, __LINE__);
+        ret = -1;
+        goto err;
+    }
+
+    //Move file descriptor to the beginning of the file
+    //so that the parameters can be read
+    rewind(conf_fp);
+
+    for(j=0; j<proc_list_length; j++) {
+        //Set defaults for all the child process structs
+        child_proc[j].proc_status = DISABLED;
+        memset(child_proc[j].group_list, 0, sizeof(child_proc[j].group_list));
+        config_mask=0;
+        if(loc_read_conf_r(conf_fp, loc_process_conf_parameter_table,
+                           sizeof(loc_process_conf_parameter_table)/sizeof(loc_process_conf_parameter_table[0]))) {
+            LOC_LOGE("%s:%d]: Unable to read conf file. Failing\n", __func__, __LINE__);
+            ret = -1;
+            goto err;
+        }
+
+        name_length=(int)strlen(conf.proc_name);
+        group_list_length=(int)strlen(conf.group_list);
+        platform_length = (int)strlen(conf.platform_list);
+        baseband_length = (int)strlen(conf.baseband);
+        status_length = (int)strlen(conf.proc_status);
+        auto_platform_length = (int)strlen(conf.auto_platform);
+        soc_id_list_length = (int)strlen(conf.soc_id_list);
+
+        if(!name_length || !group_list_length || !platform_length ||
+           !baseband_length || !status_length || !auto_platform_length || !soc_id_list_length) {
+            LOC_LOGE("%s:%d]: Error: i: %d; One of the parameters not specified in conf file",
+                     __func__, __LINE__, i);
+            continue;
+        }
+
+        if (!isVendorEnhanced() && (conf.vendor_enhanced_process != 0)) {
+            LOC_LOGD("%s:%d]: Process %s is disabled via vendor enhanced process check",
+                     __func__, __LINE__, conf.proc_name);
+            child_proc[j].proc_status = DISABLED_VIA_VENDOR_ENHANCED_CHECK;
+            continue;
+        }
+
+        if (strcmp(conf.proc_status, "DISABLED") == 0) {
+            LOC_LOGD("%s:%d]: Process %s is disabled in conf file",
+                     __func__, __LINE__, conf.proc_name);
+            child_proc[j].proc_status = DISABLED_FROM_CONF;
+            continue;
+        }
+        else if (strcmp(conf.proc_status, "ENABLED") == 0) {
+            LOC_LOGD("%s:%d]: Process %s is enabled in conf file",
+                     __func__, __LINE__, conf.proc_name);
+        }
+
+        //Since strlcpy copies length-1 characters, we add 1 to name_length
+        if((name_length+1) > LOC_MAX_PARAM_STRING) {
+            LOC_LOGE("%s:%d]: i: %d; Length of name parameter too long. Max length: %d",
+                     __func__, __LINE__, i, LOC_MAX_PARAM_STRING);
+            continue;
+        }
+        strlcpy(child_proc[j].name[0], conf.proc_name, sizeof (child_proc[j].name[0]));
+
+        child_proc[j].num_groups = 0;
+        ngroups = loc_util_split_string(conf.group_list, split_strings, MAX_NUM_STRINGS, ' ');
+        for(i=0; i<ngroups; i++) {
+            struct group* grp = getgrnam(split_strings[i]);
+            if (grp) {
+                child_proc[j].group_list[child_proc[j].num_groups] = grp->gr_gid;
+                child_proc[j].num_groups++;
+                LOC_LOGd("Group %s = %d", split_strings[i], grp->gr_gid);
+            }
+        }
+
+        nstrings = loc_util_split_string(conf.platform_list, split_strings, MAX_NUM_STRINGS, ' ');
+        if (strcmp("all", split_strings[0]) == 0) {
+            if (nstrings == 1 || (nstrings == 2 && (strcmp("exclude", split_strings[1]) == 0))) {
+                LOC_LOGD("%s:%d]: Enabled for all targets\n", __func__, __LINE__);
+                config_mask |= CONFIG_MASK_TARGET_ALL;
+            }
+            else if (nstrings > 2 && (strcmp("exclude", split_strings[1]) == 0)) {
+                config_mask |= CONFIG_MASK_TARGET_FOUND;
+                for (i=2; i<nstrings; i++) {
+                    if (strcmp(platform_name, split_strings[i]) == 0) {
+                        LOC_LOGD("%s:%d]: Disabled platform %s\n", __func__, __LINE__, platform_name);
+                        config_mask &= ~CONFIG_MASK_TARGET_FOUND;
+                        break;
+                    }
+                }
+            }
+        }
+        else {
+            for(i=0; i<nstrings; i++) {
+                if (strcmp(platform_name, split_strings[i]) == 0) {
+                    LOC_LOGD("%s:%d]: Matched platform: %s\n",
+                             __func__, __LINE__, split_strings[i]);
+                    config_mask |= CONFIG_MASK_TARGET_FOUND;
+                    break;
+                }
+            }
+        }
+
+        // SOC Id's check
+        nstrings = loc_util_split_string(conf.soc_id_list, split_strings, MAX_NUM_STRINGS, ' ');
+        if (strcmp("all", split_strings[0]) == 0) {
+            if (nstrings == 1 || (nstrings == 2 && (strcmp("exclude", split_strings[1]) == 0))) {
+                LOC_LOGd("Enabled for all SOC ids\n");
+                config_mask |= CONFIG_MASK_SOCID_ALL;
+            }
+            else if (nstrings > 2 && (strcmp("exclude", split_strings[1]) == 0)) {
+                config_mask |= CONFIG_MASK_SOCID_FOUND;
+                for (i = 2; i < nstrings; i++) {
+                    if (strcmp(socid_value, split_strings[i]) == 0) {
+                        LOC_LOGd("Disabled for SOC id %s\n", socid_value);
+                        config_mask &= ~CONFIG_MASK_SOCID_FOUND;
+                        break;
+                    }
+                }
+            }
+        }
+        else {
+            for (i = 0; i < nstrings; i++) {
+                if (strcmp(socid_value, split_strings[i]) == 0) {
+                    LOC_LOGd("Matched SOC id : %s\n", split_strings[i]);
+                    config_mask |= CONFIG_MASK_SOCID_FOUND;
+                    break;
+                }
+            }
+        }
+
+        nstrings = loc_util_split_string(conf.baseband, split_strings, MAX_NUM_STRINGS, ' ');
+        if (strcmp("all", split_strings[0]) == 0) {
+            if (nstrings == 1 || (nstrings == 2 && (strcmp("exclude", split_strings[1]) == 0))) {
+                LOC_LOGD("%s:%d]: Enabled for all basebands\n", __func__, __LINE__);
+                config_mask |= CONFIG_MASK_BASEBAND_ALL;
+            }
+            else if (nstrings > 2 && (strcmp("exclude", split_strings[1]) == 0)) {
+                config_mask |= CONFIG_MASK_BASEBAND_FOUND;
+                for (i=2; i<nstrings; i++) {
+                    if (strcmp(baseband_name, split_strings[i]) == 0) {
+                        LOC_LOGD("%s:%d]: Disabled band %s\n", __func__, __LINE__, baseband_name);
+                        config_mask &= ~CONFIG_MASK_BASEBAND_FOUND;
+                        break;
+                    }
+                }
+            }
+        }
+        else {
+            for(i=0; i<nstrings; i++) {
+                if (strcmp(baseband_name, split_strings[i]) == 0) {
+                    LOC_LOGD("%s:%d]: Matched baseband: %s\n",
+                             __func__, __LINE__, split_strings[i]);
+                    config_mask |= CONFIG_MASK_BASEBAND_FOUND;
+                    break;
+                }
+                //Since ro.baseband is not a reliable source for detecting sglte
+                //the alternative is to read the SGLTE_TARGET parameter from gps.conf
+                //this parameter is read into conf_sglte_target
+                else if((strcmp("sglte", split_strings[i]) == 0 ) && conf.sglte_target) {
+                    LOC_LOGD("%s:%d]: Matched baseband SGLTE\n", __func__, __LINE__);
+                    config_mask |= CONFIG_MASK_BASEBAND_FOUND;
+                    break;
+                }
+            }
+        }
+
+        nstrings = loc_util_split_string(conf.auto_platform, split_strings, MAX_NUM_STRINGS, ' ');
+        if (strcmp("all", split_strings[0]) == 0) {
+            LOC_LOGD("%s:%d]: Enabled for all auto platforms\n", __func__, __LINE__);
+            config_mask |= CONFIG_MASK_AUTOPLATFORM_ALL;
+        }
+        else {
+            for(i=0; i<nstrings; i++) {
+                if (strcmp(autoplatform_name, split_strings[i]) == 0) {
+                    LOC_LOGD("%s:%d]: Matched auto platform: %s\n",
+                             __func__, __LINE__, split_strings[i]);
+                    config_mask |= CONFIG_MASK_AUTOPLATFORM_FOUND;
+                    break;
+                }
+            }
+        }
+
+        nstrings = loc_util_split_string(conf.low_ram_targets, split_strings, MAX_NUM_STRINGS, ' ');
+        if (!strcmp("DISABLED", split_strings[0]) && low_ram_target) {
+            LOC_LOGd("Disabled for low ram targets\n");
+            child_proc[j].proc_status = DISABLED;
+            continue;
+        }
+
+        if((config_mask & CONFIG_MASK_TARGET_CHECK) &&
+           (config_mask & CONFIG_MASK_BASEBAND_CHECK) &&
+           (config_mask & CONFIG_MASK_AUTOPLATFORM_CHECK) &&
+           (config_mask & CONFIG_MASK_SOCID_CHECK) &&
+           (child_proc[j].proc_status != DISABLED_FROM_CONF) &&
+           (child_proc[j].proc_status != DISABLED_VIA_VENDOR_ENHANCED_CHECK)) {
+
+            //Set args
+            //The first argument passed through argv is usually the name of the
+            //binary when started from commandline.
+            //getopt() seems to ignore this first argument and hence we assign it
+            //to the process name for consistency with command line args
+            i = 0;
+            char* temp_arg = ('/' == child_proc[j].name[0][0]) ?
+                (strrchr(child_proc[j].name[0], '/') + 1) : child_proc[j].name[0];
+            strlcpy (child_proc[j].args[i++], temp_arg, sizeof (child_proc[j].args[0]));
+
+            if(conf.premium_feature) {
+               if(conf.loc_feature_mask & loc_service_mask) {
+                    LOC_LOGD("%s:%d]: Enabled. %s has service mask: %x\n",
+                             __func__, __LINE__, child_proc[j].name[0], conf.loc_feature_mask);
+                    child_proc[j].proc_status = ENABLED;
+
+                    if(conf.loc_feature_mask &
+                       (LOC_FEATURE_MASK_GTP_WIFI_BASIC | LOC_FEATURE_MASK_GTP_WIFI_PREMIUM)) {
+                        if(loc_service_mask & LOC_FEATURE_MASK_GTP_WIFI_BASIC) {
+                            strlcpy(child_proc[j].args[i++], arg_gtp_wifi,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                            strlcpy(child_proc[j].args[i++], arg_basic,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                        }
+                        else if(loc_service_mask & LOC_FEATURE_MASK_GTP_WIFI_PREMIUM) {
+                            strlcpy(child_proc[j].args[i++], arg_gtp_wifi,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                            strlcpy(child_proc[j].args[i++], arg_premium,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                        }
+                        else
+                        {
+                            strlcpy(child_proc[j].args[i++], arg_gtp_wifi,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                            strlcpy(child_proc[j].args[i++], arg_disabled,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                        }
+                    }
+                    if(conf.loc_feature_mask &
+                       (LOC_FEATURE_MASK_GTP_CELL_BASIC | LOC_FEATURE_MASK_GTP_CELL_PREMIUM )) {
+                        if(loc_service_mask & LOC_FEATURE_MASK_GTP_MODEM_CELL_BASIC) {
+                            strlcpy(child_proc[j].args[i++], arg_gtp_modem_cell,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                            strlcpy(child_proc[j].args[i++], arg_basic,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                        }
+                        else {
+                             strlcpy(child_proc[j].args[i++], arg_gtp_modem_cell,
+                                     LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                             strlcpy(child_proc[j].args[i++], arg_disabled,
+                                     LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                       }
+                    }
+                    if(conf.loc_feature_mask &
+                       (LOC_FEATURE_MASK_SAP_BASIC | LOC_FEATURE_MASK_SAP_PREMIUM)) {
+                        if(loc_service_mask & LOC_FEATURE_MASK_SAP_BASIC) {
+                            strlcpy(child_proc[j].args[i++], arg_sap,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                            strlcpy(child_proc[j].args[i++], arg_basic,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                        }
+                        else if(loc_service_mask & LOC_FEATURE_MASK_SAP_PREMIUM) {
+                            strlcpy(child_proc[j].args[i++], arg_sap,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                            strlcpy(child_proc[j].args[i++], arg_premium,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                        }
+                        else
+                        {
+                            strlcpy(child_proc[j].args[i++], arg_sap,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                            strlcpy(child_proc[j].args[i++], arg_disabled,
+                                    LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                        }
+                    }
+
+                    if(conf.loc_feature_mask & LOC_FEATURE_MASK_GTP_WAA_BASIC) {
+                      if(loc_service_mask & LOC_FEATURE_MASK_GTP_WAA_BASIC) {
+                        strlcpy(child_proc[j].args[i++], arg_gtp_waa,
+                                LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                        strlcpy(child_proc[j].args[i++], arg_basic,
+                                LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                      }
+                      else
+                      {
+                        strlcpy(child_proc[j].args[i++], arg_gtp_waa,
+                                LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                        strlcpy(child_proc[j].args[i++], arg_disabled,
+                                LOC_PROCESS_MAX_ARG_STR_LENGTH);
+                      }
+                    }
+                    IF_LOC_LOGD {
+                        LOC_LOGD("%s:%d]: %s args\n", __func__, __LINE__, child_proc[j].name[0]);
+                        for(unsigned int k=0; k<LOC_PROCESS_MAX_NUM_ARGS; k++) {
+                            if(child_proc[j].args[k][0] != '\0') {
+                                LOC_LOGD("%s:%d]: k: %d, %s\n", __func__, __LINE__, k,
+                                         child_proc[j].args[k]);
+                            }
+                        }
+                        LOC_LOGD("%s:%d]: \n", __func__, __LINE__);
+                    }
+                }
+                else {
+                    LOC_LOGD("%s:%d]: Disabled. %s has service mask:  %x \n",
+                             __func__, __LINE__, child_proc[j].name[0], conf.loc_feature_mask);
+                }
+            }
+            else {
+                LOC_LOGD("%s:%d]: %s not a premium feature. Enabled\n",
+                         __func__, __LINE__, child_proc[j].name[0]);
+                child_proc[j].proc_status = ENABLED;
+            }
+
+            /*Fill up the remaining arguments from configuration file*/
+            LOC_LOGD("%s] Parsing Process_Arguments from Configuration: %s \n",
+                      __func__, conf.proc_argument);
+            if(0 != conf.proc_argument[0])
+            {
+                /**************************************
+                ** conf_proc_argument is shared by all the programs getting launched,
+                ** hence copy to process specific argument string and parse the same.
+                ***************************************/
+                strlcpy(child_proc[j].argumentString, conf.proc_argument,
+                        sizeof(child_proc[j].argumentString));
+                char *temp_args[LOC_PROCESS_MAX_NUM_ARGS];
+                memset (temp_args, 0, sizeof (temp_args));
+                loc_util_split_string(child_proc[j].argumentString, &temp_args[i],
+                                      (LOC_PROCESS_MAX_NUM_ARGS - i), ' ');
+                // copy argument from the pointer to the memory
+                for (unsigned int index = i; index < LOC_PROCESS_MAX_NUM_ARGS; index++) {
+                    if (temp_args[index] == NULL) {
+                        break;
+                    }
+                    strlcpy (child_proc[j].args[index], temp_args[index],
+                             sizeof (child_proc[j].args[index]));
+                }
+            }
+        }
+        else {
+            LOC_LOGD("%s:%d]: Process %s is disabled\n",
+                     __func__, __LINE__, child_proc[j].name[0]);
+        }
+    }
+
+err:
+    if (conf_fp) {
+        fclose(conf_fp);
+    }
+    if (ret != 0) {
+        LOC_LOGE("%s:%d]: ret: %d", __func__, __LINE__, ret);
+        if (child_proc) {
+            free (child_proc);
+            child_proc = nullptr;
+        }
+        *process_count_ptr = 0;
+        *process_info_table_ptr = nullptr;
+
+    }
+    else {
+        *process_count_ptr = proc_list_length;
+        *process_info_table_ptr = child_proc;
+    }
+
+    return ret;
+}
diff --git a/gps/utils/loc_cfg.h b/gps/utils/loc_cfg.h
new file mode 100644
index 0000000..e87d632
--- /dev/null
+++ b/gps/utils/loc_cfg.h
@@ -0,0 +1,167 @@
+/* Copyright (c) 2011-2015, 2018, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOC_CFG_H
+#define LOC_CFG_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <grp.h>
+
+#define LOC_MAX_PARAM_NAME                 80
+#define LOC_MAX_PARAM_STRING               172
+#define LOC_MAX_PARAM_LINE    (LOC_MAX_PARAM_NAME + LOC_MAX_PARAM_STRING)
+
+#define LOC_FEATURE_MODE_DISABLED "DISABLED"
+#define LOC_FEATURE_MODE_BASIC    "BASIC"
+#define LOC_FEATURE_MODE_PREMIUM  "PREMIUM"
+
+#define LOC_FEATURE_GTP_AP_CELL        "gtp-ap-cell"
+#define LOC_FEATURE_GTP_MODEM_CELL     "gtp-modem-cell"
+#define LOC_FEATURE_GTP_CELL_ENH       "gtp-cell-enh"
+#define LOC_FEATURE_GTP_WIFI           "gtp-wifi"
+#define LOC_FEATURE_GTP_WAA            "gtp-waa"
+#define LOC_FEATURE_SAP                "sap"
+
+#define LOC_PROCESS_MAX_NUM_GROUPS     20
+#define LOC_PROCESS_MAX_NUM_ARGS       25
+#define LOC_PROCESS_MAX_ARG_STR_LENGTH 32
+
+#define UTIL_UPDATE_CONF(conf_data, len, config_table) \
+    loc_update_conf((conf_data), (len), (&config_table[0]), \
+                    sizeof(config_table) / sizeof(config_table[0]))
+
+#define UTIL_READ_CONF_DEFAULT(filename) \
+    loc_read_conf((filename), NULL, 0);
+
+#define UTIL_READ_CONF(filename, config_table) \
+    loc_read_conf((filename), (&config_table[0]), sizeof(config_table) / sizeof(config_table[0]))
+
+#define UTIL_READ_CONF_LONG(filename, config_table, rec_len) \
+    loc_read_conf_long((filename), (&config_table[0]), \
+            sizeof(config_table) / sizeof(config_table[0]), (rec_len))
+
+/*=============================================================================
+ *
+ *                        MODULE TYPE DECLARATION
+ *
+ *============================================================================*/
+typedef struct
+{
+  const char *param_name;
+  void       *param_ptr;   /* for string type, buf size need to be LOC_MAX_PARAM_STRING */
+  uint8_t    *param_set;   /* indicate value set by config file */
+  char        param_type;  /* 'n' for number,
+                              's' for string, NOTE: buf size need to be LOC_MAX_PARAM_STRING
+                              'f' for double */
+} loc_param_s_type;
+
+typedef enum {
+    ENABLED,
+    RUNNING,
+    DISABLED,
+    DISABLED_FROM_CONF,
+    DISABLED_VIA_VENDOR_ENHANCED_CHECK
+} loc_process_e_status;
+
+typedef struct {
+    loc_process_e_status proc_status;
+    pid_t                proc_id;
+    char                 name[2][LOC_MAX_PARAM_STRING];
+    gid_t                group_list[LOC_PROCESS_MAX_NUM_GROUPS];
+    unsigned char        num_groups;
+    char                 args[LOC_PROCESS_MAX_NUM_ARGS][LOC_PROCESS_MAX_ARG_STR_LENGTH];
+    char                 argumentString[LOC_MAX_PARAM_STRING];
+} loc_process_info_s_type;
+
+/*=============================================================================
+ *
+ *                          MODULE EXTERNAL DATA
+ *
+ *============================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=============================================================================
+ *
+ *                       MODULE EXPORTED FUNCTIONS
+ *
+ *============================================================================*/
+bool isVendorEnhanced();
+void setVendorEnhanced(bool vendorEnhanced);
+void loc_read_conf_long(const char* conf_file_name,
+                        const loc_param_s_type* config_table,
+                        uint32_t table_length, uint16_t string_len);
+int loc_read_conf_r_long(FILE *conf_fp, const loc_param_s_type* config_table,
+                         uint32_t table_length, uint16_t string_len);
+int loc_update_conf_long(const char* conf_data, int32_t length,
+                         const loc_param_s_type* config_table, uint32_t table_length,
+                         uint16_t string_len);
+
+inline void loc_read_conf(const char* conf_file_name,
+                          const loc_param_s_type* config_table, uint32_t table_length) {
+    loc_read_conf_long(conf_file_name, config_table, table_length, LOC_MAX_PARAM_STRING);
+}
+
+inline int loc_read_conf_r(FILE *conf_fp, const loc_param_s_type* config_table,
+                    uint32_t table_length) {
+    return (loc_read_conf_r_long(conf_fp, config_table, table_length, LOC_MAX_PARAM_STRING));
+}
+
+inline int loc_update_conf(const char* conf_data, int32_t length,
+                    const loc_param_s_type* config_table, uint32_t table_length) {
+    return (loc_update_conf_long(
+                    conf_data, length, config_table, table_length, LOC_MAX_PARAM_STRING));
+}
+
+// Below are the location conf file paths
+extern const char LOC_PATH_GPS_CONF[];
+extern const char LOC_PATH_IZAT_CONF[];
+extern const char LOC_PATH_FLP_CONF[];
+extern const char LOC_PATH_LOWI_CONF[];
+extern const char LOC_PATH_SAP_CONF[];
+extern const char LOC_PATH_APDR_CONF[];
+extern const char LOC_PATH_XTWIFI_CONF[];
+extern const char LOC_PATH_QUIPC_CONF[];
+extern const char LOC_PATH_ANT_CORR[];
+extern const char LOC_PATH_SLIM_CONF[];
+extern const char LOC_PATH_VPE_CONF[];
+
+int loc_read_process_conf(const char* conf_file_name, uint32_t * process_count_ptr,
+                          loc_process_info_s_type** process_info_table_ptr);
+int loc_get_datum_type();
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LOC_CFG_H */
diff --git a/gps/utils/loc_gps.h b/gps/utils/loc_gps.h
new file mode 100644
index 0000000..90541c4
--- /dev/null
+++ b/gps/utils/loc_gps.h
@@ -0,0 +1,2235 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef LOC_GPS_H
+#define LOC_GPS_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <stdbool.h>
+
+__BEGIN_DECLS
+
+#define LOC_FLP_STATUS_LOCATION_AVAILABLE         0
+#define LOC_FLP_STATUS_LOCATION_UNAVAILABLE       1
+#define LOC_CAPABILITY_GNSS         (1U<<0)
+#define LOC_CAPABILITY_WIFI         (1U<<1)
+#define LOC_CAPABILITY_CELL         (1U<<3)
+
+/** Milliseconds since January 1, 1970 */
+typedef int64_t LocGpsUtcTime;
+
+/** Maximum number of SVs for loc_gps_sv_status_callback(). */
+#define LOC_GPS_MAX_SVS 32
+/** Maximum number of SVs for loc_gps_sv_status_callback(). */
+#define LOC_GNSS_MAX_SVS 64
+
+/** Maximum number of Measurements in loc_gps_measurement_callback(). */
+#define LOC_GPS_MAX_MEASUREMENT   32
+
+/** Maximum number of Measurements in loc_gnss_measurement_callback(). */
+#define LOC_GNSS_MAX_MEASUREMENT   64
+
+/** Requested operational mode for GPS operation. */
+typedef uint32_t LocGpsPositionMode;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+/** Mode for running GPS standalone (no assistance). */
+#define LOC_GPS_POSITION_MODE_STANDALONE    0
+/** AGPS MS-Based mode. */
+#define LOC_GPS_POSITION_MODE_MS_BASED      1
+/**
+ * AGPS MS-Assisted mode. This mode is not maintained by the platform anymore.
+ * It is strongly recommended to use LOC_GPS_POSITION_MODE_MS_BASED instead.
+ */
+#define LOC_GPS_POSITION_MODE_MS_ASSISTED   2
+
+/** Requested recurrence mode for GPS operation. */
+typedef uint32_t LocGpsPositionRecurrence;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+/** Receive GPS fixes on a recurring basis at a specified period. */
+#define LOC_GPS_POSITION_RECURRENCE_PERIODIC    0
+/** Request a single shot GPS fix. */
+#define LOC_GPS_POSITION_RECURRENCE_SINGLE      1
+
+/** GPS status event values. */
+typedef uint16_t LocGpsStatusValue;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+/** GPS status unknown. */
+#define LOC_GPS_STATUS_NONE             0
+/** GPS has begun navigating. */
+#define LOC_GPS_STATUS_SESSION_BEGIN    1
+/** GPS has stopped navigating. */
+#define LOC_GPS_STATUS_SESSION_END      2
+/** GPS has powered on but is not navigating. */
+#define LOC_GPS_STATUS_ENGINE_ON        3
+/** GPS is powered off. */
+#define LOC_GPS_STATUS_ENGINE_OFF       4
+
+/** Flags to indicate which values are valid in a LocGpsLocation. */
+typedef uint16_t LocGpsLocationFlags;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+/** LocGpsLocation has valid latitude and longitude. */
+#define LOC_GPS_LOCATION_HAS_LAT_LONG   0x0001
+/** LocGpsLocation has valid altitude. */
+#define LOC_GPS_LOCATION_HAS_ALTITUDE   0x0002
+/** LocGpsLocation has valid speed. */
+#define LOC_GPS_LOCATION_HAS_SPEED      0x0004
+/** LocGpsLocation has valid bearing. */
+#define LOC_GPS_LOCATION_HAS_BEARING    0x0008
+/** LocGpsLocation has valid accuracy. */
+#define LOC_GPS_LOCATION_HAS_ACCURACY   0x0010
+/** LocGpsLocation has valid vertical uncertainity */
+#define LOC_GPS_LOCATION_HAS_VERT_UNCERTAINITY   0x0040
+/** LocGpsLocation has valid spoof mask */
+#define LOC_GPS_LOCATION_HAS_SPOOF_MASK   0x0080
+/** LocGpsLocation has valid speed accuracy */
+#define LOC_GPS_LOCATION_HAS_SPEED_ACCURACY   0x0100
+/** LocGpsLocation has valid bearing accuracy */
+#define LOC_GPS_LOCATION_HAS_BEARING_ACCURACY 0x0200
+/** LocGpsLocation has valid Real Time and Real Time Uncertainty */
+#define LOC_GPS_LOCATION_HAS_ELAPSED_REAL_TIME 0x0400
+
+/** Spoof mask in LocGpsLocation */
+typedef uint32_t LocGpsSpoofMask;
+#define LOC_GPS_LOCATION_NONE_SPOOFED            0x0000
+#define LOC_GPS_LOCATION_POSITION_SPOOFED        0x0001
+#define LOC_GPS_LOCATION_TIME_SPOOFED            0x0002
+#define LOC_GPS_LOCATION_NAVIGATION_DATA_SPOOFED 0x0004
+
+/** Flags for the loc_gps_set_capabilities callback. */
+
+/**
+ * GPS HAL schedules fixes for LOC_GPS_POSITION_RECURRENCE_PERIODIC mode. If this is
+ * not set, then the framework will use 1000ms for min_interval and will start
+ * and call start() and stop() to schedule the GPS.
+ */
+#define LOC_GPS_CAPABILITY_SCHEDULING       (1 << 0)
+/** GPS supports MS-Based AGPS mode */
+#define LOC_GPS_CAPABILITY_MSB              (1 << 1)
+/** GPS supports MS-Assisted AGPS mode */
+#define LOC_GPS_CAPABILITY_MSA              (1 << 2)
+/** GPS supports single-shot fixes */
+#define LOC_GPS_CAPABILITY_SINGLE_SHOT      (1 << 3)
+/** GPS supports on demand time injection */
+#define LOC_GPS_CAPABILITY_ON_DEMAND_TIME   (1 << 4)
+/** GPS supports Geofencing  */
+#define LOC_GPS_CAPABILITY_GEOFENCING       (1 << 5)
+/** GPS supports Measurements. */
+#define LOC_GPS_CAPABILITY_MEASUREMENTS     (1 << 6)
+/** GPS supports Navigation Messages */
+#define LOC_GPS_CAPABILITY_NAV_MESSAGES     (1 << 7)
+
+/**
+ * Flags used to specify which aiding data to delete when calling
+ * delete_aiding_data().
+ */
+typedef uint16_t LocGpsAidingData;
+/* IMPORTANT: Note that the following values must match
+ * constants in GpsLocationProvider.java. */
+#define LOC_GPS_DELETE_EPHEMERIS        0x0001
+#define LOC_GPS_DELETE_ALMANAC          0x0002
+#define LOC_GPS_DELETE_POSITION         0x0004
+#define LOC_GPS_DELETE_TIME             0x0008
+#define LOC_GPS_DELETE_IONO             0x0010
+#define LOC_GPS_DELETE_UTC              0x0020
+#define LOC_GPS_DELETE_HEALTH           0x0040
+#define LOC_GPS_DELETE_SVDIR            0x0080
+#define LOC_GPS_DELETE_SVSTEER          0x0100
+#define LOC_GPS_DELETE_SADATA           0x0200
+#define LOC_GPS_DELETE_RTI              0x0400
+#define LOC_GPS_DELETE_MB_DATA          0x0800
+#define LOC_GPS_DELETE_CELLDB_INFO      0x8000
+#define LOC_GPS_DELETE_ALL              0xFFFF
+
+/** AGPS type */
+typedef uint16_t LocAGpsType;
+#define LOC_AGPS_TYPE_ANY           0
+#define LOC_AGPS_TYPE_SUPL          1
+#define LOC_AGPS_TYPE_C2K           2
+#define LOC_AGPS_TYPE_WWAN_ANY      3
+#define LOC_AGPS_TYPE_WIFI          4
+#define LOC_AGPS_TYPE_SUPL_ES       5
+
+typedef uint16_t LocAGpsSetIDType;
+#define LOC_AGPS_SETID_TYPE_NONE    0
+#define LOC_AGPS_SETID_TYPE_IMSI    1
+#define LOC_AGPS_SETID_TYPE_MSISDN  2
+
+typedef uint16_t LocApnIpType;
+#define LOC_APN_IP_INVALID          0
+#define LOC_APN_IP_IPV4             1
+#define LOC_APN_IP_IPV6             2
+#define LOC_APN_IP_IPV4V6           3
+
+/**
+ * String length constants
+ */
+#define LOC_GPS_NI_SHORT_STRING_MAXLEN      256
+#define LOC_GPS_NI_LONG_STRING_MAXLEN       2048
+
+/**
+ * LocGpsNiType constants
+ */
+typedef uint32_t LocGpsNiType;
+#define LOC_GPS_NI_TYPE_VOICE              1
+#define LOC_GPS_NI_TYPE_UMTS_SUPL          2
+#define LOC_GPS_NI_TYPE_UMTS_CTRL_PLANE    3
+/*Emergency SUPL*/
+#define LOC_GPS_NI_TYPE_EMERGENCY_SUPL     4
+
+/**
+ * LocGpsNiNotifyFlags constants
+ */
+typedef uint32_t LocGpsNiNotifyFlags;
+/** NI requires notification */
+#define LOC_GPS_NI_NEED_NOTIFY          0x0001
+/** NI requires verification */
+#define LOC_GPS_NI_NEED_VERIFY          0x0002
+/** NI requires privacy override, no notification/minimal trace */
+#define LOC_GPS_NI_PRIVACY_OVERRIDE     0x0004
+
+/**
+ * GPS NI responses, used to define the response in
+ * NI structures
+ */
+typedef int LocGpsUserResponseType;
+#define LOC_GPS_NI_RESPONSE_ACCEPT         1
+#define LOC_GPS_NI_RESPONSE_DENY           2
+#define LOC_GPS_NI_RESPONSE_NORESP         3
+
+/**
+ * NI data encoding scheme
+ */
+typedef int LocGpsNiEncodingType;
+#define LOC_GPS_ENC_NONE                   0
+#define LOC_GPS_ENC_SUPL_GSM_DEFAULT       1
+#define LOC_GPS_ENC_SUPL_UTF8              2
+#define LOC_GPS_ENC_SUPL_UCS2              3
+#define LOC_GPS_ENC_UNKNOWN                -1
+
+/** AGPS status event values. */
+typedef uint8_t LocAGpsStatusValue;
+/** GPS requests data connection for AGPS. */
+#define LOC_GPS_REQUEST_AGPS_DATA_CONN  1
+/** GPS releases the AGPS data connection. */
+#define LOC_GPS_RELEASE_AGPS_DATA_CONN  2
+/** AGPS data connection initiated */
+#define LOC_GPS_AGPS_DATA_CONNECTED     3
+/** AGPS data connection completed */
+#define LOC_GPS_AGPS_DATA_CONN_DONE     4
+/** AGPS data connection failed */
+#define LOC_GPS_AGPS_DATA_CONN_FAILED   5
+
+typedef uint16_t LocAGpsRefLocationType;
+#define LOC_AGPS_REF_LOCATION_TYPE_GSM_CELLID   1
+#define LOC_AGPS_REF_LOCATION_TYPE_UMTS_CELLID  2
+#define LOC_AGPS_REF_LOCATION_TYPE_MAC          3
+#define LOC_AGPS_REF_LOCATION_TYPE_LTE_CELLID   4
+
+/* Deprecated, to be removed in the next Android release. */
+#define LOC_AGPS_REG_LOCATION_TYPE_MAC          3
+
+/** Network types for update_network_state "type" parameter */
+#define LOC_AGPS_RIL_NETWORK_TYPE_MOBILE        0
+#define LOC_AGPS_RIL_NETWORK_TYPE_WIFI          1
+#define LOC_AGPS_RIL_NETWORK_TYPE_MOBILE_MMS    2
+#define LOC_AGPS_RIL_NETWORK_TYPE_MOBILE_SUPL   3
+#define LOC_AGPS_RIL_NETWORK_TTYPE_MOBILE_DUN   4
+#define LOC_AGPS_RIL_NETWORK_TTYPE_MOBILE_HIPRI 5
+#define LOC_AGPS_RIL_NETWORK_TTYPE_WIMAX        6
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint16_t LocGpsClockFlags;
+#define LOC_GPS_CLOCK_HAS_LEAP_SECOND               (1<<0)
+#define LOC_GPS_CLOCK_HAS_TIME_UNCERTAINTY          (1<<1)
+#define LOC_GPS_CLOCK_HAS_FULL_BIAS                 (1<<2)
+#define LOC_GPS_CLOCK_HAS_BIAS                      (1<<3)
+#define LOC_GPS_CLOCK_HAS_BIAS_UNCERTAINTY          (1<<4)
+#define LOC_GPS_CLOCK_HAS_DRIFT                     (1<<5)
+#define LOC_GPS_CLOCK_HAS_DRIFT_UNCERTAINTY         (1<<6)
+
+/**
+ * Flags to indicate what fields in LocGnssClock are valid.
+ */
+typedef uint16_t LocGnssClockFlags;
+/** A valid 'leap second' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_LEAP_SECOND               (1<<0)
+/** A valid 'time uncertainty' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_TIME_UNCERTAINTY          (1<<1)
+/** A valid 'full bias' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_FULL_BIAS                 (1<<2)
+/** A valid 'bias' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_BIAS                      (1<<3)
+/** A valid 'bias uncertainty' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_BIAS_UNCERTAINTY          (1<<4)
+/** A valid 'drift' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_DRIFT                     (1<<5)
+/** A valid 'drift uncertainty' is stored in the data structure. */
+#define LOC_GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY         (1<<6)
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint8_t LocGpsClockType;
+#define LOC_GPS_CLOCK_TYPE_UNKNOWN                  0
+#define LOC_GPS_CLOCK_TYPE_LOCAL_HW_TIME            1
+#define LOC_GPS_CLOCK_TYPE_GPS_TIME                 2
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint32_t LocGpsMeasurementFlags;
+#define LOC_GPS_MEASUREMENT_HAS_SNR                               (1<<0)
+#define LOC_GPS_MEASUREMENT_HAS_ELEVATION                         (1<<1)
+#define LOC_GPS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY             (1<<2)
+#define LOC_GPS_MEASUREMENT_HAS_AZIMUTH                           (1<<3)
+#define LOC_GPS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY               (1<<4)
+#define LOC_GPS_MEASUREMENT_HAS_PSEUDORANGE                       (1<<5)
+#define LOC_GPS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY           (1<<6)
+#define LOC_GPS_MEASUREMENT_HAS_CODE_PHASE                        (1<<7)
+#define LOC_GPS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY            (1<<8)
+#define LOC_GPS_MEASUREMENT_HAS_CARRIER_FREQUENCY                 (1<<9)
+#define LOC_GPS_MEASUREMENT_HAS_CARRIER_CYCLES                    (1<<10)
+#define LOC_GPS_MEASUREMENT_HAS_CARRIER_PHASE                     (1<<11)
+#define LOC_GPS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY         (1<<12)
+#define LOC_GPS_MEASUREMENT_HAS_BIT_NUMBER                        (1<<13)
+#define LOC_GPS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT                (1<<14)
+#define LOC_GPS_MEASUREMENT_HAS_DOPPLER_SHIFT                     (1<<15)
+#define LOC_GPS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY         (1<<16)
+#define LOC_GPS_MEASUREMENT_HAS_USED_IN_FIX                       (1<<17)
+#define LOC_GPS_MEASUREMENT_HAS_UNCORRECTED_PSEUDORANGE_RATE      (1<<18)
+
+/**
+ * Flags to indicate what fields in LocGnssMeasurement are valid.
+ */
+typedef uint32_t LocGnssMeasurementFlags;
+/** A valid 'snr' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_SNR                               (1<<0)
+/** A valid 'carrier frequency' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY                 (1<<9)
+/** A valid 'carrier cycles' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_CYCLES                    (1<<10)
+/** A valid 'carrier phase' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE                     (1<<11)
+/** A valid 'carrier phase uncertainty' is stored in the data structure. */
+#define LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY         (1<<12)
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint8_t LocGpsLossOfLock;
+#define LOC_GPS_LOSS_OF_LOCK_UNKNOWN                            0
+#define LOC_GPS_LOSS_OF_LOCK_OK                                 1
+#define LOC_GPS_LOSS_OF_LOCK_CYCLE_SLIP                         2
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. Use LocGnssMultipathIndicator instead.
+ */
+typedef uint8_t LocGpsMultipathIndicator;
+#define LOC_GPS_MULTIPATH_INDICATOR_UNKNOWN                 0
+#define LOC_GPS_MULTIPATH_INDICATOR_DETECTED                1
+#define LOC_GPS_MULTIPATH_INDICATOR_NOT_USED                2
+
+/**
+ * Enumeration of available values for the GNSS Measurement's multipath
+ * indicator.
+ */
+typedef uint8_t LocGnssMultipathIndicator;
+/** The indicator is not available or unknown. */
+#define LOC_GNSS_MULTIPATH_INDICATOR_UNKNOWN                 0
+/** The measurement is indicated to be affected by multipath. */
+#define LOC_GNSS_MULTIPATH_INDICATOR_PRESENT                 1
+/** The measurement is indicated to be not affected by multipath. */
+#define LOC_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT             2
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint16_t LocGpsMeasurementState;
+#define LOC_GPS_MEASUREMENT_STATE_UNKNOWN                   0
+#define LOC_GPS_MEASUREMENT_STATE_CODE_LOCK             (1<<0)
+#define LOC_GPS_MEASUREMENT_STATE_BIT_SYNC              (1<<1)
+#define LOC_GPS_MEASUREMENT_STATE_SUBFRAME_SYNC         (1<<2)
+#define LOC_GPS_MEASUREMENT_STATE_TOW_DECODED           (1<<3)
+#define LOC_GPS_MEASUREMENT_STATE_MSEC_AMBIGUOUS        (1<<4)
+
+/**
+ * Flags indicating the GNSS measurement state.
+ *
+ * The expected behavior here is for GPS HAL to set all the flags that applies.
+ * For example, if the state for a satellite is only C/A code locked and bit
+ * synchronized, and there is still millisecond ambiguity, the state should be
+ * set as:
+ *
+ * LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK | LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC |
+ *         LOC_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS
+ *
+ * If GNSS is still searching for a satellite, the corresponding state should be
+ * set to LOC_GNSS_MEASUREMENT_STATE_UNKNOWN(0).
+ */
+typedef uint32_t LocGnssMeasurementState;
+#define LOC_GNSS_MEASUREMENT_STATE_UNKNOWN                   0
+#define LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK             (1<<0)
+#define LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC              (1<<1)
+#define LOC_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC         (1<<2)
+#define LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED           (1<<3)
+#define LOC_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS        (1<<4)
+#define LOC_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC           (1<<5)
+#define LOC_GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC       (1<<6)
+#define LOC_GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED       (1<<7)
+#define LOC_GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC       (1<<8)
+#define LOC_GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC  (1<<9)
+#define LOC_GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK    (1<<10)
+#define LOC_GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK (1<<11)
+#define LOC_GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC     (1<<12)
+#define LOC_GNSS_MEASUREMENT_STATE_SBAS_SYNC             (1<<13)
+
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint16_t LocGpsAccumulatedDeltaRangeState;
+#define LOC_GPS_ADR_STATE_UNKNOWN                       0
+#define LOC_GPS_ADR_STATE_VALID                     (1<<0)
+#define LOC_GPS_ADR_STATE_RESET                     (1<<1)
+#define LOC_GPS_ADR_STATE_CYCLE_SLIP                (1<<2)
+
+/**
+ * Flags indicating the Accumulated Delta Range's states.
+ */
+typedef uint16_t LocGnssAccumulatedDeltaRangeState;
+#define LOC_GNSS_ADR_STATE_UNKNOWN                       0
+#define LOC_GNSS_ADR_STATE_VALID                     (1<<0)
+#define LOC_GNSS_ADR_STATE_RESET                     (1<<1)
+#define LOC_GNSS_ADR_STATE_CYCLE_SLIP                (1<<2)
+
+#if 0
+/* The following typedef together with its constants below are deprecated, and
+ * will be removed in the next release. */
+typedef uint8_t GpsNavigationMessageType;
+#define GPS_NAVIGATION_MESSAGE_TYPE_UNKNOWN         0
+#define GPS_NAVIGATION_MESSAGE_TYPE_L1CA            1
+#define GPS_NAVIGATION_MESSAGE_TYPE_L2CNAV          2
+#define GPS_NAVIGATION_MESSAGE_TYPE_L5CNAV          3
+#define GPS_NAVIGATION_MESSAGE_TYPE_CNAV2           4
+
+/**
+ * Enumeration of available values to indicate the GNSS Navigation message
+ * types.
+ *
+ * For convenience, first byte is the LocGnssConstellationType on which that signal
+ * is typically transmitted
+ */
+typedef int16_t GnssNavigationMessageType;
+
+#define GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN       0
+/** GPS L1 C/A message contained in the structure.  */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_L1CA      0x0101
+/** GPS L2-CNAV message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_L2CNAV    0x0102
+/** GPS L5-CNAV message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_L5CNAV    0x0103
+/** GPS CNAV-2 message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GPS_CNAV2     0x0104
+/** Glonass L1 CA message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GLO_L1CA      0x0301
+/** Beidou D1 message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_BDS_D1        0x0501
+/** Beidou D2 message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_BDS_D2        0x0502
+/** Galileo I/NAV message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GAL_I         0x0601
+/** Galileo F/NAV message contained in the structure. */
+#define GNSS_NAVIGATION_MESSAGE_TYPE_GAL_F         0x0602
+
+/**
+ * Status of Navigation Message
+ * When a message is received properly without any parity error in its navigation words, the
+ * status should be set to NAV_MESSAGE_STATUS_PARITY_PASSED. But if a message is received
+ * with words that failed parity check, but GPS is able to correct those words, the status
+ * should be set to NAV_MESSAGE_STATUS_PARITY_REBUILT.
+ * No need to send any navigation message that contains words with parity error and cannot be
+ * corrected.
+ */
+typedef uint16_t NavigationMessageStatus;
+#define NAV_MESSAGE_STATUS_UNKNOWN              0
+#define NAV_MESSAGE_STATUS_PARITY_PASSED   (1<<0)
+#define NAV_MESSAGE_STATUS_PARITY_REBUILT  (1<<1)
+
+/* This constant is deprecated, and will be removed in the next release. */
+#define NAV_MESSAGE_STATUS_UNKONW              0
+#endif
+
+/**
+ * Flags that indicate information about the satellite
+ */
+typedef uint8_t                                 LocGnssSvFlags;
+#define LOC_GNSS_SV_FLAGS_NONE                      0
+#define LOC_GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA        (1 << 0)
+#define LOC_GNSS_SV_FLAGS_HAS_ALMANAC_DATA          (1 << 1)
+#define LOC_GNSS_SV_FLAGS_USED_IN_FIX               (1 << 2)
+
+/**
+ * Constellation type of LocGnssSvInfo
+ */
+typedef uint8_t                         LocGnssConstellationType;
+#define LOC_GNSS_CONSTELLATION_UNKNOWN      0
+#define LOC_GNSS_CONSTELLATION_GPS          1
+#define LOC_GNSS_CONSTELLATION_SBAS         2
+#define LOC_GNSS_CONSTELLATION_GLONASS      3
+#define LOC_GNSS_CONSTELLATION_QZSS         4
+#define LOC_GNSS_CONSTELLATION_BEIDOU       5
+#define LOC_GNSS_CONSTELLATION_GALILEO      6
+
+/**
+ * Name for the GPS XTRA interface.
+ */
+#define LOC_GPS_XTRA_INTERFACE      "gps-xtra"
+
+/**
+ * Name for the GPS DEBUG interface.
+ */
+#define LOC_GPS_DEBUG_INTERFACE      "gps-debug"
+
+/**
+ * Name for the AGPS interface.
+ */
+
+#define LOC_AGPS_INTERFACE      "agps"
+
+/**
+ * Name of the Supl Certificate interface.
+ */
+#define LOC_SUPL_CERTIFICATE_INTERFACE  "supl-certificate"
+
+/**
+ * Name for NI interface
+ */
+#define LOC_GPS_NI_INTERFACE "gps-ni"
+
+/**
+ * Name for the AGPS-RIL interface.
+ */
+#define LOC_AGPS_RIL_INTERFACE      "agps_ril"
+
+/**
+ * Name for the GPS_Geofencing interface.
+ */
+#define LOC_GPS_GEOFENCING_INTERFACE   "gps_geofencing"
+
+/**
+ * Name of the GPS Measurements interface.
+ */
+#define LOC_GPS_MEASUREMENT_INTERFACE   "gps_measurement"
+
+/**
+ * Name of the GPS navigation message interface.
+ */
+#define LOC_GPS_NAVIGATION_MESSAGE_INTERFACE     "gps_navigation_message"
+
+/**
+ * Name of the GNSS/GPS configuration interface.
+ */
+#define LOC_GNSS_CONFIGURATION_INTERFACE     "gnss_configuration"
+
+/** Represents a location. */
+typedef struct {
+    /** set to sizeof(LocGpsLocation) */
+    uint32_t        size;
+    /** Contains LocGpsLocationFlags bits. */
+    uint16_t        flags;
+    /** The spoof mask */
+    LocGpsSpoofMask spoof_mask;
+    /** Represents latitude in degrees. */
+    double          latitude;
+    /** Represents longitude in degrees. */
+    double          longitude;
+    /**
+     * Represents altitude in meters above the WGS 84 reference ellipsoid.
+     */
+    double          altitude;
+    /** Represents horizontal speed in meters per second. */
+    float           speed;
+    /** Represents heading in degrees. */
+    float           bearing;
+    /** Represents expected accuracy in meters. */
+    float           accuracy;
+    /** Represents the expected vertical uncertainity in meters*/
+    float           vertUncertainity;
+    /** Timestamp for the location fix. */
+    LocGpsUtcTime   timestamp;
+    /** Elapsed RealTime in nanosends */
+    uint64_t        elapsedRealTime;
+    /** Elapsed Real Time Uncertainty in nanosends */
+    uint64_t        elapsedRealTimeUnc;
+} LocGpsLocation;
+
+/** Represents the status. */
+typedef struct {
+    /** set to sizeof(LocGpsStatus) */
+    size_t          size;
+    LocGpsStatusValue status;
+} LocGpsStatus;
+
+/**
+ * Legacy struct to represents SV information.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssSvInfo instead.
+ */
+typedef struct {
+    /** set to sizeof(LocGpsSvInfo) */
+    size_t          size;
+    /** Pseudo-random number for the SV. */
+    int     prn;
+    /** Signal to noise ratio. */
+    float   snr;
+    /** Elevation of SV in degrees. */
+    float   elevation;
+    /** Azimuth of SV in degrees. */
+    float   azimuth;
+} LocGpsSvInfo;
+
+typedef struct {
+    /** set to sizeof(LocGnssSvInfo) */
+    size_t size;
+
+    /**
+     * Pseudo-random number for the SV, or FCN/OSN number for Glonass. The
+     * distinction is made by looking at constellation field. Values should be
+     * in the range of:
+     *
+     * - GPS:     1-32
+     * - SBAS:    120-151, 183-192
+     * - GLONASS: 1-24, the orbital slot number (OSN), if known.  Or, if not:
+     *            93-106, the frequency channel number (FCN) (-7 to +6) offset by + 100
+     *            i.e. report an FCN of -7 as 93, FCN of 0 as 100, and FCN of +6 as 106.
+     * - QZSS:    193-200
+     * - Galileo: 1-36
+     * - Beidou:  1-37
+     */
+    int16_t svid;
+
+    /**
+     * Defines the constellation of the given SV. Value should be one of those
+     * LOC_GNSS_CONSTELLATION_* constants
+     */
+    LocGnssConstellationType constellation;
+
+    /**
+     * Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
+     * It contains the measured C/N0 value for the signal at the antenna port.
+     *
+     * This is a mandatory value.
+     */
+    float c_n0_dbhz;
+
+    /** Elevation of SV in degrees. */
+    float elevation;
+
+    /** Azimuth of SV in degrees. */
+    float azimuth;
+
+    /**
+     * Contains additional data about the given SV. Value should be one of those
+     * LOC_GNSS_SV_FLAGS_* constants
+     */
+    LocGnssSvFlags flags;
+
+} LocGnssSvInfo;
+
+/**
+ * Legacy struct to represents SV status.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssSvStatus instead.
+ */
+typedef struct {
+    /** set to sizeof(LocGpsSvStatus) */
+    size_t size;
+    int num_svs;
+    LocGpsSvInfo sv_list[LOC_GPS_MAX_SVS];
+    uint32_t ephemeris_mask;
+    uint32_t almanac_mask;
+    uint32_t used_in_fix_mask;
+} LocGpsSvStatus;
+
+/**
+ * Represents SV status.
+ */
+typedef struct {
+    /** set to sizeof(LocGnssSvStatus) */
+    size_t size;
+
+    /** Number of GPS SVs currently visible, refers to the SVs stored in sv_list */
+    int num_svs;
+    /**
+     * Pointer to an array of SVs information for all GNSS constellations,
+     * except GPS, which is reported using sv_list
+     */
+    LocGnssSvInfo gnss_sv_list[LOC_GNSS_MAX_SVS];
+
+} LocGnssSvStatus;
+
+/* CellID for 2G, 3G and LTE, used in AGPS. */
+typedef struct {
+    LocAGpsRefLocationType type;
+    /** Mobile Country Code. */
+    uint16_t mcc;
+    /** Mobile Network Code .*/
+    uint16_t mnc;
+    /** Location Area Code in 2G, 3G and LTE. In 3G lac is discarded. In LTE,
+     * lac is populated with tac, to ensure that we don't break old clients that
+     * might rely in the old (wrong) behavior.
+     */
+    uint16_t lac;
+    /** Cell id in 2G. Utran Cell id in 3G. Cell Global Id EUTRA in LTE. */
+    uint32_t cid;
+    /** Tracking Area Code in LTE. */
+    uint16_t tac;
+    /** Physical Cell id in LTE (not used in 2G and 3G) */
+    uint16_t pcid;
+} LocAGpsRefLocationCellID;
+
+typedef struct {
+    uint8_t mac[6];
+} LocAGpsRefLocationMac;
+
+/** Represents ref locations */
+typedef struct {
+    LocAGpsRefLocationType type;
+    union {
+        LocAGpsRefLocationCellID   cellID;
+        LocAGpsRefLocationMac      mac;
+    } u;
+} LocAGpsRefLocation;
+
+/**
+ * Callback with location information. Can only be called from a thread created
+ * by create_thread_cb.
+ */
+typedef void (* loc_gps_location_callback)(LocGpsLocation* location);
+
+/**
+ * Callback with status information. Can only be called from a thread created by
+ * create_thread_cb.
+ */
+typedef void (* loc_gps_status_callback)(LocGpsStatus* status);
+/**
+ * Legacy callback with SV status information.
+ * Can only be called from a thread created by create_thread_cb.
+ *
+ * This callback is deprecated, and will be removed in the next release. Use
+ * loc_gnss_sv_status_callback() instead.
+ */
+typedef void (* loc_gps_sv_status_callback)(LocGpsSvStatus* sv_info);
+
+/**
+ * Callback with SV status information.
+ * Can only be called from a thread created by create_thread_cb.
+ */
+typedef void (* loc_gnss_sv_status_callback)(LocGnssSvStatus* sv_info);
+
+/**
+ * Callback for reporting NMEA sentences. Can only be called from a thread
+ * created by create_thread_cb.
+ */
+typedef void (* loc_gps_nmea_callback)(LocGpsUtcTime timestamp, const char* nmea, int length);
+
+/**
+ * Callback to inform framework of the GPS engine's capabilities. Capability
+ * parameter is a bit field of LOC_GPS_CAPABILITY_* flags.
+ */
+typedef void (* loc_gps_set_capabilities)(uint32_t capabilities);
+
+/**
+ * Callback utility for acquiring the GPS wakelock. This can be used to prevent
+ * the CPU from suspending while handling GPS events.
+ */
+typedef void (* loc_gps_acquire_wakelock)();
+
+/** Callback utility for releasing the GPS wakelock. */
+typedef void (* loc_gps_release_wakelock)();
+
+/** Callback for requesting NTP time */
+typedef void (* loc_gps_request_utc_time)();
+
+/**
+ * Callback for creating a thread that can call into the Java framework code.
+ * This must be used to create any threads that report events up to the
+ * framework.
+ */
+typedef pthread_t (* loc_gps_create_thread)(const char* name, void (*start)(void *), void* arg);
+
+/**
+ * Provides information about how new the underlying GPS/GNSS hardware and
+ * software is.
+ *
+ * This information will be available for Android Test Applications. If a GPS
+ * HAL does not provide this information, it will be considered "2015 or
+ * earlier".
+ *
+ * If a GPS HAL does provide this information, then newer years will need to
+ * meet newer CTS standards. E.g. if the date are 2016 or above, then N+ level
+ * LocGpsMeasurement support will be verified.
+ */
+typedef struct {
+    /** Set to sizeof(LocGnssSystemInfo) */
+    size_t   size;
+    /* year in which the last update was made to the underlying hardware/firmware
+     * used to capture GNSS signals, e.g. 2016 */
+    uint16_t year_of_hw;
+} LocGnssSystemInfo;
+
+/**
+ * Callback to inform framework of the engine's hardware version information.
+ */
+typedef void (*loc_gnss_set_system_info)(const LocGnssSystemInfo* info);
+
+/** New GPS callback structure. */
+typedef struct {
+    /** set to sizeof(LocGpsCallbacks) */
+    size_t      size;
+    loc_gps_location_callback location_cb;
+    loc_gps_status_callback status_cb;
+    loc_gps_sv_status_callback sv_status_cb;
+    loc_gps_nmea_callback nmea_cb;
+    loc_gps_set_capabilities set_capabilities_cb;
+    loc_gps_acquire_wakelock acquire_wakelock_cb;
+    loc_gps_release_wakelock release_wakelock_cb;
+    loc_gps_create_thread create_thread_cb;
+    loc_gps_request_utc_time request_utc_time_cb;
+
+    loc_gnss_set_system_info set_system_info_cb;
+    loc_gnss_sv_status_callback gnss_sv_status_cb;
+} LocGpsCallbacks;
+
+/** Represents the standard GPS interface. */
+typedef struct {
+    /** set to sizeof(LocGpsInterface) */
+    size_t          size;
+    /**
+     * Opens the interface and provides the callback routines
+     * to the implementation of this interface.
+     */
+    int   (*init)( LocGpsCallbacks* callbacks );
+
+    /** Starts navigating. */
+    int   (*start)( void );
+
+    /** Stops navigating. */
+    int   (*stop)( void );
+
+    /** Closes the interface. */
+    void  (*cleanup)( void );
+
+    /** Injects the current time. */
+    int   (*inject_time)(LocGpsUtcTime time, int64_t timeReference,
+                         int uncertainty);
+
+    /**
+     * Injects current location from another location provider (typically cell
+     * ID). Latitude and longitude are measured in degrees expected accuracy is
+     * measured in meters
+     */
+    int  (*inject_location)(double latitude, double longitude, float accuracy);
+
+    /**
+     * Specifies that the next call to start will not use the
+     * information defined in the flags. LOC_GPS_DELETE_ALL is passed for
+     * a cold start.
+     */
+    void  (*delete_aiding_data)(LocGpsAidingData flags);
+
+    /**
+     * min_interval represents the time between fixes in milliseconds.
+     * preferred_accuracy represents the requested fix accuracy in meters.
+     * preferred_time represents the requested time to first fix in milliseconds.
+     *
+     * 'mode' parameter should be one of LOC_GPS_POSITION_MODE_MS_BASED
+     * or LOC_GPS_POSITION_MODE_STANDALONE.
+     * It is allowed by the platform (and it is recommended) to fallback to
+     * LOC_GPS_POSITION_MODE_MS_BASED if LOC_GPS_POSITION_MODE_MS_ASSISTED is passed in, and
+     * LOC_GPS_POSITION_MODE_MS_BASED is supported.
+     */
+    int   (*set_position_mode)(LocGpsPositionMode mode, LocGpsPositionRecurrence recurrence,
+            uint32_t min_interval, uint32_t preferred_accuracy, uint32_t preferred_time);
+
+    /** Get a pointer to extension information. */
+    const void* (*get_extension)(const char* name);
+} LocGpsInterface;
+
+/**
+ * Callback to request the client to download XTRA data. The client should
+ * download XTRA data and inject it by calling inject_xtra_data(). Can only be
+ * called from a thread created by create_thread_cb.
+ */
+typedef void (* loc_gps_xtra_download_request)();
+
+/** Callback structure for the XTRA interface. */
+typedef struct {
+    loc_gps_xtra_download_request download_request_cb;
+    loc_gps_create_thread create_thread_cb;
+} LocGpsXtraCallbacks;
+
+/** Extended interface for XTRA support. */
+typedef struct {
+    /** set to sizeof(LocGpsXtraInterface) */
+    size_t          size;
+    /**
+     * Opens the XTRA interface and provides the callback routines
+     * to the implementation of this interface.
+     */
+    int  (*init)( LocGpsXtraCallbacks* callbacks );
+    /** Injects XTRA data into the GPS. */
+    int  (*inject_xtra_data)( char* data, int length );
+} LocGpsXtraInterface;
+
+#if 0
+/** Extended interface for DEBUG support. */
+typedef struct {
+    /** set to sizeof(LocGpsDebugInterface) */
+    size_t          size;
+
+    /**
+     * This function should return any information that the native
+     * implementation wishes to include in a bugreport.
+     */
+    size_t (*get_internal_state)(char* buffer, size_t bufferSize);
+} LocGpsDebugInterface;
+#endif
+
+/*
+ * Represents the status of AGPS augmented to support IPv4 and IPv6.
+ */
+typedef struct {
+    /** set to sizeof(LocAGpsStatus) */
+    size_t                  size;
+
+    LocAGpsType                type;
+    LocAGpsStatusValue         status;
+
+    /**
+     * Must be set to a valid IPv4 address if the field 'addr' contains an IPv4
+     * address, or set to INADDR_NONE otherwise.
+     */
+    uint32_t                ipaddr;
+
+    /**
+     * Must contain the IPv4 (AF_INET) or IPv6 (AF_INET6) address to report.
+     * Any other value of addr.ss_family will be rejected.
+     */
+    struct sockaddr_storage addr;
+} LocAGpsStatus;
+
+/**
+ * Callback with AGPS status information. Can only be called from a thread
+ * created by create_thread_cb.
+ */
+typedef void (* loc_agps_status_callback)(LocAGpsStatus* status);
+
+/** Callback structure for the AGPS interface. */
+typedef struct {
+    loc_agps_status_callback status_cb;
+    loc_gps_create_thread create_thread_cb;
+} LocAGpsCallbacks;
+
+/**
+ * Extended interface for AGPS support, it is augmented to enable to pass
+ * extra APN data.
+ */
+typedef struct {
+    /** set to sizeof(LocAGpsInterface) */
+    size_t size;
+
+    /**
+     * Opens the AGPS interface and provides the callback routines to the
+     * implementation of this interface.
+     */
+    void (*init)(LocAGpsCallbacks* callbacks);
+    /**
+     * Deprecated.
+     * If the HAL supports LocAGpsInterface_v2 this API will not be used, see
+     * data_conn_open_with_apn_ip_type for more information.
+     */
+    int (*data_conn_open)(const char* apn);
+    /**
+     * Notifies that the AGPS data connection has been closed.
+     */
+    int (*data_conn_closed)();
+    /**
+     * Notifies that a data connection is not available for AGPS.
+     */
+    int (*data_conn_failed)();
+    /**
+     * Sets the hostname and port for the AGPS server.
+     */
+    int (*set_server)(LocAGpsType type, const char* hostname, int port);
+
+    /**
+     * Notifies that a data connection is available and sets the name of the
+     * APN, and its IP type, to be used for SUPL connections.
+     */
+    int (*data_conn_open_with_apn_ip_type)(
+            const char* apn,
+            LocApnIpType apnIpType);
+} LocAGpsInterface;
+
+/** Error codes associated with certificate operations */
+#define LOC_AGPS_CERTIFICATE_OPERATION_SUCCESS               0
+#define LOC_AGPS_CERTIFICATE_ERROR_GENERIC                -100
+#define LOC_AGPS_CERTIFICATE_ERROR_TOO_MANY_CERTIFICATES  -101
+
+/** A data structure that represents an X.509 certificate using DER encoding */
+typedef struct {
+    size_t  length;
+    u_char* data;
+} LocDerEncodedCertificate;
+
+/**
+ * A type definition for SHA1 Fingerprints used to identify X.509 Certificates
+ * The Fingerprint is a digest of the DER Certificate that uniquely identifies it.
+ */
+typedef struct {
+    u_char data[20];
+} LocSha1CertificateFingerprint;
+
+/** AGPS Interface to handle SUPL certificate operations */
+typedef struct {
+    /** set to sizeof(LocSuplCertificateInterface) */
+    size_t size;
+
+    /**
+     * Installs a set of Certificates used for SUPL connections to the AGPS server.
+     * If needed the HAL should find out internally any certificates that need to be removed to
+     * accommodate the certificates to install.
+     * The certificates installed represent a full set of valid certificates needed to connect to
+     * AGPS SUPL servers.
+     * The list of certificates is required, and all must be available at the same time, when trying
+     * to establish a connection with the AGPS Server.
+     *
+     * Parameters:
+     *      certificates - A pointer to an array of DER encoded certificates that are need to be
+     *                     installed in the HAL.
+     *      length - The number of certificates to install.
+     * Returns:
+     *      LOC_AGPS_CERTIFICATE_OPERATION_SUCCESS if the operation is completed successfully
+     *      LOC_AGPS_CERTIFICATE_ERROR_TOO_MANY_CERTIFICATES if the HAL cannot store the number of
+     *          certificates attempted to be installed, the state of the certificates stored should
+     *          remain the same as before on this error case.
+     *
+     * IMPORTANT:
+     *      If needed the HAL should find out internally the set of certificates that need to be
+     *      removed to accommodate the certificates to install.
+     */
+    int  (*install_certificates) ( const LocDerEncodedCertificate* certificates, size_t length );
+
+    /**
+     * Notifies the HAL that a list of certificates used for SUPL connections are revoked. It is
+     * expected that the given set of certificates is removed from the internal store of the HAL.
+     *
+     * Parameters:
+     *      fingerprints - A pointer to an array of SHA1 Fingerprints to identify the set of
+     *                     certificates to revoke.
+     *      length - The number of fingerprints provided.
+     * Returns:
+     *      LOC_AGPS_CERTIFICATE_OPERATION_SUCCESS if the operation is completed successfully.
+     *
+     * IMPORTANT:
+     *      If any of the certificates provided (through its fingerprint) is not known by the HAL,
+     *      it should be ignored and continue revoking/deleting the rest of them.
+     */
+    int  (*revoke_certificates) ( const LocSha1CertificateFingerprint* fingerprints, size_t length );
+} LocSuplCertificateInterface;
+
+/** Represents an NI request */
+typedef struct {
+    /** set to sizeof(LocGpsNiNotification) */
+    size_t          size;
+
+    /**
+     * An ID generated by HAL to associate NI notifications and UI
+     * responses
+     */
+    int             notification_id;
+
+    /**
+     * An NI type used to distinguish different categories of NI
+     * events, such as LOC_GPS_NI_TYPE_VOICE, LOC_GPS_NI_TYPE_UMTS_SUPL, ...
+     */
+    LocGpsNiType       ni_type;
+
+    /**
+     * Notification/verification options, combinations of LocGpsNiNotifyFlags constants
+     */
+    LocGpsNiNotifyFlags notify_flags;
+
+    /**
+     * Timeout period to wait for user response.
+     * Set to 0 for no time out limit.
+     */
+    int             timeout;
+
+    /**
+     * Default response when time out.
+     */
+    LocGpsUserResponseType default_response;
+
+    /**
+     * Requestor ID
+     */
+    char            requestor_id[LOC_GPS_NI_SHORT_STRING_MAXLEN];
+
+    /**
+     * Notification message. It can also be used to store client_id in some cases
+     */
+    char            text[LOC_GPS_NI_LONG_STRING_MAXLEN];
+
+    /**
+     * Client name decoding scheme
+     */
+    LocGpsNiEncodingType requestor_id_encoding;
+
+    /**
+     * Client name decoding scheme
+     */
+    LocGpsNiEncodingType text_encoding;
+
+    /**
+     * A pointer to extra data. Format:
+     * key_1 = value_1
+     * key_2 = value_2
+     */
+    char           extras[LOC_GPS_NI_LONG_STRING_MAXLEN];
+
+} LocGpsNiNotification;
+
+/**
+ * Callback with NI notification. Can only be called from a thread created by
+ * create_thread_cb.
+ */
+typedef void (*loc_gps_ni_notify_callback)(LocGpsNiNotification *notification);
+
+/** GPS NI callback structure. */
+typedef struct
+{
+    /**
+     * Sends the notification request from HAL to GPSLocationProvider.
+     */
+    loc_gps_ni_notify_callback notify_cb;
+    loc_gps_create_thread create_thread_cb;
+} LocGpsNiCallbacks;
+
+/**
+ * Extended interface for Network-initiated (NI) support.
+ */
+typedef struct
+{
+    /** set to sizeof(LocGpsNiInterface) */
+    size_t          size;
+
+   /** Registers the callbacks for HAL to use. */
+   void (*init) (LocGpsNiCallbacks *callbacks);
+
+   /** Sends a response to HAL. */
+   void (*respond) (int notif_id, LocGpsUserResponseType user_response);
+} LocGpsNiInterface;
+
+#define LOC_AGPS_RIL_REQUEST_SETID_IMSI     (1<<0L)
+#define LOC_AGPS_RIL_REQUEST_SETID_MSISDN   (1<<1L)
+
+#define LOC_AGPS_RIL_REQUEST_REFLOC_CELLID  (1<<0L)
+#define LOC_AGPS_RIL_REQUEST_REFLOC_MAC     (1<<1L)
+
+typedef void (*loc_agps_ril_request_set_id)(uint32_t flags);
+typedef void (*loc_agps_ril_request_ref_loc)(uint32_t flags);
+
+typedef struct {
+    loc_agps_ril_request_set_id request_setid;
+    loc_agps_ril_request_ref_loc request_refloc;
+    loc_gps_create_thread create_thread_cb;
+} LocAGpsRilCallbacks;
+
+/** Extended interface for AGPS_RIL support. */
+typedef struct {
+    /** set to sizeof(LocAGpsRilInterface) */
+    size_t          size;
+    /**
+     * Opens the AGPS interface and provides the callback routines
+     * to the implementation of this interface.
+     */
+    void  (*init)( LocAGpsRilCallbacks* callbacks );
+
+    /**
+     * Sets the reference location.
+     */
+    void (*set_ref_location) (const LocAGpsRefLocation *agps_reflocation, size_t sz_struct);
+    /**
+     * Sets the set ID.
+     */
+    void (*set_set_id) (LocAGpsSetIDType type, const char* setid);
+
+    /**
+     * Send network initiated message.
+     */
+    void (*ni_message) (uint8_t *msg, size_t len);
+
+    /**
+     * Notify GPS of network status changes.
+     * These parameters match values in the android.net.NetworkInfo class.
+     */
+    void (*update_network_state) (int connected, int type, int roaming, const char* extra_info);
+
+    /**
+     * Notify GPS of network status changes.
+     * These parameters match values in the android.net.NetworkInfo class.
+     */
+    void (*update_network_availability) (int avaiable, const char* apn);
+} LocAGpsRilInterface;
+
+/**
+ * GPS Geofence.
+ *      There are 3 states associated with a Geofence: Inside, Outside, Unknown.
+ * There are 3 transitions: ENTERED, EXITED, UNCERTAIN.
+ *
+ * An example state diagram with confidence level: 95% and Unknown time limit
+ * set as 30 secs is shown below. (confidence level and Unknown time limit are
+ * explained latter)
+ *                         ____________________________
+ *                        |       Unknown (30 secs)   |
+ *                         """"""""""""""""""""""""""""
+ *                            ^ |                  |  ^
+ *                   UNCERTAIN| |ENTERED     EXITED|  |UNCERTAIN
+ *                            | v                  v  |
+ *                        ________    EXITED     _________
+ *                       | Inside | -----------> | Outside |
+ *                       |        | <----------- |         |
+ *                        """"""""    ENTERED    """""""""
+ *
+ * Inside state: We are 95% confident that the user is inside the geofence.
+ * Outside state: We are 95% confident that the user is outside the geofence
+ * Unknown state: Rest of the time.
+ *
+ * The Unknown state is better explained with an example:
+ *
+ *                            __________
+ *                           |         c|
+ *                           |  ___     |    _______
+ *                           |  |a|     |   |   b   |
+ *                           |  """     |    """""""
+ *                           |          |
+ *                            """"""""""
+ * In the diagram above, "a" and "b" are 2 geofences and "c" is the accuracy
+ * circle reported by the GPS subsystem. Now with regard to "b", the system is
+ * confident that the user is outside. But with regard to "a" is not confident
+ * whether it is inside or outside the geofence. If the accuracy remains the
+ * same for a sufficient period of time, the UNCERTAIN transition would be
+ * triggered with the state set to Unknown. If the accuracy improves later, an
+ * appropriate transition should be triggered.  This "sufficient period of time"
+ * is defined by the parameter in the add_geofence_area API.
+ *     In other words, Unknown state can be interpreted as a state in which the
+ * GPS subsystem isn't confident enough that the user is either inside or
+ * outside the Geofence. It moves to Unknown state only after the expiry of the
+ * timeout.
+ *
+ * The geofence callback needs to be triggered for the ENTERED and EXITED
+ * transitions, when the GPS system is confident that the user has entered
+ * (Inside state) or exited (Outside state) the Geofence. An implementation
+ * which uses a value of 95% as the confidence is recommended. The callback
+ * should be triggered only for the transitions requested by the
+ * add_geofence_area call.
+ *
+ * Even though the diagram and explanation talks about states and transitions,
+ * the callee is only interested in the transistions. The states are mentioned
+ * here for illustrative purposes.
+ *
+ * Startup Scenario: When the device boots up, if an application adds geofences,
+ * and then we get an accurate GPS location fix, it needs to trigger the
+ * appropriate (ENTERED or EXITED) transition for every Geofence it knows about.
+ * By default, all the Geofences will be in the Unknown state.
+ *
+ * When the GPS system is unavailable, loc_gps_geofence_status_callback should be
+ * called to inform the upper layers of the same. Similarly, when it becomes
+ * available the callback should be called. This is a global state while the
+ * UNKNOWN transition described above is per geofence.
+ *
+ * An important aspect to note is that users of this API (framework), will use
+ * other subsystems like wifi, sensors, cell to handle Unknown case and
+ * hopefully provide a definitive state transition to the third party
+ * application. GPS Geofence will just be a signal indicating what the GPS
+ * subsystem knows about the Geofence.
+ *
+ */
+#define LOC_GPS_GEOFENCE_ENTERED     (1<<0L)
+#define LOC_GPS_GEOFENCE_EXITED      (1<<1L)
+#define LOC_GPS_GEOFENCE_UNCERTAIN   (1<<2L)
+
+#define LOC_GPS_GEOFENCE_UNAVAILABLE (1<<0L)
+#define LOC_GPS_GEOFENCE_AVAILABLE   (1<<1L)
+
+#define LOC_GPS_GEOFENCE_OPERATION_SUCCESS           0
+#define LOC_GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES -100
+#define LOC_GPS_GEOFENCE_ERROR_ID_EXISTS          -101
+#define LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN         -102
+#define LOC_GPS_GEOFENCE_ERROR_INVALID_TRANSITION -103
+#define LOC_GPS_GEOFENCE_ERROR_GENERIC            -149
+
+/**
+ * The callback associated with the geofence.
+ * Parameters:
+ *      geofence_id - The id associated with the add_geofence_area.
+ *      location    - The current GPS location.
+ *      transition  - Can be one of LOC_GPS_GEOFENCE_ENTERED, LOC_GPS_GEOFENCE_EXITED,
+ *                    LOC_GPS_GEOFENCE_UNCERTAIN.
+ *      timestamp   - Timestamp when the transition was detected.
+ *
+ * The callback should only be called when the caller is interested in that
+ * particular transition. For instance, if the caller is interested only in
+ * ENTERED transition, then the callback should NOT be called with the EXITED
+ * transition.
+ *
+ * IMPORTANT: If a transition is triggered resulting in this callback, the GPS
+ * subsystem will wake up the application processor, if its in suspend state.
+ */
+typedef void (*loc_gps_geofence_transition_callback) (int32_t geofence_id,  LocGpsLocation* location,
+        int32_t transition, LocGpsUtcTime timestamp);
+
+/**
+ * The callback associated with the availability of the GPS system for geofencing
+ * monitoring. If the GPS system determines that it cannot monitor geofences
+ * because of lack of reliability or unavailability of the GPS signals, it will
+ * call this callback with LOC_GPS_GEOFENCE_UNAVAILABLE parameter.
+ *
+ * Parameters:
+ *  status - LOC_GPS_GEOFENCE_UNAVAILABLE or LOC_GPS_GEOFENCE_AVAILABLE.
+ *  last_location - Last known location.
+ */
+typedef void (*loc_gps_geofence_status_callback) (int32_t status, LocGpsLocation* last_location);
+
+/**
+ * The callback associated with the add_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS
+ *          LOC_GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES  - geofence limit has been reached.
+ *          LOC_GPS_GEOFENCE_ERROR_ID_EXISTS  - geofence with id already exists
+ *          LOC_GPS_GEOFENCE_ERROR_INVALID_TRANSITION - the monitorTransition contains an
+ *              invalid transition
+ *          LOC_GPS_GEOFENCE_ERROR_GENERIC - for other errors.
+ */
+typedef void (*loc_gps_geofence_add_callback) (int32_t geofence_id, int32_t status);
+
+/**
+ * The callback associated with the remove_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS
+ *          LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN - for invalid id
+ *          LOC_GPS_GEOFENCE_ERROR_GENERIC for others.
+ */
+typedef void (*loc_gps_geofence_remove_callback) (int32_t geofence_id, int32_t status);
+
+
+/**
+ * The callback associated with the pause_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS
+ *          LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN - for invalid id
+ *          LOC_GPS_GEOFENCE_ERROR_INVALID_TRANSITION -
+ *                    when monitor_transitions is invalid
+ *          LOC_GPS_GEOFENCE_ERROR_GENERIC for others.
+ */
+typedef void (*loc_gps_geofence_pause_callback) (int32_t geofence_id, int32_t status);
+
+/**
+ * The callback associated with the resume_geofence call.
+ *
+ * Parameter:
+ * geofence_id - Id of the geofence.
+ * status - LOC_GPS_GEOFENCE_OPERATION_SUCCESS
+ *          LOC_GPS_GEOFENCE_ERROR_ID_UNKNOWN - for invalid id
+ *          LOC_GPS_GEOFENCE_ERROR_GENERIC for others.
+ */
+typedef void (*loc_gps_geofence_resume_callback) (int32_t geofence_id, int32_t status);
+
+typedef struct {
+    loc_gps_geofence_transition_callback geofence_transition_callback;
+    loc_gps_geofence_status_callback geofence_status_callback;
+    loc_gps_geofence_add_callback geofence_add_callback;
+    loc_gps_geofence_remove_callback geofence_remove_callback;
+    loc_gps_geofence_pause_callback geofence_pause_callback;
+    loc_gps_geofence_resume_callback geofence_resume_callback;
+    loc_gps_create_thread create_thread_cb;
+} LocGpsGeofenceCallbacks;
+
+/** Extended interface for GPS_Geofencing support */
+typedef struct {
+   /** set to sizeof(LocGpsGeofencingInterface) */
+   size_t          size;
+
+   /**
+    * Opens the geofence interface and provides the callback routines
+    * to the implementation of this interface.
+    */
+   void  (*init)( LocGpsGeofenceCallbacks* callbacks );
+
+   /**
+    * Add a geofence area. This api currently supports circular geofences.
+    * Parameters:
+    *    geofence_id - The id for the geofence. If a geofence with this id
+    *       already exists, an error value (LOC_GPS_GEOFENCE_ERROR_ID_EXISTS)
+    *       should be returned.
+    *    latitude, longtitude, radius_meters - The lat, long and radius
+    *       (in meters) for the geofence
+    *    last_transition - The current state of the geofence. For example, if
+    *       the system already knows that the user is inside the geofence,
+    *       this will be set to LOC_GPS_GEOFENCE_ENTERED. In most cases, it
+    *       will be LOC_GPS_GEOFENCE_UNCERTAIN.
+    *    monitor_transition - Which transitions to monitor. Bitwise OR of
+    *       LOC_GPS_GEOFENCE_ENTERED, LOC_GPS_GEOFENCE_EXITED and
+    *       LOC_GPS_GEOFENCE_UNCERTAIN.
+    *    notification_responsiveness_ms - Defines the best-effort description
+    *       of how soon should the callback be called when the transition
+    *       associated with the Geofence is triggered. For instance, if set
+    *       to 1000 millseconds with LOC_GPS_GEOFENCE_ENTERED, the callback
+    *       should be called 1000 milliseconds within entering the geofence.
+    *       This parameter is defined in milliseconds.
+    *       NOTE: This is not to be confused with the rate that the GPS is
+    *       polled at. It is acceptable to dynamically vary the rate of
+    *       sampling the GPS for power-saving reasons; thus the rate of
+    *       sampling may be faster or slower than this.
+    *    unknown_timer_ms - The time limit after which the UNCERTAIN transition
+    *       should be triggered. This parameter is defined in milliseconds.
+    *       See above for a detailed explanation.
+    */
+   void (*add_geofence_area) (int32_t geofence_id, double latitude, double longitude,
+       double radius_meters, int last_transition, int monitor_transitions,
+       int notification_responsiveness_ms, int unknown_timer_ms);
+
+   /**
+    * Pause monitoring a particular geofence.
+    * Parameters:
+    *   geofence_id - The id for the geofence.
+    */
+   void (*pause_geofence) (int32_t geofence_id);
+
+   /**
+    * Resume monitoring a particular geofence.
+    * Parameters:
+    *   geofence_id - The id for the geofence.
+    *   monitor_transitions - Which transitions to monitor. Bitwise OR of
+    *       LOC_GPS_GEOFENCE_ENTERED, LOC_GPS_GEOFENCE_EXITED and
+    *       LOC_GPS_GEOFENCE_UNCERTAIN.
+    *       This supersedes the value associated provided in the
+    *       add_geofence_area call.
+    */
+   void (*resume_geofence) (int32_t geofence_id, int monitor_transitions);
+
+   /**
+    * Remove a geofence area. After the function returns, no notifications
+    * should be sent.
+    * Parameter:
+    *   geofence_id - The id for the geofence.
+    */
+   void (*remove_geofence_area) (int32_t geofence_id);
+} LocGpsGeofencingInterface;
+
+/**
+ * Legacy struct to represent an estimate of the GPS clock time.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssClock instead.
+ */
+typedef struct {
+    /** set to sizeof(LocGpsClock) */
+    size_t size;
+    LocGpsClockFlags flags;
+    int16_t leap_second;
+    LocGpsClockType type;
+    int64_t time_ns;
+    double time_uncertainty_ns;
+    int64_t full_bias_ns;
+    double bias_ns;
+    double bias_uncertainty_ns;
+    double drift_nsps;
+    double drift_uncertainty_nsps;
+} LocGpsClock;
+
+/**
+ * Represents an estimate of the GPS clock time.
+ */
+typedef struct {
+    /** set to sizeof(LocGnssClock) */
+    size_t size;
+
+    /**
+     * A set of flags indicating the validity of the fields in this data
+     * structure.
+     */
+    LocGnssClockFlags flags;
+
+    /**
+     * Leap second data.
+     * The sign of the value is defined by the following equation:
+     *      utc_time_ns = time_ns - (full_bias_ns + bias_ns) - leap_second *
+     *      1,000,000,000
+     *
+     * If the data is available 'flags' must contain LOC_GNSS_CLOCK_HAS_LEAP_SECOND.
+     */
+    int16_t leap_second;
+
+    /**
+     * The GNSS receiver internal clock value. This is the local hardware clock
+     * value.
+     *
+     * For local hardware clock, this value is expected to be monotonically
+     * increasing while the hardware clock remains power on. (For the case of a
+     * HW clock that is not continuously on, see the
+     * hw_clock_discontinuity_count field). The receiver's estimate of GPS time
+     * can be derived by substracting the sum of full_bias_ns and bias_ns (when
+     * available) from this value.
+     *
+     * This GPS time is expected to be the best estimate of current GPS time
+     * that GNSS receiver can achieve.
+     *
+     * Sub-nanosecond accuracy can be provided by means of the 'bias_ns' field.
+     * The value contains the 'time uncertainty' in it.
+     *
+     * This field is mandatory.
+     */
+    int64_t time_ns;
+
+    /**
+     * 1-Sigma uncertainty associated with the clock's time in nanoseconds.
+     * The uncertainty is represented as an absolute (single sided) value.
+     *
+     * If the data is available, 'flags' must contain
+     * LOC_GNSS_CLOCK_HAS_TIME_UNCERTAINTY. This value is effectively zero (it is
+     * the reference local clock, by which all other times and time
+     * uncertainties are measured.)  (And thus this field can be not provided,
+     * per LOC_GNSS_CLOCK_HAS_TIME_UNCERTAINTY flag, or provided & set to 0.)
+     */
+    double time_uncertainty_ns;
+
+    /**
+     * The difference between hardware clock ('time' field) inside GPS receiver
+     * and the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
+     *
+     * The sign of the value is defined by the following equation:
+     *      local estimate of GPS time = time_ns - (full_bias_ns + bias_ns)
+     *
+     * This value is mandatory if the receiver has estimated GPS time. If the
+     * computed time is for a non-GPS constellation, the time offset of that
+     * constellation to GPS has to be applied to fill this value. The error
+     * estimate for the sum of this and the bias_ns is the bias_uncertainty_ns,
+     * and the caller is responsible for using this uncertainty (it can be very
+     * large before the GPS time has been solved for.) If the data is available
+     * 'flags' must contain LOC_GNSS_CLOCK_HAS_FULL_BIAS.
+     */
+    int64_t full_bias_ns;
+
+    /**
+     * Sub-nanosecond bias.
+     * The error estimate for the sum of this and the full_bias_ns is the
+     * bias_uncertainty_ns
+     *
+     * If the data is available 'flags' must contain LOC_GNSS_CLOCK_HAS_BIAS. If GPS
+     * has computed a position fix. This value is mandatory if the receiver has
+     * estimated GPS time.
+     */
+    double bias_ns;
+
+    /**
+     * 1-Sigma uncertainty associated with the local estimate of GPS time (clock
+     * bias) in nanoseconds. The uncertainty is represented as an absolute
+     * (single sided) value.
+     *
+     * If the data is available 'flags' must contain
+     * LOC_GNSS_CLOCK_HAS_BIAS_UNCERTAINTY. This value is mandatory if the receiver
+     * has estimated GPS time.
+     */
+    double bias_uncertainty_ns;
+
+    /**
+     * The clock's drift in nanoseconds (per second).
+     *
+     * A positive value means that the frequency is higher than the nominal
+     * frequency, and that the (full_bias_ns + bias_ns) is growing more positive
+     * over time.
+     *
+     * The value contains the 'drift uncertainty' in it.
+     * If the data is available 'flags' must contain LOC_GNSS_CLOCK_HAS_DRIFT.
+     *
+     * This value is mandatory if the receiver has estimated GNSS time
+     */
+    double drift_nsps;
+
+    /**
+     * 1-Sigma uncertainty associated with the clock's drift in nanoseconds (per second).
+     * The uncertainty is represented as an absolute (single sided) value.
+     *
+     * If the data is available 'flags' must contain
+     * LOC_GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY. If GPS has computed a position fix this
+     * field is mandatory and must be populated.
+     */
+    double drift_uncertainty_nsps;
+
+    /**
+     * When there are any discontinuities in the HW clock, this field is
+     * mandatory.
+     *
+     * A "discontinuity" is meant to cover the case of a switch from one source
+     * of clock to another.  A single free-running crystal oscillator (XO)
+     * should generally not have any discontinuities, and this can be set and
+     * left at 0.
+     *
+     * If, however, the time_ns value (HW clock) is derived from a composite of
+     * sources, that is not as smooth as a typical XO, or is otherwise stopped &
+     * restarted, then this value shall be incremented each time a discontinuity
+     * occurs.  (E.g. this value may start at zero at device boot-up and
+     * increment each time there is a change in clock continuity. In the
+     * unlikely event that this value reaches full scale, rollover (not
+     * clamping) is required, such that this value continues to change, during
+     * subsequent discontinuity events.)
+     *
+     * While this number stays the same, between LocGnssClock reports, it can be
+     * safely assumed that the time_ns value has been running continuously, e.g.
+     * derived from a single, high quality clock (XO like, or better, that's
+     * typically used during continuous GNSS signal sampling.)
+     *
+     * It is expected, esp. during periods where there are few GNSS signals
+     * available, that the HW clock be discontinuity-free as long as possible,
+     * as this avoids the need to use (waste) a GNSS measurement to fully
+     * re-solve for the GPS clock bias and drift, when using the accompanying
+     * measurements, from consecutive LocGnssData reports.
+     */
+    uint32_t hw_clock_discontinuity_count;
+
+} LocGnssClock;
+
+/**
+ * Legacy struct to represent a GPS Measurement, it contains raw and computed
+ * information.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssMeasurement instead.
+ */
+typedef struct {
+    /** set to sizeof(LocGpsMeasurement) */
+    size_t size;
+    LocGpsMeasurementFlags flags;
+    int8_t prn;
+    double time_offset_ns;
+    LocGpsMeasurementState state;
+    int64_t received_gps_tow_ns;
+    int64_t received_gps_tow_uncertainty_ns;
+    double c_n0_dbhz;
+    double pseudorange_rate_mps;
+    double pseudorange_rate_uncertainty_mps;
+    LocGpsAccumulatedDeltaRangeState accumulated_delta_range_state;
+    double accumulated_delta_range_m;
+    double accumulated_delta_range_uncertainty_m;
+    double pseudorange_m;
+    double pseudorange_uncertainty_m;
+    double code_phase_chips;
+    double code_phase_uncertainty_chips;
+    float carrier_frequency_hz;
+    int64_t carrier_cycles;
+    double carrier_phase;
+    double carrier_phase_uncertainty;
+    LocGpsLossOfLock loss_of_lock;
+    int32_t bit_number;
+    int16_t time_from_last_bit_ms;
+    double doppler_shift_hz;
+    double doppler_shift_uncertainty_hz;
+    LocGpsMultipathIndicator multipath_indicator;
+    double snr_db;
+    double elevation_deg;
+    double elevation_uncertainty_deg;
+    double azimuth_deg;
+    double azimuth_uncertainty_deg;
+    bool used_in_fix;
+} LocGpsMeasurement;
+
+/**
+ * Represents a GNSS Measurement, it contains raw and computed information.
+ *
+ * Independence - All signal measurement information (e.g. sv_time,
+ * pseudorange_rate, multipath_indicator) reported in this struct should be
+ * based on GNSS signal measurements only. You may not synthesize measurements
+ * by calculating or reporting expected measurements based on known or estimated
+ * position, velocity, or time.
+ */
+typedef struct {
+    /** set to sizeof(LocGnssMeasurement) */
+    size_t size;
+
+    /** A set of flags indicating the validity of the fields in this data structure. */
+    LocGnssMeasurementFlags flags;
+
+    /**
+     * Satellite vehicle ID number, as defined in LocGnssSvInfo::svid
+     * This is a mandatory value.
+     */
+    int16_t svid;
+
+    /**
+     * Defines the constellation of the given SV. Value should be one of those
+     * LOC_GNSS_CONSTELLATION_* constants
+     */
+    LocGnssConstellationType constellation;
+
+    /**
+     * Time offset at which the measurement was taken in nanoseconds.
+     * The reference receiver's time is specified by LocGpsData::clock::time_ns and should be
+     * interpreted in the same way as indicated by LocGpsClock::type.
+     *
+     * The sign of time_offset_ns is given by the following equation:
+     *      measurement time = LocGpsClock::time_ns + time_offset_ns
+     *
+     * It provides an individual time-stamp for the measurement, and allows sub-nanosecond accuracy.
+     * This is a mandatory value.
+     */
+    double time_offset_ns;
+
+    /**
+     * Per satellite sync state. It represents the current sync state for the associated satellite.
+     * Based on the sync state, the 'received GPS tow' field should be interpreted accordingly.
+     *
+     * This is a mandatory value.
+     */
+    LocGnssMeasurementState state;
+
+    /**
+     * The received GNSS Time-of-Week at the measurement time, in nanoseconds.
+     * Ensure that this field is independent (see comment at top of
+     * LocGnssMeasurement struct.)
+     *
+     * For GPS & QZSS, this is:
+     *   Received GPS Time-of-Week at the measurement time, in nanoseconds.
+     *   The value is relative to the beginning of the current GPS week.
+     *
+     *   Given the highest sync state that can be achieved, per each satellite, valid range
+     *   for this field can be:
+     *     Searching       : [ 0       ]   : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN
+     *     C/A code lock   : [ 0   1ms ]   : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set
+     *     Bit sync        : [ 0  20ms ]   : LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC is set
+     *     Subframe sync   : [ 0    6s ]   : LOC_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC is set
+     *     TOW decoded     : [ 0 1week ]   : LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED is set
+     *
+     *   Note well: if there is any ambiguity in integer millisecond,
+     *   LOC_GNSS_MEASUREMENT_STATE_MSEC_AMBIGUOUS should be set accordingly, in the 'state' field.
+     *
+     *   This value must be populated if 'state' != LOC_GNSS_MEASUREMENT_STATE_UNKNOWN.
+     *
+     * For Glonass, this is:
+     *   Received Glonass time of day, at the measurement time in nanoseconds.
+     *
+     *   Given the highest sync state that can be achieved, per each satellite, valid range for
+     *   this field can be:
+     *     Searching       : [ 0       ]   : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN
+     *     C/A code lock   : [ 0   1ms ]   : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set
+     *     Symbol sync     : [ 0  10ms ]   : LOC_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC is set
+     *     Bit sync        : [ 0  20ms ]   : LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC is set
+     *     String sync     : [ 0    2s ]   : LOC_GNSS_MEASUREMENT_STATE_GLO_STRING_SYNC is set
+     *     Time of day     : [ 0  1day ]   : LOC_GNSS_MEASUREMENT_STATE_GLO_TOD_DECODED is set
+     *
+     * For Beidou, this is:
+     *   Received Beidou time of week, at the measurement time in nanoseconds.
+     *
+     *   Given the highest sync state that can be achieved, per each satellite, valid range for
+     *   this field can be:
+     *     Searching    : [ 0       ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN
+     *     C/A code lock: [ 0   1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set
+     *     Bit sync (D2): [ 0   2ms ] : LOC_GNSS_MEASUREMENT_STATE_BDS_D2_BIT_SYNC is set
+     *     Bit sync (D1): [ 0  20ms ] : LOC_GNSS_MEASUREMENT_STATE_BIT_SYNC is set
+     *     Subframe (D2): [ 0  0.6s ] : LOC_GNSS_MEASUREMENT_STATE_BDS_D2_SUBFRAME_SYNC is set
+     *     Subframe (D1): [ 0    6s ] : LOC_GNSS_MEASUREMENT_STATE_SUBFRAME_SYNC is set
+     *     Time of week : [ 0 1week ] : LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED is set
+     *
+     * For Galileo, this is:
+     *   Received Galileo time of week, at the measurement time in nanoseconds.
+     *
+     *     E1BC code lock   : [ 0   4ms ]   : LOC_GNSS_MEASUREMENT_STATE_GAL_E1BC_CODE_LOCK is set
+     *     E1C 2nd code lock: [ 0 100ms ]   :
+     *     LOC_GNSS_MEASUREMENT_STATE_GAL_E1C_2ND_CODE_LOCK is set
+     *
+     *     E1B page    : [ 0    2s ] : LOC_GNSS_MEASUREMENT_STATE_GAL_E1B_PAGE_SYNC is set
+     *     Time of week: [ 0 1week ] : LOC_GNSS_MEASUREMENT_STATE_TOW_DECODED is set
+     *
+     * For SBAS, this is:
+     *   Received SBAS time, at the measurement time in nanoseconds.
+     *
+     *   Given the highest sync state that can be achieved, per each satellite,
+     *   valid range for this field can be:
+     *     Searching    : [ 0     ] : LOC_GNSS_MEASUREMENT_STATE_UNKNOWN
+     *     C/A code lock: [ 0 1ms ] : LOC_GNSS_MEASUREMENT_STATE_CODE_LOCK is set
+     *     Symbol sync  : [ 0 2ms ] : LOC_GNSS_MEASUREMENT_STATE_SYMBOL_SYNC is set
+     *     Message      : [ 0  1s ] : LOC_GNSS_MEASUREMENT_STATE_SBAS_SYNC is set
+    */
+    int64_t received_sv_time_in_ns;
+
+    /**
+     * 1-Sigma uncertainty of the Received GPS Time-of-Week in nanoseconds.
+     *
+     * This value must be populated if 'state' != LOC_GPS_MEASUREMENT_STATE_UNKNOWN.
+     */
+    int64_t received_sv_time_uncertainty_in_ns;
+
+    /**
+     * Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
+     * It contains the measured C/N0 value for the signal at the antenna port.
+     *
+     * This is a mandatory value.
+     */
+    double c_n0_dbhz;
+
+    /**
+     * Pseudorange rate at the timestamp in m/s. The correction of a given
+     * Pseudorange Rate value includes corrections for receiver and satellite
+     * clock frequency errors. Ensure that this field is independent (see
+     * comment at top of LocGnssMeasurement struct.)
+     *
+     * It is mandatory to provide the 'uncorrected' 'pseudorange rate', and provide LocGpsClock's
+     * 'drift' field as well (When providing the uncorrected pseudorange rate, do not apply the
+     * corrections described above.)
+     *
+     * The value includes the 'pseudorange rate uncertainty' in it.
+     * A positive 'uncorrected' value indicates that the SV is moving away from the receiver.
+     *
+     * The sign of the 'uncorrected' 'pseudorange rate' and its relation to the sign of 'doppler
+     * shift' is given by the equation:
+     *      pseudorange rate = -k * doppler shift   (where k is a constant)
+     *
+     * This should be the most accurate pseudorange rate available, based on
+     * fresh signal measurements from this channel.
+     *
+     * It is mandatory that this value be provided at typical carrier phase PRR
+     * quality (few cm/sec per second of uncertainty, or better) - when signals
+     * are sufficiently strong & stable, e.g. signals from a GPS simulator at >=
+     * 35 dB-Hz.
+     */
+    double pseudorange_rate_mps;
+
+    /**
+     * 1-Sigma uncertainty of the pseudorange_rate_mps.
+     * The uncertainty is represented as an absolute (single sided) value.
+     *
+     * This is a mandatory value.
+     */
+    double pseudorange_rate_uncertainty_mps;
+
+    /**
+     * Accumulated delta range's state. It indicates whether ADR is reset or there is a cycle slip
+     * (indicating loss of lock).
+     *
+     * This is a mandatory value.
+     */
+    LocGnssAccumulatedDeltaRangeState accumulated_delta_range_state;
+
+    /**
+     * Accumulated delta range since the last channel reset in meters.
+     * A positive value indicates that the SV is moving away from the receiver.
+     *
+     * The sign of the 'accumulated delta range' and its relation to the sign of 'carrier phase'
+     * is given by the equation:
+     *          accumulated delta range = -k * carrier phase    (where k is a constant)
+     *
+     * This value must be populated if 'accumulated delta range state' != LOC_GPS_ADR_STATE_UNKNOWN.
+     * However, it is expected that the data is only accurate when:
+     *      'accumulated delta range state' == LOC_GPS_ADR_STATE_VALID.
+     */
+    double accumulated_delta_range_m;
+
+    /**
+     * 1-Sigma uncertainty of the accumulated delta range in meters.
+     * This value must be populated if 'accumulated delta range state' != LOC_GPS_ADR_STATE_UNKNOWN.
+     */
+    double accumulated_delta_range_uncertainty_m;
+
+    /**
+     * Carrier frequency at which codes and messages are modulated, it can be L1 or L2.
+     * If the field is not set, the carrier frequency is assumed to be L1.
+     *
+     * If the data is available, 'flags' must contain
+     * LOC_GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY.
+     */
+    float carrier_frequency_hz;
+
+    /**
+     * The number of full carrier cycles between the satellite and the receiver.
+     * The reference frequency is given by the field 'carrier_frequency_hz'.
+     * Indications of possible cycle slips and resets in the accumulation of
+     * this value can be inferred from the accumulated_delta_range_state flags.
+     *
+     * If the data is available, 'flags' must contain
+     * LOC_GNSS_MEASUREMENT_HAS_CARRIER_CYCLES.
+     */
+    int64_t carrier_cycles;
+
+    /**
+     * The RF phase detected by the receiver, in the range [0.0, 1.0].
+     * This is usually the fractional part of the complete carrier phase measurement.
+     *
+     * The reference frequency is given by the field 'carrier_frequency_hz'.
+     * The value contains the 'carrier-phase uncertainty' in it.
+     *
+     * If the data is available, 'flags' must contain
+     * LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE.
+     */
+    double carrier_phase;
+
+    /**
+     * 1-Sigma uncertainty of the carrier-phase.
+     * If the data is available, 'flags' must contain
+     * LOC_GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY.
+     */
+    double carrier_phase_uncertainty;
+
+    /**
+     * An enumeration that indicates the 'multipath' state of the event.
+     *
+     * The multipath Indicator is intended to report the presence of overlapping
+     * signals that manifest as distorted correlation peaks.
+     *
+     * - if there is a distorted correlation peak shape, report that multipath
+     *   is LOC_GNSS_MULTIPATH_INDICATOR_PRESENT.
+     * - if there is not a distorted correlation peak shape, report
+     *   LOC_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT
+     * - if signals are too weak to discern this information, report
+     *   LOC_GNSS_MULTIPATH_INDICATOR_UNKNOWN
+     *
+     * Example: when doing the standardized overlapping Multipath Performance
+     * test (3GPP TS 34.171) the Multipath indicator should report
+     * LOC_GNSS_MULTIPATH_INDICATOR_PRESENT for those signals that are tracked, and
+     * contain multipath, and LOC_GNSS_MULTIPATH_INDICATOR_NOT_PRESENT for those
+     * signals that are tracked and do not contain multipath.
+     */
+    LocGnssMultipathIndicator multipath_indicator;
+
+    /**
+     * Signal-to-noise ratio at correlator output in dB.
+     * If the data is available, 'flags' must contain LOC_GNSS_MEASUREMENT_HAS_SNR.
+     * This is the power ratio of the "correlation peak height above the
+     * observed noise floor" to "the noise RMS".
+     */
+    double snr_db;
+} LocGnssMeasurement;
+
+/**
+ * Legacy struct to represents a reading of GPS measurements.
+ * Deprecated, to be removed in the next Android release.
+ * Use LocGnssData instead.
+ */
+typedef struct {
+    /** set to sizeof(LocGpsData) */
+    size_t size;
+    size_t measurement_count;
+    LocGpsMeasurement measurements[LOC_GPS_MAX_MEASUREMENT];
+
+    /** The GPS clock time reading. */
+    LocGpsClock clock;
+} LocGpsData;
+
+/**
+ * Represents a reading of GNSS measurements. For devices where LocGnssSystemInfo's
+ * year_of_hw is set to 2016+, it is mandatory that these be provided, on
+ * request, when the GNSS receiver is searching/tracking signals.
+ *
+ * - Reporting of GPS constellation measurements is mandatory.
+ * - Reporting of all tracked constellations are encouraged.
+ */
+typedef struct {
+    /** set to sizeof(LocGnssData) */
+    size_t size;
+
+    /** Number of measurements. */
+    size_t measurement_count;
+
+    /** The array of measurements. */
+    LocGnssMeasurement measurements[LOC_GNSS_MAX_MEASUREMENT];
+
+    /** The GPS clock time reading. */
+    LocGnssClock clock;
+} LocGnssData;
+
+/**
+ * The legacy callback for to report measurements from the HAL.
+ *
+ * This callback is deprecated, and will be removed in the next release. Use
+ * loc_gnss_measurement_callback() instead.
+ *
+ * Parameters:
+ *    data - A data structure containing the measurements.
+ */
+typedef void (*loc_gps_measurement_callback) (LocGpsData* data);
+
+/**
+ * The callback for to report measurements from the HAL.
+ *
+ * Parameters:
+ *    data - A data structure containing the measurements.
+ */
+typedef void (*loc_gnss_measurement_callback) (LocGnssData* data);
+
+typedef struct {
+    /** set to sizeof(LocGpsMeasurementCallbacks) */
+    size_t size;
+    loc_gps_measurement_callback measurement_callback;
+    loc_gnss_measurement_callback loc_gnss_measurement_callback;
+} LocGpsMeasurementCallbacks;
+
+#define LOC_GPS_MEASUREMENT_OPERATION_SUCCESS          0
+#define LOC_GPS_MEASUREMENT_ERROR_ALREADY_INIT      -100
+#define LOC_GPS_MEASUREMENT_ERROR_GENERIC           -101
+
+/**
+ * Extended interface for GPS Measurements support.
+ */
+typedef struct {
+    /** Set to sizeof(LocGpsMeasurementInterface) */
+    size_t size;
+
+    /**
+     * Initializes the interface and registers the callback routines with the HAL.
+     * After a successful call to 'init' the HAL must begin to provide updates at its own phase.
+     *
+     * Status:
+     *    LOC_GPS_MEASUREMENT_OPERATION_SUCCESS
+     *    LOC_GPS_MEASUREMENT_ERROR_ALREADY_INIT - if a callback has already been registered without a
+     *              corresponding call to 'close'
+     *    LOC_GPS_MEASUREMENT_ERROR_GENERIC - if any other error occurred, it is expected that the HAL
+     *              will not generate any updates upon returning this error code.
+     */
+    int (*init) (LocGpsMeasurementCallbacks* callbacks);
+
+    /**
+     * Stops updates from the HAL, and unregisters the callback routines.
+     * After a call to stop, the previously registered callbacks must be considered invalid by the
+     * HAL.
+     * If stop is invoked without a previous 'init', this function should perform no work.
+     */
+    void (*close) ();
+
+} LocGpsMeasurementInterface;
+
+#if 0
+/**
+ * Legacy struct to represents a GPS navigation message (or a fragment of it).
+ * Deprecated, to be removed in the next Android release.
+ * Use GnssNavigationMessage instead.
+ */
+typedef struct {
+    /** set to sizeof(GpsNavigationMessage) */
+    size_t size;
+    int8_t prn;
+    GpsNavigationMessageType type;
+    NavigationMessageStatus status;
+    int16_t message_id;
+    int16_t submessage_id;
+    size_t data_length;
+    uint8_t* data;
+} GpsNavigationMessage;
+
+/** Represents a GPS navigation message (or a fragment of it). */
+typedef struct {
+    /** set to sizeof(GnssNavigationMessage) */
+    size_t size;
+
+    /**
+     * Satellite vehicle ID number, as defined in LocGnssSvInfo::svid
+     * This is a mandatory value.
+     */
+    int16_t svid;
+
+    /**
+     * The type of message contained in the structure.
+     * This is a mandatory value.
+     */
+    GnssNavigationMessageType type;
+
+    /**
+     * The status of the received navigation message.
+     * No need to send any navigation message that contains words with parity error and cannot be
+     * corrected.
+     */
+    NavigationMessageStatus status;
+
+    /**
+     * Message identifier. It provides an index so the complete Navigation
+     * Message can be assembled.
+     *
+     * - For GPS L1 C/A subframe 4 and 5, this value corresponds to the 'frame
+     *   id' of the navigation message, in the range of 1-25 (Subframe 1, 2, 3
+     *   does not contain a 'frame id' and this value can be set to -1.)
+     *
+     * - For Glonass L1 C/A, this refers to the frame ID, in the range of 1-5.
+     *
+     * - For BeiDou D1, this refers to the frame number in the range of 1-24
+     *
+     * - For Beidou D2, this refers to the frame number, in the range of 1-120
+     *
+     * - For Galileo F/NAV nominal frame structure, this refers to the subframe
+     *   number, in the range of 1-12
+     *
+     * - For Galileo I/NAV nominal frame structure, this refers to the subframe
+     *   number in the range of 1-24
+     */
+    int16_t message_id;
+
+    /**
+     * Sub-message identifier. If required by the message 'type', this value
+     * contains a sub-index within the current message (or frame) that is being
+     * transmitted.
+     *
+     * - For GPS L1 C/A, BeiDou D1 & BeiDou D2, the submessage id corresponds to
+     *   the subframe number of the navigation message, in the range of 1-5.
+     *
+     * - For Glonass L1 C/A, this refers to the String number, in the range from
+     *   1-15
+     *
+     * - For Galileo F/NAV, this refers to the page type in the range 1-6
+     *
+     * - For Galileo I/NAV, this refers to the word type in the range 1-10+
+     */
+    int16_t submessage_id;
+
+    /**
+     * The length of the data (in bytes) contained in the current message.
+     * If this value is different from zero, 'data' must point to an array of the same size.
+     * e.g. for L1 C/A the size of the sub-frame will be 40 bytes (10 words, 30 bits/word).
+     *
+     * This is a mandatory value.
+     */
+    size_t data_length;
+
+    /**
+     * The data of the reported GPS message. The bytes (or words) specified
+     * using big endian format (MSB first).
+     *
+     * - For GPS L1 C/A, Beidou D1 & Beidou D2, each subframe contains 10 30-bit
+     *   words. Each word (30 bits) should be fit into the last 30 bits in a
+     *   4-byte word (skip B31 and B32), with MSB first, for a total of 40
+     *   bytes, covering a time period of 6, 6, and 0.6 seconds, respectively.
+     *
+     * - For Glonass L1 C/A, each string contains 85 data bits, including the
+     *   checksum.  These bits should be fit into 11 bytes, with MSB first (skip
+     *   B86-B88), covering a time period of 2 seconds.
+     *
+     * - For Galileo F/NAV, each word consists of 238-bit (sync & tail symbols
+     *   excluded). Each word should be fit into 30-bytes, with MSB first (skip
+     *   B239, B240), covering a time period of 10 seconds.
+     *
+     * - For Galileo I/NAV, each page contains 2 page parts, even and odd, with
+     *   a total of 2x114 = 228 bits, (sync & tail excluded) that should be fit
+     *   into 29 bytes, with MSB first (skip B229-B232).
+     */
+    uint8_t* data;
+
+} GnssNavigationMessage;
+
+/**
+ * The legacy callback to report an available fragment of a GPS navigation
+ * messages from the HAL.
+ *
+ * This callback is deprecated, and will be removed in the next release. Use
+ * gnss_navigation_message_callback() instead.
+ *
+ * Parameters:
+ *      message - The GPS navigation submessage/subframe representation.
+ */
+typedef void (*gps_navigation_message_callback) (GpsNavigationMessage* message);
+
+/**
+ * The callback to report an available fragment of a GPS navigation messages from the HAL.
+ *
+ * Parameters:
+ *      message - The GPS navigation submessage/subframe representation.
+ */
+typedef void (*gnss_navigation_message_callback) (GnssNavigationMessage* message);
+
+typedef struct {
+    /** set to sizeof(GpsNavigationMessageCallbacks) */
+    size_t size;
+    gps_navigation_message_callback navigation_message_callback;
+    gnss_navigation_message_callback gnss_navigation_message_callback;
+} GpsNavigationMessageCallbacks;
+
+#define GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS             0
+#define GPS_NAVIGATION_MESSAGE_ERROR_ALREADY_INIT         -100
+#define GPS_NAVIGATION_MESSAGE_ERROR_GENERIC              -101
+
+/**
+ * Extended interface for GPS navigation message reporting support.
+ */
+typedef struct {
+    /** Set to sizeof(GpsNavigationMessageInterface) */
+    size_t size;
+
+    /**
+     * Initializes the interface and registers the callback routines with the HAL.
+     * After a successful call to 'init' the HAL must begin to provide updates as they become
+     * available.
+     *
+     * Status:
+     *      GPS_NAVIGATION_MESSAGE_OPERATION_SUCCESS
+     *      GPS_NAVIGATION_MESSAGE_ERROR_ALREADY_INIT - if a callback has already been registered
+     *              without a corresponding call to 'close'.
+     *      GPS_NAVIGATION_MESSAGE_ERROR_GENERIC - if any other error occurred, it is expected that
+     *              the HAL will not generate any updates upon returning this error code.
+     */
+    int (*init) (GpsNavigationMessageCallbacks* callbacks);
+
+    /**
+     * Stops updates from the HAL, and unregisters the callback routines.
+     * After a call to stop, the previously registered callbacks must be considered invalid by the
+     * HAL.
+     * If stop is invoked without a previous 'init', this function should perform no work.
+     */
+    void (*close) ();
+
+} GpsNavigationMessageInterface;
+#endif
+
+/**
+ * Interface for passing GNSS configuration contents from platform to HAL.
+ */
+typedef struct {
+    /** Set to sizeof(LocGnssConfigurationInterface) */
+    size_t size;
+
+    /**
+     * Deliver GNSS configuration contents to HAL.
+     * Parameters:
+     *     config_data - a pointer to a char array which holds what usually is expected from
+                         file(/vendor/etc/gps.conf), i.e., a sequence of UTF8 strings separated by '\n'.
+     *     length - total number of UTF8 characters in configuraiton data.
+     *
+     * IMPORTANT:
+     *      GPS HAL should expect this function can be called multiple times. And it may be
+     *      called even when GpsLocationProvider is already constructed and enabled. GPS HAL
+     *      should maintain the existing requests for various callback regardless the change
+     *      in configuration data.
+     */
+    void (*configuration_update) (const char* config_data, int32_t length);
+} LocGnssConfigurationInterface;
+
+__END_DECLS
+
+#endif /* LOC_GPS_H */
+
diff --git a/gps/utils/loc_log.cpp b/gps/utils/loc_log.cpp
new file mode 100644
index 0000000..2110683
--- /dev/null
+++ b/gps/utils/loc_log.cpp
@@ -0,0 +1,282 @@
+/* Copyright (c) 2011-2012, 2015, 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include "log_util.h"
+#include "loc_log.h"
+#include "msg_q.h"
+#include <loc_pla.h>
+#include "LogBuffer.h"
+#include <unordered_map>
+#include <fstream>
+#include <algorithm>
+#include <string>
+#include <cctype>
+#define  BUFFER_SIZE  120
+#define  LOG_TAG_LEVEL_CONF_FILE_PATH "/data/vendor/location/gps.prop"
+
+// Logging Improvements
+const char *loc_logger_boolStr[]={"False","True"};
+const char VOID_RET[]   = "None";
+const char FROM_AFW[]   = "===>";
+const char TO_MODEM[]   = "--->";
+const char FROM_MODEM[] = "<---";
+const char TO_AFW[]     = "<===";
+const char EXIT_TAG[]   = "Exiting";
+const char ENTRY_TAG[]  = "Entering";
+const char EXIT_ERROR_TAG[]  = "Exiting with error";
+
+int build_type_prop = BUILD_TYPE_PROP_NA;
+
+const string gEmptyStr = "";
+const string gUnknownStr = "UNKNOWN";
+/* Logging Mechanism */
+loc_logger_s_type loc_logger;
+
+/* tag base logging control map*/
+static std::unordered_map<std::string, uint8_t> tag_level_map;
+static bool tag_map_inited = false;
+
+/* returns the least signification bit that is set in the mask
+   Param
+      mask -        bit mask.
+      clearTheBit - if true, mask gets modified upon return.
+   returns 0 if mask is 0.
+*/
+uint64_t loc_get_least_bit(uint64_t& mask, bool clearTheBit) {
+    uint64_t bit = 0;
+
+    if (mask > 0) {
+        uint64_t less1 = mask - 1;
+        bit = mask & ~(less1);
+        if (clearTheBit) {
+            mask &= less1;
+        }
+    }
+
+    return bit;
+}
+
+string loc_get_bit_defs(uint64_t mask, const NameValTbl& tbl) {
+    string out;
+    while (mask > 0) {
+        out += loc_get_name_from_tbl(tbl, loc_get_least_bit(mask));
+        if (mask > 0) {
+            out += " | ";
+        }
+    }
+    return out;
+}
+
+DECLARE_TBL(loc_msg_q_status) =
+{
+    NAME_VAL( eMSG_Q_SUCCESS ),
+    NAME_VAL( eMSG_Q_FAILURE_GENERAL ),
+    NAME_VAL( eMSG_Q_INVALID_PARAMETER ),
+    NAME_VAL( eMSG_Q_INVALID_HANDLE ),
+    NAME_VAL( eMSG_Q_UNAVAILABLE_RESOURCE ),
+    NAME_VAL( eMSG_Q_INSUFFICIENT_BUFFER )
+};
+
+/* Find msg_q status name */
+const char* loc_get_msg_q_status(int status)
+{
+   return loc_get_name_from_val(loc_msg_q_status_tbl, (int64_t) status);
+}
+
+//Target names
+DECLARE_TBL(target_name) =
+{
+    NAME_VAL(GNSS_NONE),
+    NAME_VAL(GNSS_MSM),
+    NAME_VAL(GNSS_GSS),
+    NAME_VAL(GNSS_MDM),
+    NAME_VAL(GNSS_AUTO),
+    NAME_VAL(GNSS_UNKNOWN)
+};
+
+/*===========================================================================
+
+FUNCTION loc_get_target_name
+
+DESCRIPTION
+   Returns pointer to a string that contains name of the target
+
+   XX:XX:XX.000\0
+
+RETURN VALUE
+   The target name string
+
+===========================================================================*/
+const char *loc_get_target_name(unsigned int target)
+{
+    int64_t index = 0;
+    static char ret[BUFFER_SIZE];
+
+    snprintf(ret, sizeof(ret), " %s with%s SSC",
+             loc_get_name_from_val(target_name_tbl, getTargetGnssType(target)),
+             ((target & HAS_SSC) == HAS_SSC) ? gEmptyStr.c_str() : "out");
+
+    return ret;
+}
+
+
+/*===========================================================================
+
+FUNCTION loc_get_time
+
+DESCRIPTION
+   Logs a callback event header.
+   The pointer time_string should point to a buffer of at least 13 bytes:
+
+   XX:XX:XX.000\0
+
+RETURN VALUE
+   The time string
+
+===========================================================================*/
+char *loc_get_time(char *time_string, size_t buf_size)
+{
+   struct timeval now;     /* sec and usec     */
+   struct tm now_tm;       /* broken-down time */
+   char hms_string[80];    /* HH:MM:SS         */
+
+   gettimeofday(&now, NULL);
+   localtime_r(&now.tv_sec, &now_tm);
+
+   strftime(hms_string, sizeof hms_string, "%H:%M:%S", &now_tm);
+   snprintf(time_string, buf_size, "%s.%03d", hms_string, (int) (now.tv_usec / 1000));
+
+   return time_string;
+}
+
+/*===========================================================================
+FUNCTION get_timestamp
+
+DESCRIPTION
+   Generates a timestamp using the current system time
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Char pointer to the parameter str
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+char * get_timestamp(char *str, unsigned long buf_size)
+{
+  struct timeval tv;
+  struct timezone tz;
+  int hh, mm, ss;
+  gettimeofday(&tv, &tz);
+  hh = tv.tv_sec/3600%24;
+  mm = (tv.tv_sec%3600)/60;
+  ss = tv.tv_sec%60;
+  snprintf(str, buf_size, "%02d:%02d:%02d.%06ld", hh, mm, ss, tv.tv_usec);
+  return str;
+}
+
+/*===========================================================================
+
+FUNCTION log_buffer_insert
+
+DESCRIPTION
+   Insert a log sentence with specific level to the log buffer.
+
+RETURN VALUE
+   N/A
+
+===========================================================================*/
+void log_buffer_insert(char *str, unsigned long buf_size, int level)
+{
+    timespec tv;
+    clock_gettime(CLOCK_BOOTTIME, &tv);
+    uint64_t elapsedTime = (uint64_t)tv.tv_sec + (uint64_t)tv.tv_nsec/1000000000;
+    string ss = str;
+    loc_util::LogBuffer::getInstance()->append(ss, level, elapsedTime);
+}
+
+void log_tag_level_map_init()
+{
+    if (tag_map_inited) {
+        return;
+    }
+
+    std::string filename = LOG_TAG_LEVEL_CONF_FILE_PATH;
+
+    std::ifstream s(filename);
+    if (!s.is_open()) {
+        ALOGE("cannot open file:%s", LOG_TAG_LEVEL_CONF_FILE_PATH);
+    } else {
+        std::string line;
+        while (std::getline(s, line)) {
+            line.erase(std::remove(line.begin(), line.end(), ' '), line.end());
+            int pos = line.find('=');
+            if (pos <= 0 || pos >= (line.size() - 1)) {
+                ALOGE("wrong format in gps.prop");
+                continue;
+            }
+            std::string tag = line.substr(0, pos);
+            std::string level = line.substr(pos+1, 1);
+            if (!std::isdigit(*(level.begin()))) {
+                ALOGE("wrong format in gps.prop");
+                continue;
+            }
+            tag_level_map[tag] = (uint8_t)std::stoul(level);
+        }
+    }
+    tag_map_inited = true;
+}
+
+int get_tag_log_level(const char* tag)
+{
+    if (!tag_map_inited) {
+        return -1;
+    }
+
+    // in case LOG_TAG isn't defined in a source file, use the global log level
+    if (tag == NULL) {
+        return loc_logger.DEBUG_LEVEL;
+    }
+    int log_level;
+    auto search = tag_level_map.find(std::string(tag));
+    if (tag_level_map.end() != search) {
+        log_level = search->second;
+    } else {
+        log_level = loc_logger.DEBUG_LEVEL;
+    }
+    return log_level;
+}
diff --git a/gps/utils/loc_log.h b/gps/utils/loc_log.h
new file mode 100644
index 0000000..b750932
--- /dev/null
+++ b/gps/utils/loc_log.h
@@ -0,0 +1,122 @@
+/* Copyright (c) 2011-2012, 2015, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOC_LOG_H
+#define LOC_LOG_H
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <unordered_map>
+#include <string>
+#include "loc_target.h"
+#include "loc_misc_utils.h"
+
+using std::string;
+using std::unordered_map;
+
+typedef unordered_map<int64_t, string> NameValTbl;
+
+#define NAME_VAL(x) {x, "" #x ""}
+#define DECLARE_TBL(T) static const NameValTbl T##_tbl
+
+extern const string gEmptyStr;
+extern const string gUnknownStr;
+
+#define CHECK_MASK(type, value, mask_var, mask) \
+   (((mask_var) & (mask)) ? (type) (value) : (type) (-1))
+
+#define LOC_TABLE_SIZE(table) (sizeof(table)/sizeof((table)[0]))
+
+#define FIELDVAL_DEC(field) \
+        loc_put_tag_val(#field, to_string(field))
+#define FIELDVAL_DEC_ARR(field) \
+        loc_put_tag_val(#field, \
+                        loc_parenthesize(loc_prim_arr_to_string(field, \
+                                                                sizeof(field)/sizeof(field[0]))))
+#define FIELDVAL_HEX(field) \
+        loc_put_tag_val(#field, to_string_hex(field))
+#define FIELDVAL_HEX_ARR(field) \
+        loc_put_tag_val(#field, \
+                        loc_parenthesize(loc_prim_arr_to_string(field, \
+                                                                sizeof(field)/sizeof(field[0]), \
+                                                                false)))
+#define FIELDVAL_ENUM(field, tbl) \
+        loc_put_tag_val(#field, \
+                        loc_get_name_from_tbl(tbl, field, gUnknownStr))
+#define FIELDVAL_MASK(field, tbl) \
+        loc_put_tag_val(#field, \
+                        to_string_hex((uint64_t)field) + " " + \
+                                loc_parenthesize(loc_get_bit_defs(field, tbl)))
+
+/* get from a table of strings with index */
+/* tbl - map of <int, string> entries
+   key - key to the matching entry
+   defalt - default pointer in case of incorrect parameters
+ */
+inline static const string& loc_get_name_from_tbl(const NameValTbl& tbl, int64_t key,
+                                    const string& defalt = gEmptyStr) {
+    auto item = tbl.find(key);
+    if (item != tbl.end()) {
+        return item->second;
+    } else {
+        return defalt;
+    }
+}
+
+/* puts to string formatted "TAG: VAL" with option ending string, default to newline */
+inline string loc_put_tag_val(const string& tag, const string& val, const string& eol = "\n") {
+    return tag + ": " + val + eol;
+}
+
+inline string loc_parenthesize(const string& str) {
+    return "(" + str + ")";
+}
+
+/* Get names from value */
+inline const char* loc_get_name_from_val(const NameValTbl& table, int64_t value) {
+    return loc_get_name_from_tbl(table, value, gUnknownStr).c_str();
+}
+
+inline const char* log_succ_fail_string(int is_succ) {
+    return is_succ? "successful" : "failed";
+}
+
+/* prints mask into a string with bit definitions from tbl */
+/* mask - bit mask, to be expanded into " BIT_NAMEx | BIT_NAMEy ... "
+   tbl - a table with defs for each bit, defined as <bit, name> entries
+         {{bit0, "BIT0_NAME"}, {bit1, "BIT1_NAME"}, .... {bitn, "BITn_NAME"} }
+   entries - number of strings in the table
+ */
+string loc_get_bit_defs(uint64_t mask, const NameValTbl& tbl);
+uint64_t loc_get_least_bit(uint64_t& mask, bool clearThebit = true);
+const char* loc_get_msg_q_status(int status);
+const char* loc_get_target_name(unsigned int target);
+char *loc_get_time(char *time_string, size_t buf_size);
+
+#endif /* LOC_LOG_H */
diff --git a/gps/utils/loc_misc_utils.cpp b/gps/utils/loc_misc_utils.cpp
new file mode 100644
index 0000000..fbcaef4
--- /dev/null
+++ b/gps/utils/loc_misc_utils.cpp
@@ -0,0 +1,351 @@
+/* Copyright (c) 2014, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_misc_utils"
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <dlfcn.h>
+#include <math.h>
+#include <log_util.h>
+#include <loc_misc_utils.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#ifndef MSEC_IN_ONE_SEC
+#define MSEC_IN_ONE_SEC 1000ULL
+#endif
+#define GET_MSEC_FROM_TS(ts) ((ts.tv_sec * MSEC_IN_ONE_SEC) + (ts.tv_nsec + 500000)/1000000)
+
+int loc_util_split_string(char *raw_string, char **split_strings_ptr,
+                          int max_num_substrings, char delimiter)
+{
+    int raw_string_index=0;
+    int num_split_strings=0;
+    unsigned char end_string=0;
+    int raw_string_length=0;
+
+    if(!raw_string || !split_strings_ptr) {
+        LOC_LOGE("%s:%d]: NULL parameters", __func__, __LINE__);
+        num_split_strings = -1;
+        goto err;
+    }
+    LOC_LOGD("%s:%d]: raw string: %s\n", __func__, __LINE__, raw_string);
+    raw_string_length = strlen(raw_string) + 1;
+    split_strings_ptr[num_split_strings] = &raw_string[raw_string_index];
+    for(raw_string_index=0; raw_string_index < raw_string_length; raw_string_index++) {
+        if(raw_string[raw_string_index] == '\0')
+            end_string=1;
+        if((raw_string[raw_string_index] == delimiter) || end_string) {
+            raw_string[raw_string_index] = '\0';
+            if (num_split_strings < max_num_substrings) {
+                LOC_LOGD("%s:%d]: split string: %s\n",
+                         __func__, __LINE__, split_strings_ptr[num_split_strings]);
+            }
+            num_split_strings++;
+            if(((raw_string_index + 1) < raw_string_length) &&
+               (num_split_strings < max_num_substrings)) {
+                split_strings_ptr[num_split_strings] = &raw_string[raw_string_index+1];
+            }
+            else {
+                break;
+            }
+        }
+        if(end_string)
+            break;
+    }
+err:
+    LOC_LOGD("%s:%d]: num_split_strings: %d\n", __func__, __LINE__, num_split_strings);
+    return num_split_strings;
+}
+
+void loc_util_trim_space(char *org_string)
+{
+    char *scan_ptr, *write_ptr;
+    char *first_nonspace = NULL, *last_nonspace = NULL;
+
+    if(org_string == NULL) {
+        LOC_LOGE("%s:%d]: NULL parameter", __func__, __LINE__);
+        goto err;
+    }
+
+    scan_ptr = write_ptr = org_string;
+
+    while (*scan_ptr) {
+        //Find the first non-space character
+        if ( !isspace(*scan_ptr) && first_nonspace == NULL) {
+            first_nonspace = scan_ptr;
+        }
+        //Once the first non-space character is found in the
+        //above check, keep shifting the characters to the left
+        //to replace the spaces
+        if (first_nonspace != NULL) {
+            *(write_ptr++) = *scan_ptr;
+            //Keep track of which was the last non-space character
+            //encountered
+            //last_nonspace will not be updated in the case where
+            //the string ends with spaces
+            if ( !isspace(*scan_ptr)) {
+                last_nonspace = write_ptr;
+            }
+        }
+        scan_ptr++;
+    }
+    //Add NULL terminator after the last non-space character
+    if (last_nonspace) { *last_nonspace = '\0'; }
+err:
+    return;
+}
+
+inline void logDlError(const char* failedCall) {
+    const char * err = dlerror();
+    LOC_LOGe("%s error: %s", failedCall, (nullptr == err) ? "unknown" : err);
+}
+
+void* dlGetSymFromLib(void*& libHandle, const char* libName, const char* symName)
+{
+    void* sym = nullptr;
+    if ((nullptr != libHandle || nullptr != libName) && nullptr != symName) {
+        if (nullptr == libHandle) {
+            libHandle = dlopen(libName, RTLD_NOW);
+            if (nullptr == libHandle) {
+                logDlError("dlopen");
+            }
+        }
+        // NOT else, as libHandle gets assigned 5 line above
+        if (nullptr != libHandle) {
+            sym = dlsym(libHandle, symName);
+            if (nullptr == sym) {
+                logDlError("dlsym");
+            }
+        }
+    } else {
+        LOC_LOGe("Either libHandle (%p) or libName (%p) must not be null; "
+                 "symName (%p) can not be null.", libHandle, libName, symName);
+    }
+
+    return sym;
+}
+
+uint64_t getQTimerTickCount()
+{
+    uint64_t qTimerCount = 0;
+#if __aarch64__
+    asm volatile("mrs %0, cntvct_el0" : "=r" (qTimerCount));
+#elif defined (__i386__) || defined (__x86_64__)
+    /* Qtimer not supported in x86 architecture */
+    qTimerCount = 0;
+#else
+    asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (qTimerCount));
+#endif
+
+    return qTimerCount;
+}
+
+uint64_t getQTimerDeltaNanos()
+{
+    char qtimer_val_string[100];
+    char *temp;
+    uint64_t local_qtimer = 0, remote_qtimer = 0;
+    int mdm_fd = -1, wlan_fd = -1, ret = 0;
+    uint64_t delta = 0;
+
+    memset(qtimer_val_string, '\0', sizeof(qtimer_val_string));
+
+    char devNode[] = "/sys/bus/mhi/devices/0306_00.01.00/time_us";
+    for (; devNode[27] < 3 && mdm_fd < 0; devNode[27]++) {
+        mdm_fd = ::open(devNode, O_RDONLY);
+        if (mdm_fd < 0) {
+            LOC_LOGe("MDM open file: %s error: %s", devNode, strerror(errno));
+        }
+    }
+    if (mdm_fd > 0) {
+        ret = read(mdm_fd, qtimer_val_string, sizeof(qtimer_val_string)-1);
+        ::close(mdm_fd);
+        if (ret < 0) {
+            LOC_LOGe("MDM read time_us file error: %s", strerror(errno));
+        } else {
+            temp = qtimer_val_string;
+            temp = strchr(temp, ':');
+            temp = temp + 2;
+            local_qtimer = atoll(temp);
+
+            temp = strchr(temp, ':');
+            temp = temp + 2;
+            remote_qtimer = atoll(temp);
+
+            if (local_qtimer >= remote_qtimer) {
+                delta = (local_qtimer - remote_qtimer) * 1000;
+            }
+            LOC_LOGv("qtimer values in microseconds: local:%" PRIi64 " remote:%" PRIi64 ""
+                     " delta in nanoseconds:%" PRIi64 "",
+                     local_qtimer, remote_qtimer, delta);
+        }
+    }
+    return delta;
+}
+
+uint64_t getQTimerFreq()
+{
+#if __aarch64__
+    uint64_t val = 0;
+    asm volatile("mrs %0, cntfrq_el0" : "=r" (val));
+#elif defined (__i386__) || defined (__x86_64__)
+    /* Qtimer not supported in x86 architecture */
+    uint64_t val = 0;
+#else
+    uint32_t val = 0;
+    asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
+#endif
+    return val;
+}
+
+uint64_t getBootTimeMilliSec()
+{
+    struct timespec curTs;
+    clock_gettime(CLOCK_BOOTTIME, &curTs);
+    return (uint64_t)GET_MSEC_FROM_TS(curTs);
+}
+
+// Used for convert position/velocity from GSNS antenna based to VRP based
+void Matrix_MxV(float a[3][3],  float b[3], float c[3]) {
+    int i, j;
+
+    for (i=0; i<3; i++) {
+        c[i] = 0.0f;
+        for (j=0; j<3; j++)
+            c[i] += a[i][j] * b[j];
+    }
+}
+
+// Used for convert position/velocity from GNSS antenna based to VRP based
+void Matrix_Skew(float a[3], float c[3][3]) {
+    c[0][0] = 0.0f;
+    c[0][1] = -a[2];
+    c[0][2] = a[1];
+    c[1][0] = a[2];
+    c[1][1] = 0.0f;
+    c[1][2] = -a[0];
+    c[2][0] = -a[1];
+    c[2][1] = a[0];
+    c[2][2] = 0.0f;
+}
+
+// Used for convert position/velocity from GNSS antenna based to VRP based
+void Euler2Dcm(float euler[3], float dcm[3][3]) {
+    float cr = 0.0, sr = 0.0, cp = 0.0, sp = 0.0, ch = 0.0, sh = 0.0;
+
+    cr = cosf(euler[0]);
+    sr = sinf(euler[0]);
+    cp = cosf(euler[1]);
+    sp = sinf(euler[1]);
+    ch = cosf(euler[2]);
+    sh = sinf(euler[2]);
+
+    dcm[0][0] = cp * ch;
+    dcm[0][1] = (sp*sr*ch) - (cr*sh);
+    dcm[0][2] = (cr*sp*ch) + (sh*sr);
+
+    dcm[1][0] = cp * sh;
+    dcm[1][1] = (sr*sp*sh) + (cr*ch);
+    dcm[1][2] = (cr*sp*sh) - (sr*ch);
+
+    dcm[2][0] = -sp;
+    dcm[2][1] = sr * cp;
+    dcm[2][2] = cr * cp;
+}
+
+// Used for convert position from GSNS based to VRP based
+// The converted position will be stored in the llaInfo parameter.
+#define A6DOF_WGS_A (6378137.0f)
+#define A6DOF_WGS_B (6335439.0f)
+#define A6DOF_WGS_E2 (0.00669437999014f)
+void loc_convert_lla_gnss_to_vrp(double lla[3], float rollPitchYaw[3],
+                                 float leverArm[3]) {
+    LOC_LOGv("lla: %f, %f, %f, lever arm: %f %f %f, "
+             "rollpitchyaw: %f %f %f",
+             lla[0], lla[1], lla[2],
+             leverArm[0], leverArm[1], leverArm[2],
+             rollPitchYaw[0], rollPitchYaw[1], rollPitchYaw[2]);
+
+    float cnb[3][3];
+    memset(cnb, 0, sizeof(cnb));
+    Euler2Dcm(rollPitchYaw, cnb);
+
+    float sl = sin(lla[0]);
+    float cl = cos(lla[0]);
+    float sf = 1.0f / (1.0f - A6DOF_WGS_E2 * sl* sl);
+    float sfr = sqrtf(sf);
+
+    float rn = A6DOF_WGS_B * sf * sfr + lla[2];
+    float re = A6DOF_WGS_A * sfr + lla[2];
+
+    float deltaNEU[3];
+
+    // gps_pos_lla = imu_pos_lla + Cbn*la_b .* [1/geo.Rn; 1/(geo.Re*geo.cL); -1];
+    Matrix_MxV(cnb, leverArm, deltaNEU);
+
+    // NED to lla conversion
+    lla[0] = lla[0] + deltaNEU[0] / rn;
+    lla[1] = lla[1] + deltaNEU[1] / (re * cl);
+    lla[2] = lla[2] + deltaNEU[2];
+}
+
+// Used for convert velocity from GSNS based to VRP based
+// The converted velocity will be stored in the enuVelocity parameter.
+void loc_convert_velocity_gnss_to_vrp(float enuVelocity[3], float rollPitchYaw[3],
+                                      float rollPitchYawRate[3], float leverArm[3]) {
+
+    LOC_LOGv("enu velocity: %f, %f, %f, lever arm: %f %f %f, roll pitch yaw: %f %f %f,"
+             "rollpitchyawRate: %f %f %f",
+             enuVelocity[0], enuVelocity[1], enuVelocity[2],
+             leverArm[0], leverArm[1], leverArm[2],
+             rollPitchYaw[0], rollPitchYaw[1], rollPitchYaw[2],
+             rollPitchYawRate[0], rollPitchYawRate[1], rollPitchYawRate[2]);
+
+    float cnb[3][3];
+    memset(cnb, 0, sizeof(cnb));
+    Euler2Dcm(rollPitchYaw, cnb);
+
+    float skewLA[3][3];
+    memset(skewLA, 0, sizeof(skewLA));
+    Matrix_Skew(leverArm, skewLA);
+
+    float tmp[3];
+    float deltaEnuVelocity[3];
+    memset(tmp, 0, sizeof(tmp));
+    memset(deltaEnuVelocity, 0, sizeof(deltaEnuVelocity));
+    Matrix_MxV(skewLA, rollPitchYawRate, tmp);
+    Matrix_MxV(cnb, tmp, deltaEnuVelocity);
+
+    enuVelocity[0] = enuVelocity[0] - deltaEnuVelocity[0];
+    enuVelocity[1] = enuVelocity[1] - deltaEnuVelocity[1];
+    enuVelocity[2] = enuVelocity[2] - deltaEnuVelocity[2];
+}
diff --git a/gps/utils/loc_misc_utils.h b/gps/utils/loc_misc_utils.h
new file mode 100644
index 0000000..2335e57
--- /dev/null
+++ b/gps/utils/loc_misc_utils.h
@@ -0,0 +1,321 @@
+/* Copyright (c) 2014, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef _LOC_MISC_UTILS_H_
+#define _LOC_MISC_UTILS_H_
+#include <stdint.h>
+#include <ios>
+#include <string>
+#include <sstream>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <stddef.h>
+#include <stdint.h>
+/*===========================================================================
+FUNCTION loc_split_string
+
+DESCRIPTION:
+    This function is used to split a delimiter separated string into
+    sub-strings. This function does not allocate new memory to store the split
+    strings. Instead, it places '\0' in places of delimiters and assings the
+    starting address of the substring within the raw string as the string address
+    The input raw_string no longer remains to be a collection of sub-strings
+    after this function is executed.
+    Please make a copy of the input string before calling this function if
+    necessary
+
+PARAMETERS:
+    char *raw_string: is the original string with delimiter separated substrings
+    char **split_strings_ptr: is the arraw of pointers which will hold the addresses
+                              of individual substrings
+    int max_num_substrings: is the maximum number of substrings that are expected
+                            by the caller. The array of pointers in the above parameter
+                            is usually this long
+    char delimiter: is the delimiter that separates the substrings. Examples: ' ', ';'
+
+DEPENDENCIES
+    N/A
+
+RETURN VALUE
+    int Number of split strings
+
+SIDE EFFECTS
+    The input raw_string no longer remains a delimiter separated single string.
+
+EXAMPLE
+    delimiter = ' ' //space
+    raw_string = "hello new user" //delimiter is space ' '
+    addresses  =  0123456789abcd
+    split_strings_ptr[0] = &raw_string[0]; //split_strings_ptr[0] contains "hello"
+    split_strings_ptr[1] = &raw_string[6]; //split_strings_ptr[1] contains "new"
+    split_strings_ptr[2] = &raw_string[a]; //split_strings_ptr[2] contains "user"
+
+===========================================================================*/
+int loc_util_split_string(char *raw_string, char **split_strings_ptr, int max_num_substrings,
+                     char delimiter);
+
+/*===========================================================================
+FUNCTION trim_space
+
+DESCRIPTION
+   Removes leading and trailing spaces of the string
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   None
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+void loc_util_trim_space(char *org_string);
+
+/*===========================================================================
+FUNCTION dlGetSymFromLib
+
+DESCRIPTION
+   Handy function to get a pointer to a symbol from a library.
+
+   If libHandle is not null, it will be used as the handle to the library. In
+   that case libName wll not be used;
+   libHandle is an in / out parameter.
+   If libHandle is null, libName will be used to dlopen.
+   Either libHandle or libName must not be nullptr.
+   symName must not be null.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   pointer to symName. Could be nullptr if
+       Parameters are incorrect; or
+       libName can not be opened; or
+       symName can not be found.
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+void* dlGetSymFromLib(void*& libHandle, const char* libName, const char* symName);
+
+/*===========================================================================
+FUNCTION getQTimerTickCount
+
+DESCRIPTION
+   This function is used to read the QTimer ticks count. This value is globally maintained and
+   must be the same across all processors on a target.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+    uint64_t QTimer tick count
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+uint64_t getQTimerTickCount();
+
+/*===========================================================================
+FUNCTION getQTimerDeltaNanos
+
+DESCRIPTION
+This function is used to read the the difference in nanoseconds between
+Qtimer on AP side and Qtimer on MP side for dual-SoC architectures such as Kona
+
+DEPENDENCIES
+N/A
+
+RETURN VALUE
+uint64_t QTimer difference in nanoseconds
+
+SIDE EFFECTS
+N/A
+===========================================================================*/
+uint64_t getQTimerDeltaNanos();
+
+/*===========================================================================
+FUNCTION getQTimerFreq
+
+DESCRIPTION
+   This function is used to read the QTimer frequency in hz. This value is globally maintained and
+   must be the same across all processors on a target.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+    uint64_t QTimer frequency
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+uint64_t getQTimerFreq();
+
+/*===========================================================================
+FUNCTION getBootTimeMilliSec
+
+DESCRIPTION
+   This function is used to get boot time in milliseconds.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+    uint64_t boot time in milliseconds
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+uint64_t getBootTimeMilliSec();
+
+#ifdef __cplusplus
+}
+#endif
+
+using std::hex;
+using std::string;
+using std::stringstream;
+
+/*===========================================================================
+FUNCTION to_string_hex
+
+DESCRIPTION
+   This function works similar to std::to_string, but puts only in hex format.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   string, of input val in hex format
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+template <typename T>
+string to_string_hex(T val) {
+    stringstream ss;
+    if (val < 0) {
+        val = -val;
+        ss << "-";
+    }
+    ss << hex << "0x" << val;
+    return ss.str();
+}
+
+/*===========================================================================
+FUNCTION loc_prim_arr_to_string
+
+DESCRIPTION
+   This function puts out primitive array in DEC or EHX format.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+    string, space separated string of values in the input array, either
+            in decimal or hex format, depending on the value of decIfTrue
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+template <typename T>
+static string loc_prim_arr_to_string(T* arr, uint32_t size, bool decIfTrue = true) {
+    stringstream ss;
+    for (uint32_t i = 0; i < size; i++) {
+        ss << (decIfTrue ? to_string(arr[i]) : to_string_hex(arr[i]));
+        if (i != size - 1) {
+            ss << " ";
+        }
+    }
+    return ss.str();
+}
+
+/*===========================================================================
+FUNCTION qTimerTicksToNanos
+
+DESCRIPTION
+    Transform from ticks to nanoseconds, clock is 19.2 MHz
+    so the formula would be qtimer(ns) = (ticks * 1000000000) / 19200000
+    or simplified qtimer(ns) = (ticks * 10000) / 192.
+
+DEPENDENCIES
+    N/A
+
+RETURN VALUE
+    Qtimer value in nanoseconds
+
+SIDE EFFECTS
+    N/A
+===========================================================================*/
+inline uint64_t qTimerTicksToNanos(double qTimer) {
+    return (uint64_t((qTimer * double(10000ull)) / (double)192ull));
+}
+
+/*===========================================================================
+FUNCTION loc_convert_lla_gnss_to_vrp
+
+DESCRIPTION
+   This function converts lat/long/altitude from GNSS antenna based
+   to vehicle reference point based.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+    The converted lat/long/altitude will be stored in the parameter of llaInfo.
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+void loc_convert_lla_gnss_to_vrp(double lla[3], float rollPitchYaw[3],
+                                 float leverArm[3]);
+
+/*===========================================================================
+FUNCTION loc_convert_velocity_gnss_to_vrp
+
+DESCRIPTION
+   This function converts east/north/up velocity from GNSS antenna based
+   to vehicle reference point based.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+    The converted east/north/up velocity will be stored in the parameter of
+    enuVelocity.
+
+SIDE EFFECTS
+   N/A
+===========================================================================*/
+void loc_convert_velocity_gnss_to_vrp(float enuVelocity[3], float rollPitchYaw[3],
+                                      float rollPitchYawRate[3], float leverArm[3]);
+
+#endif //_LOC_MISC_UTILS_H_
diff --git a/gps/utils/loc_nmea.cpp b/gps/utils/loc_nmea.cpp
new file mode 100644
index 0000000..6b5e60e
--- /dev/null
+++ b/gps/utils/loc_nmea.cpp
@@ -0,0 +1,2347 @@
+/* Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "LocSvc_nmea"
+#include <loc_nmea.h>
+#include <math.h>
+#include <log_util.h>
+#include <loc_pla.h>
+#include <loc_cfg.h>
+
+#define GLONASS_SV_ID_OFFSET 64
+#define SBAS_SV_ID_OFFSET    (87)
+#define QZSS_SV_ID_OFFSET    (192)
+#define BDS_SV_ID_OFFSET     (200)
+#define GALILEO_SV_ID_OFFSET (300)
+#define NAVIC_SV_ID_OFFSET   (400)
+#define MAX_SV_COUNT_SUPPORTED_IN_ONE_CONSTELLATION  64
+#define MAX_SATELLITES_IN_USE 12
+#define MSEC_IN_ONE_WEEK      604800000ULL
+#define UTC_GPS_OFFSET_MSECS  315964800000ULL
+#define MAX_TAG_BLOCK_GROUP_CODE  (99999)
+
+// GNSS system id according to NMEA spec
+#define SYSTEM_ID_GPS          1
+#define SYSTEM_ID_GLONASS      2
+#define SYSTEM_ID_GALILEO      3
+#define SYSTEM_ID_BDS          4
+#define SYSTEM_ID_QZSS         5
+#define SYSTEM_ID_NAVIC        6
+
+//GNSS signal id according to NMEA spec
+#define SIGNAL_ID_ALL_SIGNALS  0
+#define SIGNAL_ID_GPS_L1CA     1
+#define SIGNAL_ID_GPS_L1P      2
+#define SIGNAL_ID_GPS_L1M      3
+#define SIGNAL_ID_GPS_L2P      4
+#define SIGNAL_ID_GPS_L2CM     5
+#define SIGNAL_ID_GPS_L2CL     6
+#define SIGNAL_ID_GPS_L5I      7
+#define SIGNAL_ID_GPS_L5Q      8
+
+
+#define SIGNAL_ID_GLO_G1CA     1
+#define SIGNAL_ID_GLO_G1P      2
+#define SIGNAL_ID_GLO_G2CA     3
+#define SIGNAL_ID_GLO_G2P      4
+
+
+#define SIGNAL_ID_GAL_E5A      1
+#define SIGNAL_ID_GAL_E5B      2
+#define SIGNAL_ID_GAL_E5AB     3
+#define SIGNAL_ID_GAL_E6A      4
+#define SIGNAL_ID_GAL_E6BC     5
+#define SIGNAL_ID_GAL_L1A      6
+#define SIGNAL_ID_GAL_L1BC     7
+
+#define SIGNAL_ID_BDS_B1I      1
+#define SIGNAL_ID_BDS_B1Q      2
+#define SIGNAL_ID_BDS_B1C      3
+#define SIGNAL_ID_BDS_B1A      4
+#define SIGNAL_ID_BDS_B2A      5
+#define SIGNAL_ID_BDS_B2B      6
+#define SIGNAL_ID_BDS_B2AB     7
+#define SIGNAL_ID_BDS_B3I      8
+#define SIGNAL_ID_BDS_B3Q      9
+#define SIGNAL_ID_BDS_B3A      0xA
+#define SIGNAL_ID_BDS_B2I      0xB
+#define SIGNAL_ID_BDS_B2Q      0xC
+
+#define SIGNAL_ID_QZSS_L1CA    1
+#define SIGNAL_ID_QZSS_L1CD    2
+#define SIGNAL_ID_QZSS_L1CP    3
+#define SIGNAL_ID_QZSS_LIS     4
+#define SIGNAL_ID_QZSS_L2CM    5
+#define SIGNAL_ID_QZSS_L2CL    6
+#define SIGNAL_ID_QZSS_L5I     7
+#define SIGNAL_ID_QZSS_L5Q     8
+#define SIGNAL_ID_QZSS_L6D     9
+#define SIGNAL_ID_QZSS_L6E     0xA
+
+#define SIGNAL_ID_NAVIC_L5SPS  1
+#define SIGNAL_ID_NAVIC_SSPS   2
+#define SIGNAL_ID_NAVIC_L5RS   3
+#define SIGNAL_ID_NAVIC_SRS    4
+#define SIGNAL_ID_NAVIC_L1SPS  5
+
+
+typedef struct loc_nmea_sv_meta_s
+{
+    char talker[3];
+    uint32_t svTypeMask;
+    uint64_t mask;
+    uint32_t svCount;
+    uint32_t totalSvUsedCount;
+    uint32_t svIdOffset;
+    uint32_t signalId;
+    uint32_t systemId;
+} loc_nmea_sv_meta;
+
+typedef struct loc_sv_cache_info_s
+{
+    uint64_t gps_used_mask;
+    uint64_t glo_used_mask;
+    uint64_t gal_used_mask;
+    uint64_t qzss_used_mask;
+    uint64_t bds_used_mask;
+    uint64_t navic_used_mask;
+    uint32_t gps_l1_count;
+    uint32_t gps_l2_count;
+    uint32_t gps_l5_count;
+    uint32_t glo_g1_count;
+    uint32_t glo_g2_count;
+    uint32_t gal_e1_count;
+    uint32_t gal_e5_count;
+    uint32_t gal_e5b_count;
+    uint32_t qzss_l1_count;
+    uint32_t qzss_l2_count;
+    uint32_t qzss_l5_count;
+    uint32_t bds_b1i_count;
+    uint32_t bds_b1c_count;
+    uint32_t bds_b2_count;
+    uint32_t navic_l5_count;
+    float hdop;
+    float pdop;
+    float vdop;
+} loc_sv_cache_info;
+
+/*===========================================================================
+FUNCTION    convert_Lla_to_Ecef
+
+DESCRIPTION
+   Convert LLA to ECEF
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   NONE
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static void convert_Lla_to_Ecef(const LocLla& plla, LocEcef& pecef)
+{
+    double r;
+
+    r = MAJA / sqrt(1.0 - ESQR * sin(plla.lat) * sin(plla.lat));
+    pecef.X = (r + plla.alt) * cos(plla.lat) * cos(plla.lon);
+    pecef.Y = (r + plla.alt) * cos(plla.lat) * sin(plla.lon);
+    pecef.Z = (r * OMES + plla.alt) * sin(plla.lat);
+}
+
+/*===========================================================================
+FUNCTION    convert_WGS84_to_PZ90
+
+DESCRIPTION
+   Convert datum from WGS84 to PZ90
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   NONE
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static void convert_WGS84_to_PZ90(const LocEcef& pWGS84, LocEcef& pPZ90)
+{
+    double deltaX     = DatumConstFromWGS84[0];
+    double deltaY     = DatumConstFromWGS84[1];
+    double deltaZ     = DatumConstFromWGS84[2];
+    double deltaScale = DatumConstFromWGS84[3];
+    double rotX       = DatumConstFromWGS84[4];
+    double rotY       = DatumConstFromWGS84[5];
+    double rotZ       = DatumConstFromWGS84[6];
+
+    pPZ90.X = deltaX + deltaScale * (pWGS84.X + rotZ * pWGS84.Y - rotY * pWGS84.Z);
+    pPZ90.Y = deltaY + deltaScale * (pWGS84.Y - rotZ * pWGS84.X + rotX * pWGS84.Z);
+    pPZ90.Z = deltaZ + deltaScale * (pWGS84.Z + rotY * pWGS84.X - rotX * pWGS84.Y);
+}
+
+/*===========================================================================
+FUNCTION    convert_Ecef_to_Lla
+
+DESCRIPTION
+   Convert ECEF to LLA
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   NONE
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static void convert_Ecef_to_Lla(const LocEcef& pecef, LocLla& plla)
+{
+    double p, r;
+    double EcefA = C_PZ90A;
+    double EcefB = C_PZ90B;
+    double Ecef1Mf;
+    double EcefE2;
+    double Mu;
+    double Smu;
+    double Cmu;
+    double Phi;
+    double Sphi;
+    double N;
+
+    p = sqrt(pecef.X * pecef.X + pecef.Y * pecef.Y);
+    r = sqrt(p * p + pecef.Z * pecef.Z);
+    if (r < 1.0) {
+        plla.lat = 1.0;
+        plla.lon = 1.0;
+        plla.alt = 1.0;
+    }
+    Ecef1Mf = 1.0 - (EcefA - EcefB) / EcefA;
+    EcefE2 = 1.0 - (EcefB * EcefB) / (EcefA * EcefA);
+    if (p > 1.0) {
+        Mu = atan2(pecef.Z * (Ecef1Mf + EcefE2 * EcefA / r), p);
+    } else {
+        if (pecef.Z > 0.0) {
+            Mu = M_PI / 2.0;
+        } else {
+            Mu = -M_PI / 2.0;
+        }
+    }
+    Smu = sin(Mu);
+    Cmu = cos(Mu);
+    Phi = atan2(pecef.Z * Ecef1Mf + EcefE2 * EcefA * Smu * Smu * Smu,
+                Ecef1Mf * (p - EcefE2 * EcefA * Cmu * Cmu * Cmu));
+    Sphi = sin(Phi);
+    N = EcefA / sqrt(1.0 - EcefE2 * Sphi * Sphi);
+    plla.alt = p * cos(Phi) + pecef.Z * Sphi - EcefA * EcefA/N;
+    plla.lat = Phi;
+    if ( p > 1.0) {
+        plla.lon = atan2(pecef.Y, pecef.X);
+    } else {
+        plla.lon = 0.0;
+    }
+}
+
+/*===========================================================================
+FUNCTION    convert_signalType_to_signalId
+
+DESCRIPTION
+   convert signalType to signal ID
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   value of signal ID
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static uint32_t convert_signalType_to_signalId(GnssSignalTypeMask signalType)
+{
+    uint32_t signalId = SIGNAL_ID_ALL_SIGNALS;
+
+    switch (signalType) {
+        case GNSS_SIGNAL_GPS_L1CA:
+        case GNSS_SIGNAL_SBAS_L1:
+            signalId = SIGNAL_ID_GPS_L1CA;
+            break;
+        case GNSS_SIGNAL_GPS_L2:
+            signalId = SIGNAL_ID_GPS_L2CL;
+            break;
+        case GNSS_SIGNAL_GPS_L5:
+            signalId = SIGNAL_ID_GPS_L5Q;
+            break;
+        case GNSS_SIGNAL_GLONASS_G1:
+            signalId = SIGNAL_ID_GLO_G1CA;
+            break;
+        case GNSS_SIGNAL_GLONASS_G2:
+            signalId = SIGNAL_ID_GLO_G2CA;
+            break;
+        case GNSS_SIGNAL_GALILEO_E1:
+            signalId = SIGNAL_ID_GAL_L1BC;
+            break;
+        case GNSS_SIGNAL_GALILEO_E5A:
+            signalId = SIGNAL_ID_GAL_E5A;
+            break;
+        case GNSS_SIGNAL_GALILEO_E5B:
+            signalId = SIGNAL_ID_GAL_E5B;
+            break;
+        case GNSS_SIGNAL_QZSS_L1CA:
+            signalId = SIGNAL_ID_QZSS_L1CA;
+            break;
+        case GNSS_SIGNAL_QZSS_L2:
+            signalId = SIGNAL_ID_QZSS_L2CL;
+            break;
+        case GNSS_SIGNAL_QZSS_L5:
+            signalId = SIGNAL_ID_QZSS_L5Q;
+            break;
+        case GNSS_SIGNAL_BEIDOU_B1I:
+            signalId = SIGNAL_ID_BDS_B1I;
+            break;
+        case GNSS_SIGNAL_BEIDOU_B1C:
+            signalId = SIGNAL_ID_BDS_B1C;
+            break;
+        case GNSS_SIGNAL_BEIDOU_B2I:
+            signalId = SIGNAL_ID_BDS_B2I;
+            break;
+        case GNSS_SIGNAL_BEIDOU_B2AI:
+        case GNSS_SIGNAL_BEIDOU_B2AQ:
+            signalId = SIGNAL_ID_BDS_B2A;
+            break;
+        case GNSS_SIGNAL_NAVIC_L5:
+            signalId = SIGNAL_ID_NAVIC_L5SPS;
+            break;
+        default:
+            signalId = SIGNAL_ID_ALL_SIGNALS;
+    }
+
+    return signalId;
+
+}
+
+/*===========================================================================
+FUNCTION    get_sv_count_from_mask
+
+DESCRIPTION
+   get the sv count from bit mask
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   value of sv count
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static uint32_t get_sv_count_from_mask(uint64_t svMask, int totalSvCount)
+{
+    int index = 0;
+    uint32_t svCount = 0;
+
+    if(totalSvCount > MAX_SV_COUNT_SUPPORTED_IN_ONE_CONSTELLATION) {
+        LOC_LOGE("total SV count in this constellation %d exceeded limit %d",
+                 totalSvCount, MAX_SV_COUNT_SUPPORTED_IN_ONE_CONSTELLATION);
+    }
+    for(index = 0; index < totalSvCount; index++) {
+        if(svMask & 0x1)
+            svCount += 1;
+        svMask >>= 1;
+    }
+    return svCount;
+}
+
+/*===========================================================================
+FUNCTION    loc_nmea_sv_meta_init
+
+DESCRIPTION
+   Init loc_nmea_sv_meta passed in
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   Pointer to loc_nmea_sv_meta
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static loc_nmea_sv_meta* loc_nmea_sv_meta_init(loc_nmea_sv_meta& sv_meta,
+                                               loc_sv_cache_info& sv_cache_info,
+                                               GnssSvType svType,
+                                               GnssSignalTypeMask signalType,
+                                               bool needCombine)
+{
+    memset(&sv_meta, 0, sizeof(sv_meta));
+    sv_meta.svTypeMask = (1 << svType);
+
+    switch (svType)
+    {
+        case GNSS_SV_TYPE_GPS:
+            sv_meta.talker[0] = 'G';
+            sv_meta.talker[1] = 'P';
+            sv_meta.mask = sv_cache_info.gps_used_mask;
+            sv_meta.systemId = SYSTEM_ID_GPS;
+            sv_meta.svTypeMask |= (1 << GNSS_SV_TYPE_SBAS);
+            switch (signalType) {
+                case GNSS_SIGNAL_GPS_L1CA:
+                    sv_meta.svCount = sv_cache_info.gps_l1_count;
+                    break;
+                case GNSS_SIGNAL_GPS_L5:
+                    sv_meta.svCount = sv_cache_info.gps_l5_count;
+                    break;
+                case GNSS_SIGNAL_GPS_L2:
+                    sv_meta.svCount = sv_cache_info.gps_l2_count;
+                    break;
+            }
+            break;
+        case GNSS_SV_TYPE_GLONASS:
+            sv_meta.talker[0] = 'G';
+            sv_meta.talker[1] = 'L';
+            sv_meta.mask = sv_cache_info.glo_used_mask;
+            // GLONASS SV ids are from 65-96
+            sv_meta.svIdOffset = GLONASS_SV_ID_OFFSET;
+            sv_meta.systemId = SYSTEM_ID_GLONASS;
+            switch (signalType) {
+                case GNSS_SIGNAL_GLONASS_G1:
+                    sv_meta.svCount = sv_cache_info.glo_g1_count;
+                    break;
+                case GNSS_SIGNAL_GLONASS_G2:
+                    sv_meta.svCount = sv_cache_info.glo_g2_count;
+                    break;
+            }
+            break;
+        case GNSS_SV_TYPE_GALILEO:
+            sv_meta.talker[0] = 'G';
+            sv_meta.talker[1] = 'A';
+            sv_meta.mask = sv_cache_info.gal_used_mask;
+            // GALILEO SV ids are from 301-336, So keep svIdOffset 300
+            sv_meta.svIdOffset = GALILEO_SV_ID_OFFSET;
+            sv_meta.systemId = SYSTEM_ID_GALILEO;
+            switch (signalType) {
+                case GNSS_SIGNAL_GALILEO_E1:
+                    sv_meta.svCount = sv_cache_info.gal_e1_count;
+                    break;
+                case GNSS_SIGNAL_GALILEO_E5A:
+                    sv_meta.svCount = sv_cache_info.gal_e5_count;
+                    break;
+                case GNSS_SIGNAL_GALILEO_E5B:
+                    sv_meta.svCount = sv_cache_info.gal_e5b_count;
+                    break;
+            }
+            break;
+        case GNSS_SV_TYPE_QZSS:
+            sv_meta.talker[0] = 'G';
+            sv_meta.talker[1] = 'Q';
+            sv_meta.mask = sv_cache_info.qzss_used_mask;
+            // QZSS SV ids are from 193-199. So keep svIdOffset 192
+            sv_meta.svIdOffset = QZSS_SV_ID_OFFSET;
+            sv_meta.systemId = SYSTEM_ID_QZSS;
+            switch (signalType) {
+                case GNSS_SIGNAL_QZSS_L1CA:
+                    sv_meta.svCount = sv_cache_info.qzss_l1_count;
+                    break;
+                case GNSS_SIGNAL_QZSS_L2:
+                    sv_meta.svCount = sv_cache_info.qzss_l2_count;
+                    break;
+                case GNSS_SIGNAL_QZSS_L5:
+                    sv_meta.svCount = sv_cache_info.qzss_l5_count;
+                    break;
+            }
+            break;
+        case GNSS_SV_TYPE_BEIDOU:
+            sv_meta.talker[0] = 'G';
+            sv_meta.talker[1] = 'B';
+            sv_meta.mask = sv_cache_info.bds_used_mask;
+            // BDS SV ids are from 201-237. So keep svIdOffset 200
+            sv_meta.svIdOffset = BDS_SV_ID_OFFSET;
+            sv_meta.systemId = SYSTEM_ID_BDS;
+            switch (signalType) {
+                case GNSS_SIGNAL_BEIDOU_B1I:
+                    sv_meta.svCount = sv_cache_info.bds_b1i_count;
+                    break;
+                case GNSS_SIGNAL_BEIDOU_B1C:
+                    sv_meta.svCount = sv_cache_info.bds_b1c_count;
+                    break;
+                case GNSS_SIGNAL_BEIDOU_B2AI:
+                    sv_meta.svCount = sv_cache_info.bds_b2_count;
+                    break;
+            }
+            break;
+        case GNSS_SV_TYPE_NAVIC:
+            sv_meta.talker[0] = 'G';
+            sv_meta.talker[1] = 'I';
+            sv_meta.mask = sv_cache_info.navic_used_mask;
+            // NAVIC SV ids are from 401-414. So keep svIdOffset 400
+            sv_meta.svIdOffset = NAVIC_SV_ID_OFFSET;
+            sv_meta.systemId = SYSTEM_ID_NAVIC;
+            switch (signalType) {
+                case GNSS_SIGNAL_NAVIC_L5:
+                    sv_meta.svCount = sv_cache_info.navic_l5_count;
+                    break;
+            }
+            break;
+        default:
+            LOC_LOGE("NMEA Error unknow constellation type: %d", svType);
+            return NULL;
+    }
+    sv_meta.signalId = convert_signalType_to_signalId(signalType);
+    sv_meta.totalSvUsedCount =
+            get_sv_count_from_mask(sv_cache_info.gps_used_mask,
+                    GPS_SV_PRN_MAX - GPS_SV_PRN_MIN + 1) +
+            get_sv_count_from_mask(sv_cache_info.glo_used_mask,
+                    GLO_SV_PRN_MAX - GLO_SV_PRN_MIN + 1) +
+            get_sv_count_from_mask(sv_cache_info.gal_used_mask,
+                    GAL_SV_PRN_MAX - GAL_SV_PRN_MIN + 1) +
+            get_sv_count_from_mask(sv_cache_info.qzss_used_mask,
+                    QZSS_SV_PRN_MAX - QZSS_SV_PRN_MIN + 1) +
+            get_sv_count_from_mask(sv_cache_info.bds_used_mask,
+                    BDS_SV_PRN_MAX - BDS_SV_PRN_MIN + 1) +
+            get_sv_count_from_mask(sv_cache_info.navic_used_mask,
+                    NAVIC_SV_PRN_MAX - NAVIC_SV_PRN_MIN + 1);
+    if (needCombine &&
+                (sv_cache_info.gps_used_mask ? 1 : 0) +
+                (sv_cache_info.glo_used_mask ? 1 : 0) +
+                (sv_cache_info.gal_used_mask ? 1 : 0) +
+                (sv_cache_info.qzss_used_mask ? 1 : 0) +
+                (sv_cache_info.bds_used_mask ? 1 : 0) +
+                (sv_cache_info.navic_used_mask ? 1 : 0) > 1)
+    {
+        // If GPS, GLONASS, Galileo, QZSS, BDS etc. are combined
+        // to obtain the reported position solution,
+        // talker shall be set to GN, to indicate that
+        // the satellites are used in a combined solution
+        sv_meta.talker[0] = 'G';
+        sv_meta.talker[1] = 'N';
+    }
+    return &sv_meta;
+}
+
+/*===========================================================================
+FUNCTION    loc_nmea_put_checksum
+
+DESCRIPTION
+   Generate NMEA sentences generated based on position report
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   Total length of the nmea sentence
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static int loc_nmea_put_checksum(char *pNmea, int maxSize, bool isTagBlock)
+{
+    uint8_t checksum = 0;
+    int length = 0;
+    int checksumLength = 0;
+    if(NULL == pNmea)
+        return 0;
+
+    pNmea++; //skip the $ or / for Tag Block
+    while (*pNmea != '\0')
+    {
+        checksum ^= *pNmea++;
+        length++;
+    }
+
+    if (isTagBlock) {
+        // length now contains tag block sentence string length not including / sign.
+        checksumLength = snprintf(pNmea, (maxSize-length-1), "*%02X\\", checksum);
+    } else {
+        // length now contains nmea sentence string length not including $ sign.
+        checksumLength = snprintf(pNmea, (maxSize-length-1), "*%02X\r\n", checksum);
+    }
+    // total length of nmea sentence is length of nmea sentence inc $ sign plus
+    // length of checksum (+1 is to cover the $ character in the length).
+    return (length + checksumLength + 1);
+}
+
+/*===========================================================================
+FUNCTION    loc_nmea_generate_GSA
+
+DESCRIPTION
+   Generate NMEA GSA sentences generated based on position report
+   Currently below sentences are generated:
+   - $GPGSA : GPS DOP and active SVs
+   - $GLGSA : GLONASS DOP and active SVs
+   - $GAGSA : GALILEO DOP and active SVs
+   - $GNGSA : GNSS DOP and active SVs
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   Number of SVs used
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static uint32_t loc_nmea_generate_GSA(const GpsLocationExtended &locationExtended,
+                              char* sentence,
+                              int bufSize,
+                              loc_nmea_sv_meta* sv_meta_p,
+                              std::vector<std::string> &nmeaArraystr,
+                              bool isTagBlockGroupingEnabled)
+{
+    if (!sentence || bufSize <= 0 || !sv_meta_p)
+    {
+        LOC_LOGE("NMEA Error invalid arguments.");
+        return 0;
+    }
+
+    char* pMarker = sentence;
+    int lengthRemaining = bufSize;
+    int length = 0;
+    int lengthTagBlock = 0;
+
+    uint32_t svUsedCount = 0;
+    uint32_t svUsedList[64] = {0};
+    uint32_t sentenceCount = 0;
+    uint32_t sentenceNumber = 1;
+    size_t svNumber = 1;
+    static uint32_t code = 1;
+
+    char fixType = '\0';
+
+    const char* talker = sv_meta_p->talker;
+    uint32_t svIdOffset = sv_meta_p->svIdOffset;
+    uint64_t mask = sv_meta_p->mask;
+
+    if (!(sv_meta_p->svTypeMask & (1 << GNSS_SV_TYPE_GLONASS))) {
+        svIdOffset = 0;
+    }
+
+    for (uint8_t i = 1; mask > 0 && svUsedCount < 64; i++)
+    {
+        if (mask & 1)
+            svUsedList[svUsedCount++] = i + svIdOffset;
+        mask = mask >> 1;
+    }
+
+    if (svUsedCount == 0) {
+        return 0;
+    } else {
+        sentenceNumber = 1;
+        sentenceCount = svUsedCount / 12 + (svUsedCount % 12 != 0);
+        svNumber = 1;
+    }
+    while (sentenceNumber <= sentenceCount) {
+        pMarker = sentence;
+        lengthRemaining = bufSize;
+        if (svUsedCount > 12 && isTagBlockGroupingEnabled) {
+            lengthTagBlock = snprintf(pMarker, lengthRemaining, "\\g:%d-%d-%d", sentenceNumber,
+                     sentenceCount, code);
+            if (MAX_TAG_BLOCK_GROUP_CODE == code) {
+                code = 1;
+            }
+            lengthTagBlock = loc_nmea_put_checksum(sentence, bufSize, true);
+            pMarker += lengthTagBlock;
+            lengthRemaining -= lengthTagBlock;
+        }
+        if (sv_meta_p->totalSvUsedCount == 0)
+            fixType = '1'; // no fix
+        else if (sv_meta_p->totalSvUsedCount <= 3)
+            fixType = '2'; // 2D fix
+        else
+            fixType = '3'; // 3D fix
+
+        // Start printing the sentence
+        // Format: $--GSA,a,x,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,p.p,h.h,v.v,s*cc
+        // a : Mode  : A : Automatic, allowed to automatically switch 2D/3D
+        // x : Fixtype : 1 (no fix), 2 (2D fix), 3 (3D fix)
+        // xx : 12 SV ID
+        // p.p : Position DOP (Dilution of Precision)
+        // h.h : Horizontal DOP
+        // v.v : Vertical DOP
+        // s : GNSS System Id
+        // cc : Checksum value
+        length = snprintf(pMarker, lengthRemaining, "$%sGSA,A,%c,", talker, fixType);
+        if (length < 0 || length >= lengthRemaining) {
+            LOC_LOGE("NMEA Error in string formatting");
+            return 0;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        // Add 12 satellite IDs
+        for (uint8_t i = 0; i < 12; i++, svNumber++)
+        {
+            if (svNumber <= svUsedCount)
+                length = snprintf(pMarker, lengthRemaining, "%02d,", svUsedList[svNumber - 1]);
+            else
+                length = snprintf(pMarker, lengthRemaining, ",");
+
+            if (length < 0 || length >= lengthRemaining) {
+                LOC_LOGE("NMEA Error in string formatting");
+                return 0;
+            }
+            pMarker += length;
+            lengthRemaining -= length;
+        }
+
+        // Add the position/horizontal/vertical DOP values
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
+        {
+            length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f,",
+                    locationExtended.pdop,
+                    locationExtended.hdop,
+                    locationExtended.vdop);
+        }
+        else
+        {   // no dop
+            length = snprintf(pMarker, lengthRemaining, ",,,");
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        // system id
+        length = snprintf(pMarker, lengthRemaining, "%d", sv_meta_p->systemId);
+        pMarker += length;
+        lengthRemaining -= length;
+
+        /* Sentence is ready, add checksum and broadcast */
+        length = loc_nmea_put_checksum(sentence + lengthTagBlock, bufSize - lengthTagBlock, false);
+        nmeaArraystr.push_back(sentence);
+        sentenceNumber++;
+        if (!isTagBlockGroupingEnabled) {
+            break;
+        }
+    }
+    if (svUsedCount > 12 && isTagBlockGroupingEnabled) {
+        code++;
+    }
+    return svUsedCount;
+}
+
+/*===========================================================================
+FUNCTION    loc_nmea_generate_GSV
+
+DESCRIPTION
+   Generate NMEA GSV sentences generated based on sv report
+   Currently below sentences are generated:
+   - $GPGSV: GPS Satellites in View
+   - $GLGSV: GLONASS Satellites in View
+   - $GAGSV: GALILEO Satellites in View
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   NONE
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static void loc_nmea_generate_GSV(const GnssSvNotification &svNotify,
+                              char* sentence,
+                              int bufSize,
+                              loc_nmea_sv_meta* sv_meta_p,
+                              std::vector<std::string> &nmeaArraystr)
+{
+    if (!sentence || bufSize <= 0)
+    {
+        LOC_LOGE("NMEA Error invalid argument.");
+        return;
+    }
+
+    char* pMarker = sentence;
+    int lengthRemaining = bufSize;
+    int length = 0;
+    int sentenceCount = 0;
+    int sentenceNumber = 1;
+    size_t svNumber = 1;
+
+    const char* talker = sv_meta_p->talker;
+    uint32_t svIdOffset = sv_meta_p->svIdOffset;
+    int svCount = sv_meta_p->svCount;
+    if (svCount <= 0)
+    {
+        LOC_LOGV("No SV in view for talker ID:%s, signal ID:%X", talker, sv_meta_p->signalId);
+        return;
+    }
+
+    if ((1 << GNSS_SV_TYPE_GLONASS) & sv_meta_p->svTypeMask) {
+        svIdOffset = 0;
+    }
+    svNumber = 1;
+    sentenceNumber = 1;
+    sentenceCount = svCount / 4 + (svCount % 4 != 0);
+
+    while (sentenceNumber <= sentenceCount)
+    {
+        pMarker = sentence;
+        lengthRemaining = bufSize;
+
+        length = snprintf(pMarker, lengthRemaining, "$%sGSV,%d,%d,%02d",
+                talker, sentenceCount, sentenceNumber, svCount);
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        for (int i=0; (svNumber <= svNotify.count) && (i < 4);  svNumber++)
+        {
+            GnssSignalTypeMask signalType = svNotify.gnssSvs[svNumber-1].gnssSignalTypeMask;
+            if (0 == signalType) {
+                // If no signal type in report, it means default L1,G1,E1,B1I
+                switch (svNotify.gnssSvs[svNumber - 1].type)
+                {
+                    case GNSS_SV_TYPE_GPS:
+                        signalType = GNSS_SIGNAL_GPS_L1CA;
+                        break;
+                    case GNSS_SV_TYPE_GLONASS:
+                        signalType = GNSS_SIGNAL_GLONASS_G1;
+                        break;
+                    case GNSS_SV_TYPE_GALILEO:
+                        signalType = GNSS_SIGNAL_GALILEO_E1;
+                        break;
+                    case GNSS_SV_TYPE_QZSS:
+                        signalType = GNSS_SIGNAL_QZSS_L1CA;
+                        break;
+                    case GNSS_SV_TYPE_BEIDOU:
+                        signalType = GNSS_SIGNAL_BEIDOU_B1I;
+                        break;
+                    case GNSS_SV_TYPE_SBAS:
+                        signalType = GNSS_SIGNAL_SBAS_L1;
+                        break;
+                    case GNSS_SV_TYPE_NAVIC:
+                        signalType = GNSS_SIGNAL_NAVIC_L5;
+                        break;
+                    default:
+                        LOC_LOGE("NMEA Error unknow constellation type: %d",
+                                svNotify.gnssSvs[svNumber - 1].type);
+                        continue;
+                }
+            }
+
+            if ((sv_meta_p->svTypeMask & (1 << svNotify.gnssSvs[svNumber - 1].type)) &&
+                    sv_meta_p->signalId == convert_signalType_to_signalId(signalType))
+            {
+                if (GNSS_SV_TYPE_SBAS == svNotify.gnssSvs[svNumber - 1].type) {
+                    svIdOffset = SBAS_SV_ID_OFFSET;
+                }
+                if (GNSS_SV_TYPE_GLONASS == svNotify.gnssSvs[svNumber - 1].type &&
+                    GLO_SV_PRN_SLOT_UNKNOWN == svNotify.gnssSvs[svNumber - 1].svId) {
+                    length = snprintf(pMarker, lengthRemaining, ",,%02d,%03d,",
+                        (int)(0.5 + svNotify.gnssSvs[svNumber - 1].elevation), //float to int
+                        (int)(0.5 + svNotify.gnssSvs[svNumber - 1].azimuth)); //float to int
+                } else {
+                    length = snprintf(pMarker, lengthRemaining, ",%02d,%02d,%03d,",
+                        svNotify.gnssSvs[svNumber - 1].svId - svIdOffset,
+                        (int)(0.5 + svNotify.gnssSvs[svNumber - 1].elevation), //float to int
+                        (int)(0.5 + svNotify.gnssSvs[svNumber - 1].azimuth)); //float to int
+                }
+                if (length < 0 || length >= lengthRemaining)
+                {
+                    LOC_LOGE("NMEA Error in string formatting");
+                    return;
+                }
+                pMarker += length;
+                lengthRemaining -= length;
+
+                if (svNotify.gnssSvs[svNumber - 1].cN0Dbhz > 0)
+                {
+                    length = snprintf(pMarker, lengthRemaining,"%02d",
+                            (int)(0.5 + svNotify.gnssSvs[svNumber - 1].cN0Dbhz)); //float to int
+
+                    if (length < 0 || length >= lengthRemaining)
+                    {
+                        LOC_LOGE("NMEA Error in string formatting");
+                        return;
+                    }
+                    pMarker += length;
+                    lengthRemaining -= length;
+                }
+
+                i++;
+            }
+
+        }
+
+        // append signalId
+        length = snprintf(pMarker, lengthRemaining,",%X",sv_meta_p->signalId);
+        pMarker += length;
+        lengthRemaining -= length;
+
+        length = loc_nmea_put_checksum(sentence, bufSize, false);
+        nmeaArraystr.push_back(sentence);
+        sentenceNumber++;
+
+    }  //while
+}
+
+/*===========================================================================
+FUNCTION    loc_nmea_generate_DTM
+
+DESCRIPTION
+   Generate NMEA DTM sentences generated based on position report
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   NONE
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static void loc_nmea_generate_DTM(const LocLla &ref_lla,
+                                  const LocLla &local_lla,
+                                  char *talker,
+                                  char *sentence,
+                                  int bufSize)
+{
+    char* pMarker = sentence;
+    int lengthRemaining = bufSize;
+    int length = 0;
+    int datum_type;
+    char ref_datum[4] = {0};
+    char local_datum[4] = {0};
+    double lla_offset[3] = {0};
+    char latHem, longHem;
+    double latMins, longMins;
+
+
+
+    datum_type = loc_get_datum_type();
+    switch (datum_type) {
+        case LOC_GNSS_DATUM_WGS84:
+            ref_datum[0] = 'W';
+            ref_datum[1] = '8';
+            ref_datum[2] = '4';
+            local_datum[0] = 'P';
+            local_datum[1] = '9';
+            local_datum[2] = '0';
+            break;
+        case LOC_GNSS_DATUM_PZ90:
+            ref_datum[0] = 'P';
+            ref_datum[1] = '9';
+            ref_datum[2] = '0';
+            local_datum[0] = 'W';
+            local_datum[1] = '8';
+            local_datum[2] = '4';
+            break;
+        default:
+            break;
+    }
+    length = snprintf(pMarker , lengthRemaining , "$%sDTM,%s,," , talker, local_datum);
+    if (length < 0 || length >= lengthRemaining) {
+        LOC_LOGE("NMEA Error in string formatting");
+        return;
+    }
+    pMarker += length;
+    lengthRemaining -= length;
+
+    lla_offset[0] = local_lla.lat - ref_lla.lat;
+    lla_offset[1] = fmod(local_lla.lon - ref_lla.lon, 360.0);
+    if (lla_offset[1] < -180.0) {
+        lla_offset[1] += 360.0;
+    } else if ( lla_offset[1] > 180.0) {
+        lla_offset[1] -= 360.0;
+    }
+    lla_offset[2] = local_lla.alt - ref_lla.alt;
+    if (lla_offset[0] > 0.0) {
+        latHem = 'N';
+    } else {
+        latHem = 'S';
+        lla_offset[0] *= -1.0;
+    }
+    latMins = fmod(lla_offset[0] * 60.0, 60.0);
+    if (lla_offset[1] < 0.0) {
+        longHem = 'W';
+        lla_offset[1] *= -1.0;
+    }else {
+        longHem = 'E';
+    }
+    longMins = fmod(lla_offset[1] * 60.0, 60.0);
+    length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,%.3lf,",
+                     (uint8_t)floor(lla_offset[0]), latMins, latHem,
+                     (uint8_t)floor(lla_offset[1]), longMins, longHem, lla_offset[2]);
+    if (length < 0 || length >= lengthRemaining) {
+        LOC_LOGE("NMEA Error in string formatting");
+        return;
+    }
+    pMarker += length;
+    lengthRemaining -= length;
+    length = snprintf(pMarker , lengthRemaining , "%s" , ref_datum);
+    if (length < 0 || length >= lengthRemaining) {
+        LOC_LOGE("NMEA Error in string formatting");
+        return;
+    }
+    pMarker += length;
+    lengthRemaining -= length;
+
+    length = loc_nmea_put_checksum(sentence, bufSize, false);
+}
+
+/*===========================================================================
+FUNCTION    get_utctime_with_leapsecond_transition
+
+DESCRIPTION
+   This function returns true if the position report is generated during
+   leap second transition period. If not, then the utc timestamp returned
+   will be set to the timestamp in the position report. If it is,
+   then the utc timestamp returned will need to take into account
+   of the leap second transition so that proper calendar year/month/date
+   can be calculated from the returned utc timestamp.
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   true: position report is generated in leap second transition period.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static bool get_utctime_with_leapsecond_transition(
+        const UlpLocation &location,
+        const GpsLocationExtended &locationExtended,
+        const LocationSystemInfo &systemInfo,
+        LocGpsUtcTime &utcPosTimestamp)
+{
+    bool inTransition = false;
+
+    // position report is not generated during leap second transition,
+    // we can use the UTC timestamp from position report as is
+    utcPosTimestamp = location.gpsLocation.timestamp;
+
+    // Check whether we are in leap second transition.
+    // If so, per NMEA spec, we need to display the extra second in format of 23:59:60
+    // with year/month/date not getting advanced.
+    if ((locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_GPS_TIME) &&
+        ((systemInfo.systemInfoMask & LOCATION_SYS_INFO_LEAP_SECOND) &&
+         (systemInfo.leapSecondSysInfo.leapSecondInfoMask &
+          LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT))) {
+
+        const LeapSecondChangeInfo  &leapSecondChangeInfo =
+            systemInfo.leapSecondSysInfo.leapSecondChangeInfo;
+        const GnssSystemTimeStructType &gpsTimestampLsChange =
+            leapSecondChangeInfo.gpsTimestampLsChange;
+
+        uint64_t gpsTimeLsChange = gpsTimestampLsChange.systemWeek * MSEC_IN_ONE_WEEK +
+                                   gpsTimestampLsChange.systemMsec;
+        uint64_t gpsTimePosReport = locationExtended.gpsTime.gpsWeek * MSEC_IN_ONE_WEEK +
+                                    locationExtended.gpsTime.gpsTimeOfWeekMs;
+        // we are only dealing with positive leap second change, as negative
+        // leap second change has never occurred and should not occur in future
+        if (leapSecondChangeInfo.leapSecondsAfterChange >
+            leapSecondChangeInfo.leapSecondsBeforeChange) {
+            // leap second adjustment is always 1 second at a time. It can happen
+            // every quarter end and up to four times per year.
+            if ((gpsTimePosReport >= gpsTimeLsChange) &&
+                (gpsTimePosReport < (gpsTimeLsChange + 1000))) {
+                inTransition = true;
+                utcPosTimestamp = gpsTimeLsChange + UTC_GPS_OFFSET_MSECS -
+                                  leapSecondChangeInfo.leapSecondsBeforeChange * 1000;
+
+                // we substract 1000 milli-seconds from UTC timestmap in order to calculate the
+                // proper year, month and date during leap second transtion.
+                // Let us give an example, assuming leap second transition is scheduled on 2019,
+                // Dec 31st mid night. When leap second transition is happening,
+                // instead of outputting the time as 2020, Jan, 1st, 00 hour, 00 min, and 00 sec.
+                // The time need to be displayed as 2019, Dec, 31st, 23 hour, 59 min and 60 sec.
+                utcPosTimestamp -= 1000;
+            }
+        }
+    }
+    return inTransition;
+}
+
+/*===========================================================================
+FUNCTION    loc_nmea_get_fix_quality
+
+DESCRIPTION
+   This function obtains the fix quality for GGA sentence, mode indicator
+   for RMC and VTG sentence based on nav solution mask and tech mask in
+   the postion report.
+
+DEPENDENCIES
+   NONE
+
+Output parameter
+   ggaGpsQuality: gps quality field in GGA sentence
+   rmcModeIndicator: mode indicator field in RMC sentence
+   vtgModeIndicator: mode indicator field in VTG sentence
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static void loc_nmea_get_fix_quality(const UlpLocation & location,
+                                     const GpsLocationExtended & locationExtended,
+                                     bool custom_gga_fix_quality,
+                                     char ggaGpsQuality[3],
+                                     char & rmcModeIndicator,
+                                     char & vtgModeIndicator,
+                                     char gnsModeIndicator[7]) {
+
+    ggaGpsQuality[0] = '0'; // 0 means no fix
+    rmcModeIndicator = 'N'; // N means no fix
+    vtgModeIndicator = 'N'; // N means no fix
+    memset(gnsModeIndicator, 'N', 6); // N means no fix
+    gnsModeIndicator[6] = '\0';
+    do {
+        if (!(location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG)){
+            break;
+        }
+        // NOTE: Order of the check is important
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK) {
+            if (LOC_NAV_MASK_PPP_CORRECTION & locationExtended.navSolutionMask) {
+                ggaGpsQuality[0] = '2';    // 2 means DGPS fix
+                rmcModeIndicator = 'P'; // P means precise
+                vtgModeIndicator = 'P'; // P means precise
+                if (locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[0] = 'P'; // P means precise
+                if (locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[1] = 'P'; // P means precise
+                if (locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[2] = 'P'; // P means precise
+                if (locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[3] = 'P'; // P means precise
+                if (locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[4] = 'P'; // P means precise
+                if (locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[5] = 'P'; // P means precise
+                break;
+            } else if (LOC_NAV_MASK_RTK_FIXED_CORRECTION & locationExtended.navSolutionMask){
+                ggaGpsQuality[0] = '4';    // 4 means RTK Fixed fix
+                rmcModeIndicator = 'R'; // use R (RTK fixed)
+                vtgModeIndicator = 'D'; // use D (differential) as
+                                        // no RTK fixed defined for VTG in NMEA 183 spec
+                if (locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[0] = 'R'; // R means RTK fixed
+                if (locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[1] = 'R'; // R means RTK fixed
+                if (locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[2] = 'R'; // R means RTK fixed
+                if (locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[3] = 'R'; // R means RTK fixed
+                if (locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[4] = 'R'; // R means RTK fixed
+                if (locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[5] = 'R'; // R means RTK fixed
+                break;
+            } else if (LOC_NAV_MASK_RTK_CORRECTION & locationExtended.navSolutionMask){
+                ggaGpsQuality[0] = '5';    // 5 means RTK float fix
+                rmcModeIndicator = 'F'; // F means RTK float fix
+                vtgModeIndicator = 'D'; // use D (differential) as
+                                        // no RTK float defined for VTG in NMEA 183 spec
+                if (locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[0] = 'F'; // F means RTK float fix
+                if (locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[1] = 'F'; // F means RTK float fix
+                if (locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[2] = 'F'; // F means RTK float fix
+                if (locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[3] = 'F'; // F means RTK float fix
+                if (locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[4] = 'F'; // F means RTK float fix
+                if (locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[5] = 'F'; // F means RTK float fix
+                break;
+            } else if (LOC_NAV_MASK_DGNSS_CORRECTION & locationExtended.navSolutionMask){
+                ggaGpsQuality[0] = '2';    // 2 means DGPS fix
+                rmcModeIndicator = 'D'; // D means differential
+                vtgModeIndicator = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[0] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[1] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[2] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[3] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[4] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[5] = 'D'; // D means differential
+                break;
+            } else if (LOC_NAV_MASK_SBAS_CORRECTION_IONO & locationExtended.navSolutionMask){
+                ggaGpsQuality[0] = '2';    // 2 means DGPS fix
+                rmcModeIndicator = 'D'; // D means differential
+                vtgModeIndicator = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[0] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[1] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[2] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[3] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[4] = 'D'; // D means differential
+                if (locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[5] = 'D'; // D means differential
+                break;
+            }
+        }
+        // NOTE: Order of the check is important
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_POS_TECH_MASK) {
+            if (LOC_POS_TECH_MASK_SATELLITE & locationExtended.tech_mask){
+                ggaGpsQuality[0] = '1'; // 1 means GPS
+                rmcModeIndicator = 'A'; // A means autonomous
+                vtgModeIndicator = 'A'; // A means autonomous
+                if (locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[0] = 'A'; // A means autonomous
+                if (locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[1] = 'A'; // A means autonomous
+                if (locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[2] = 'A'; // A means autonomous
+                if (locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[3] = 'A'; // A means autonomous
+                if (locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[4] = 'A'; // A means autonomous
+                if (locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask ? 1 : 0)
+                    gnsModeIndicator[5] = 'A'; // A means autonomous
+                break;
+            } else if (LOC_POS_TECH_MASK_SENSORS & locationExtended.tech_mask){
+                ggaGpsQuality[0] = '6'; // 6 means estimated (dead reckoning)
+                rmcModeIndicator = 'E'; // E means estimated (dead reckoning)
+                vtgModeIndicator = 'E'; // E means estimated (dead reckoning)
+                memset(gnsModeIndicator, 'E', 6); // E means estimated (dead reckoning)
+                break;
+            }
+        }
+    } while (0);
+
+    do {
+        // check for customized nmea enabled or not
+        // with customized GGA quality enabled
+        // PPP fix w/o sensor: 59, PPP fix w/ sensor: 69
+        // DGNSS/SBAS correction fix w/o sensor: 2, w/ sensor: 62
+        // RTK fixed fix w/o sensor: 4, w/ sensor: 64
+        // RTK float fix w/o sensor: 5, w/ sensor: 65
+        // SPE fix w/o sensor: 1, and w/ sensor: 61
+        // Sensor dead reckoning fix: 6
+        if (true == custom_gga_fix_quality) {
+            if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_NAV_SOLUTION_MASK) {
+                // PPP fix w/o sensor: fix quality will now be 59
+                // PPP fix w sensor: fix quality will now be 69
+                if (LOC_NAV_MASK_PPP_CORRECTION & locationExtended.navSolutionMask) {
+                    if ((locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_POS_TECH_MASK) &&
+                        (LOC_POS_TECH_MASK_SENSORS & locationExtended.tech_mask)) {
+                        ggaGpsQuality[0] = '6';
+                        ggaGpsQuality[1] = '9';
+                    } else {
+                        ggaGpsQuality[0] = '5';
+                        ggaGpsQuality[1] = '9';
+                    }
+                    break;
+                }
+            }
+
+            if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_POS_TECH_MASK) {
+                if (LOC_POS_TECH_MASK_SENSORS & locationExtended.tech_mask){
+                    char ggaQuality_copy = ggaGpsQuality[0];
+                    ggaGpsQuality[0] = '6'; // 6 sensor assisted
+                    // RTK fixed fix w/ sensor: fix quality will now be 64
+                    // RTK float fix w/ sensor: 65
+                    // DGNSS and/or SBAS correction fix and w/ sensor: 62
+                    // GPS fix without correction and w/ sensor: 61
+                    if ((LOC_NAV_MASK_RTK_FIXED_CORRECTION & locationExtended.navSolutionMask)||
+                            (LOC_NAV_MASK_RTK_CORRECTION & locationExtended.navSolutionMask)||
+                            (LOC_NAV_MASK_DGNSS_CORRECTION & locationExtended.navSolutionMask)||
+                            (LOC_NAV_MASK_SBAS_CORRECTION_IONO & locationExtended.navSolutionMask)||
+                            (LOC_POS_TECH_MASK_SATELLITE & locationExtended.tech_mask)) {
+                        ggaGpsQuality[1] = ggaQuality_copy;
+                        break;
+                    }
+                }
+            }
+        }
+    } while (0);
+
+    LOC_LOGv("gps quality: %s, rmc mode indicator: %c, vtg mode indicator: %c",
+             ggaGpsQuality, rmcModeIndicator, vtgModeIndicator);
+}
+
+/*===========================================================================
+FUNCTION    loc_nmea_generate_pos
+
+DESCRIPTION
+   Generate NMEA sentences generated based on position report
+   Currently below sentences are generated within this function:
+   - $GPGSA : GPS DOP and active SVs
+   - $GLGSA : GLONASS DOP and active SVs
+   - $GAGSA : GALILEO DOP and active SVs
+   - $GNGSA : GNSS DOP and active SVs
+   - $--VTG : Track made good and ground speed
+   - $--RMC : Recommended minimum navigation information
+   - $--GGA : Time, position and fix related data
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   0
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+void loc_nmea_generate_pos(const UlpLocation &location,
+                               const GpsLocationExtended &locationExtended,
+                               const LocationSystemInfo &systemInfo,
+                               unsigned char generate_nmea,
+                               bool custom_gga_fix_quality,
+                               std::vector<std::string> &nmeaArraystr,
+                               int& indexOfGGA,
+                               bool isTagBlockGroupingEnabled)
+{
+    ENTRY_LOG();
+
+    indexOfGGA = -1;
+    LocGpsUtcTime utcPosTimestamp = 0;
+    bool inLsTransition = false;
+
+    inLsTransition = get_utctime_with_leapsecond_transition
+                    (location, locationExtended, systemInfo, utcPosTimestamp);
+
+    time_t utcTime(utcPosTimestamp/1000);
+    struct tm result;
+    tm * pTm = gmtime_r(&utcTime, &result);
+    if (NULL == pTm) {
+        LOC_LOGE("gmtime failed");
+        return;
+    }
+
+    char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0};
+    char sentence_DTM[NMEA_SENTENCE_MAX_LENGTH] = {0};
+    char sentence_RMC[NMEA_SENTENCE_MAX_LENGTH] = {0};
+    char sentence_GNS[NMEA_SENTENCE_MAX_LENGTH] = {0};
+    char sentence_GGA[NMEA_SENTENCE_MAX_LENGTH] = {0};
+    char* pMarker = sentence;
+    int lengthRemaining = sizeof(sentence);
+    int length = 0;
+    int utcYear = pTm->tm_year % 100; // 2 digit year
+    int utcMonth = pTm->tm_mon + 1; // tm_mon starts at zero
+    int utcDay = pTm->tm_mday;
+    int utcHours = pTm->tm_hour;
+    int utcMinutes = pTm->tm_min;
+    int utcSeconds = pTm->tm_sec;
+    int utcMSeconds = (location.gpsLocation.timestamp)%1000;
+    int datum_type = loc_get_datum_type();
+    LocEcef ecef_w84;
+    LocEcef ecef_p90;
+    LocLla  lla_w84;
+    LocLla  lla_p90;
+    LocLla  ref_lla;
+    LocLla  local_lla;
+
+    if (inLsTransition) {
+        // During leap second transition, we need to display the extra
+        // leap second of hour, minute, second as (23:59:60)
+        utcHours = 23;
+        utcMinutes = 59;
+        utcSeconds = 60;
+        // As UTC timestamp is freezing during leap second transition,
+        // retrieve milli-seconds portion from GPS timestamp.
+        utcMSeconds = locationExtended.gpsTime.gpsTimeOfWeekMs % 1000;
+    }
+
+   loc_sv_cache_info sv_cache_info = {};
+
+    if (GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA & locationExtended.flags) {
+        sv_cache_info.gps_used_mask =
+                locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask;
+        sv_cache_info.glo_used_mask =
+                locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask;
+        sv_cache_info.gal_used_mask =
+                locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask;
+        sv_cache_info.bds_used_mask =
+                locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask;
+        sv_cache_info.qzss_used_mask =
+                locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask;
+        sv_cache_info.navic_used_mask =
+                locationExtended.gnss_sv_used_ids.navic_sv_used_ids_mask;
+    }
+
+    if (generate_nmea) {
+        char talker[3] = {'G', 'P', '\0'};
+        uint32_t svUsedCount = 0;
+        uint32_t count = 0;
+        loc_nmea_sv_meta sv_meta;
+        // -------------------
+        // ---$GPGSA/$GNGSA---
+        // -------------------
+
+        count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+                        loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS,
+                        GNSS_SIGNAL_GPS_L1CA, true), nmeaArraystr, isTagBlockGroupingEnabled);
+        if (count > 0)
+        {
+            svUsedCount += count;
+            talker[0] = sv_meta.talker[0];
+            talker[1] = sv_meta.talker[1];
+        }
+
+        // -------------------
+        // ---$GLGSA/$GNGSA---
+        // -------------------
+
+        count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+                        loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GLONASS,
+                        GNSS_SIGNAL_GLONASS_G1, true), nmeaArraystr, isTagBlockGroupingEnabled);
+        if (count > 0)
+        {
+            svUsedCount += count;
+            talker[0] = sv_meta.talker[0];
+            talker[1] = sv_meta.talker[1];
+        }
+
+        // -------------------
+        // ---$GAGSA/$GNGSA---
+        // -------------------
+
+        count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+                        loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO,
+                        GNSS_SIGNAL_GALILEO_E1, true), nmeaArraystr, isTagBlockGroupingEnabled);
+        if (count > 0)
+        {
+            svUsedCount += count;
+            talker[0] = sv_meta.talker[0];
+            talker[1] = sv_meta.talker[1];
+        }
+
+        // ----------------------------
+        // ---$GBGSA/$GNGSA (BEIDOU)---
+        // ----------------------------
+        count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+                        loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU,
+                        GNSS_SIGNAL_BEIDOU_B1I, true), nmeaArraystr, isTagBlockGroupingEnabled);
+        if (count > 0)
+        {
+            svUsedCount += count;
+            talker[0] = sv_meta.talker[0];
+            talker[1] = sv_meta.talker[1];
+        }
+
+        // --------------------------
+        // ---$GQGSA/$GNGSA (QZSS)---
+        // --------------------------
+
+        count = loc_nmea_generate_GSA(locationExtended, sentence, sizeof(sentence),
+                        loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS,
+                        GNSS_SIGNAL_QZSS_L1CA, true), nmeaArraystr, isTagBlockGroupingEnabled);
+        if (count > 0)
+        {
+            svUsedCount += count;
+            talker[0] = sv_meta.talker[0];
+            talker[1] = sv_meta.talker[1];
+        }
+
+        // if svUsedCount is 0, it means we do not generate any GSA sentence yet.
+        // in this case, generate an empty GSA sentence
+        if (svUsedCount == 0) {
+            strlcpy(sentence, "$GPGSA,A,1,,,,,,,,,,,,,,,,", sizeof(sentence));
+            length = loc_nmea_put_checksum(sentence, sizeof(sentence), false);
+            nmeaArraystr.push_back(sentence);
+        }
+
+        char ggaGpsQuality[3] = {'0', '\0', '\0'};
+        char rmcModeIndicator = 'N';
+        char vtgModeIndicator = 'N';
+        char gnsModeIndicator[7] = {'N', 'N', 'N', 'N', 'N', 'N', '\0'};
+        loc_nmea_get_fix_quality(location, locationExtended, custom_gga_fix_quality,
+                                 ggaGpsQuality, rmcModeIndicator, vtgModeIndicator, gnsModeIndicator);
+
+        // -------------------
+        // ------$--VTG-------
+        // -------------------
+
+        pMarker = sentence;
+        lengthRemaining = sizeof(sentence);
+
+        if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_BEARING)
+        {
+            float magTrack = location.gpsLocation.bearing;
+            if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV)
+            {
+                magTrack = location.gpsLocation.bearing - locationExtended.magneticDeviation;
+                if (magTrack < 0.0)
+                    magTrack += 360.0;
+                else if (magTrack > 360.0)
+                    magTrack -= 360.0;
+            }
+
+            length = snprintf(pMarker, lengthRemaining, "$%sVTG,%.1lf,T,%.1lf,M,", talker, location.gpsLocation.bearing, magTrack);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining, "$%sVTG,,T,,M,", talker);
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_SPEED)
+        {
+            float speedKnots = location.gpsLocation.speed * (3600.0/1852.0);
+            float speedKmPerHour = location.gpsLocation.speed * 3.6;
+
+            length = snprintf(pMarker, lengthRemaining, "%.1lf,N,%.1lf,K,", speedKnots, speedKmPerHour);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining, ",N,,K,");
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        length = snprintf(pMarker, lengthRemaining, "%c", vtgModeIndicator);
+
+        length = loc_nmea_put_checksum(sentence, sizeof(sentence), false);
+        nmeaArraystr.push_back(sentence);
+
+        memset(&ecef_w84, 0, sizeof(ecef_w84));
+        memset(&ecef_p90, 0, sizeof(ecef_p90));
+        memset(&lla_w84, 0, sizeof(lla_w84));
+        memset(&lla_p90, 0, sizeof(lla_p90));
+        memset(&ref_lla, 0, sizeof(ref_lla));
+        memset(&local_lla, 0, sizeof(local_lla));
+        lla_w84.lat = location.gpsLocation.latitude / 180.0 * M_PI;
+        lla_w84.lon = location.gpsLocation.longitude / 180.0 * M_PI;
+        lla_w84.alt = location.gpsLocation.altitude;
+
+        convert_Lla_to_Ecef(lla_w84, ecef_w84);
+        convert_WGS84_to_PZ90(ecef_w84, ecef_p90);
+        convert_Ecef_to_Lla(ecef_p90, lla_p90);
+
+        switch (datum_type) {
+            case LOC_GNSS_DATUM_WGS84:
+                ref_lla.lat = location.gpsLocation.latitude;
+                ref_lla.lon = location.gpsLocation.longitude;
+                ref_lla.alt = location.gpsLocation.altitude;
+                local_lla.lat = lla_p90.lat / M_PI * 180.0;
+                local_lla.lon = lla_p90.lon / M_PI * 180.0;
+                local_lla.alt = lla_p90.alt;
+                break;
+            case LOC_GNSS_DATUM_PZ90:
+                ref_lla.lat = lla_p90.lat / M_PI * 180.0;
+                ref_lla.lon = lla_p90.lon / M_PI * 180.0;
+                ref_lla.alt = lla_p90.alt;
+                local_lla.lat = location.gpsLocation.latitude;
+                local_lla.lon = location.gpsLocation.longitude;
+                local_lla.alt = location.gpsLocation.altitude;
+                break;
+            default:
+                break;
+        }
+
+        // -------------------
+        // ------$--DTM-------
+        // -------------------
+        loc_nmea_generate_DTM(ref_lla, local_lla, talker, sentence_DTM, sizeof(sentence_DTM));
+
+        // -------------------
+        // ------$--RMC-------
+        // -------------------
+
+        pMarker = sentence_RMC;
+        lengthRemaining = sizeof(sentence_RMC);
+
+        bool validFix = ((0 != sv_cache_info.gps_used_mask) ||
+                (0 != sv_cache_info.glo_used_mask) ||
+                (0 != sv_cache_info.gal_used_mask) ||
+                (0 != sv_cache_info.qzss_used_mask) ||
+                (0 != sv_cache_info.bds_used_mask));
+
+        if (validFix) {
+            length = snprintf(pMarker, lengthRemaining, "$%sRMC,%02d%02d%02d.%02d,A,",
+                              talker, utcHours, utcMinutes, utcSeconds, utcMSeconds/10);
+        } else {
+            length = snprintf(pMarker, lengthRemaining, "$%sRMC,%02d%02d%02d.%02d,V,",
+                              talker, utcHours, utcMinutes, utcSeconds, utcMSeconds/10);
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG)
+        {
+            double latitude = ref_lla.lat;
+            double longitude = ref_lla.lon;
+            char latHemisphere;
+            char lonHemisphere;
+            double latMinutes;
+            double lonMinutes;
+
+            if (latitude > 0)
+            {
+                latHemisphere = 'N';
+            }
+            else
+            {
+                latHemisphere = 'S';
+                latitude *= -1.0;
+            }
+
+            if (longitude < 0)
+            {
+                lonHemisphere = 'W';
+                longitude *= -1.0;
+            }
+            else
+            {
+                lonHemisphere = 'E';
+            }
+
+            latMinutes = fmod(latitude * 60.0 , 60.0);
+            lonMinutes = fmod(longitude * 60.0 , 60.0);
+
+            length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
+                              (uint8_t)floor(latitude), latMinutes, latHemisphere,
+                              (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining,",,,,");
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_SPEED)
+        {
+            float speedKnots = location.gpsLocation.speed * (3600.0/1852.0);
+            length = snprintf(pMarker, lengthRemaining, "%.1lf,", speedKnots);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining, ",");
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_BEARING)
+        {
+            length = snprintf(pMarker, lengthRemaining, "%.1lf,", location.gpsLocation.bearing);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining, ",");
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        length = snprintf(pMarker, lengthRemaining, "%2.2d%2.2d%2.2d,",
+                          utcDay, utcMonth, utcYear);
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_MAG_DEV)
+        {
+            float magneticVariation = locationExtended.magneticDeviation;
+            char direction;
+            if (magneticVariation < 0.0)
+            {
+                direction = 'W';
+                magneticVariation *= -1.0;
+            }
+            else
+            {
+                direction = 'E';
+            }
+
+            length = snprintf(pMarker, lengthRemaining, "%.1lf,%c,",
+                              magneticVariation, direction);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining, ",,");
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        length = snprintf(pMarker, lengthRemaining, "%c", rmcModeIndicator);
+        pMarker += length;
+        lengthRemaining -= length;
+
+        // hardcode Navigation Status field to 'V'
+        length = snprintf(pMarker, lengthRemaining, ",%c", 'V');
+
+        length = loc_nmea_put_checksum(sentence_RMC, sizeof(sentence_RMC), false);
+
+        // -------------------
+        // ------$--GNS-------
+        // -------------------
+
+        pMarker = sentence_GNS;
+        lengthRemaining = sizeof(sentence_GNS);
+
+        length = snprintf(pMarker, lengthRemaining, "$%sGNS,%02d%02d%02d.%02d," ,
+                          talker, utcHours, utcMinutes, utcSeconds, utcMSeconds/10);
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG)
+        {
+            double latitude = ref_lla.lat;
+            double longitude = ref_lla.lon;
+            char latHemisphere;
+            char lonHemisphere;
+            double latMinutes;
+            double lonMinutes;
+
+            if (latitude > 0)
+            {
+                latHemisphere = 'N';
+            }
+            else
+            {
+                latHemisphere = 'S';
+                latitude *= -1.0;
+            }
+
+            if (longitude < 0)
+            {
+                lonHemisphere = 'W';
+                longitude *= -1.0;
+            }
+            else
+            {
+                lonHemisphere = 'E';
+            }
+
+            latMinutes = fmod(latitude * 60.0 , 60.0);
+            lonMinutes = fmod(longitude * 60.0 , 60.0);
+
+            length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
+                              (uint8_t)floor(latitude), latMinutes, latHemisphere,
+                              (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining,",,,,");
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        length = snprintf(pMarker, lengthRemaining, "%s,", gnsModeIndicator);
+
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP) {
+            length = snprintf(pMarker, lengthRemaining, "%02d,%.1f,",
+                              svUsedCount, locationExtended.hdop);
+        }
+        else {   // no hdop
+            length = snprintf(pMarker, lengthRemaining, "%02d,,",
+                              svUsedCount);
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL)
+        {
+            length = snprintf(pMarker, lengthRemaining, "%.1lf,",
+                              locationExtended.altitudeMeanSeaLevel);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining,",");
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if ((location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_ALTITUDE) &&
+            (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL))
+        {
+            length = snprintf(pMarker, lengthRemaining, "%.1lf,",
+                              ref_lla.alt - locationExtended.altitudeMeanSeaLevel);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining, ",");
+        }
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DGNSS_DATA_AGE)
+        {
+            length = snprintf(pMarker, lengthRemaining, "%.1f,",
+                              (float)locationExtended.dgnssDataAgeMsec / 1000);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining, ",");
+        }
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DGNSS_REF_STATION_ID)
+        {
+            length = snprintf(pMarker, lengthRemaining, "%04d",
+                              locationExtended.dgnssRefStationId);
+            if (length < 0 || length >= lengthRemaining)
+            {
+                LOC_LOGE("NMEA Error in string formatting");
+                return;
+            }
+            pMarker += length;
+            lengthRemaining -= length;
+        }
+
+        // hardcode Navigation Status field to 'V'
+        length = snprintf(pMarker, lengthRemaining, ",%c", 'V');
+        pMarker += length;
+        lengthRemaining -= length;
+
+        length = loc_nmea_put_checksum(sentence_GNS, sizeof(sentence_GNS), false);
+
+        // -------------------
+        // ------$--GGA-------
+        // -------------------
+
+        pMarker = sentence_GGA;
+        lengthRemaining = sizeof(sentence_GGA);
+
+        length = snprintf(pMarker, lengthRemaining, "$%sGGA,%02d%02d%02d.%02d," ,
+                          talker, utcHours, utcMinutes, utcSeconds, utcMSeconds/10);
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_LAT_LONG)
+        {
+            double latitude = ref_lla.lat;
+            double longitude = ref_lla.lon;
+            char latHemisphere;
+            char lonHemisphere;
+            double latMinutes;
+            double lonMinutes;
+
+            if (latitude > 0)
+            {
+                latHemisphere = 'N';
+            }
+            else
+            {
+                latHemisphere = 'S';
+                latitude *= -1.0;
+            }
+
+            if (longitude < 0)
+            {
+                lonHemisphere = 'W';
+                longitude *= -1.0;
+            }
+            else
+            {
+                lonHemisphere = 'E';
+            }
+
+            latMinutes = fmod(latitude * 60.0 , 60.0);
+            lonMinutes = fmod(longitude * 60.0 , 60.0);
+
+            length = snprintf(pMarker, lengthRemaining, "%02d%09.6lf,%c,%03d%09.6lf,%c,",
+                              (uint8_t)floor(latitude), latMinutes, latHemisphere,
+                              (uint8_t)floor(longitude),lonMinutes, lonHemisphere);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining,",,,,");
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        // Number of satellites in use, 00-12
+        if (svUsedCount > MAX_SATELLITES_IN_USE)
+            svUsedCount = MAX_SATELLITES_IN_USE;
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
+        {
+            length = snprintf(pMarker, lengthRemaining, "%s,%02d,%.1f,",
+                              ggaGpsQuality, svUsedCount, locationExtended.hdop);
+        }
+        else
+        {   // no hdop
+            length = snprintf(pMarker, lengthRemaining, "%s,%02d,,",
+                              ggaGpsQuality, svUsedCount);
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL)
+        {
+            length = snprintf(pMarker, lengthRemaining, "%.1lf,M,",
+                              locationExtended.altitudeMeanSeaLevel);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining,",,");
+        }
+
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if ((location.gpsLocation.flags & LOC_GPS_LOCATION_HAS_ALTITUDE) &&
+            (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_ALTITUDE_MEAN_SEA_LEVEL))
+        {
+            length = snprintf(pMarker, lengthRemaining, "%.1lf,M,",
+                              ref_lla.alt - locationExtended.altitudeMeanSeaLevel);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining, ",,");
+        }
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DGNSS_DATA_AGE)
+        {
+            length = snprintf(pMarker, lengthRemaining, "%.1f,",
+                              (float)locationExtended.dgnssDataAgeMsec / 1000);
+        }
+        else
+        {
+            length = snprintf(pMarker, lengthRemaining, ",");
+        }
+        if (length < 0 || length >= lengthRemaining)
+        {
+            LOC_LOGE("NMEA Error in string formatting");
+            return;
+        }
+        pMarker += length;
+        lengthRemaining -= length;
+
+        if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DGNSS_REF_STATION_ID)
+        {
+            length = snprintf(pMarker, lengthRemaining, "%04d",
+                              locationExtended.dgnssRefStationId);
+            if (length < 0 || length >= lengthRemaining)
+            {
+                LOC_LOGE("NMEA Error in string formatting");
+                return;
+            }
+            pMarker += length;
+            lengthRemaining -= length;
+        }
+
+        length = loc_nmea_put_checksum(sentence_GGA, sizeof(sentence_GGA), false);
+
+        // ------$--DTM-------
+        nmeaArraystr.push_back(sentence_DTM);
+        // ------$--RMC-------
+        nmeaArraystr.push_back(sentence_RMC);
+        if(LOC_GNSS_DATUM_PZ90 == datum_type) {
+            // ------$--DTM-------
+            nmeaArraystr.push_back(sentence_DTM);
+        }
+        // ------$--GNS-------
+        nmeaArraystr.push_back(sentence_GNS);
+        if(LOC_GNSS_DATUM_PZ90 == datum_type) {
+            // ------$--DTM-------
+            nmeaArraystr.push_back(sentence_DTM);
+        }
+        // ------$--GGA-------
+        nmeaArraystr.push_back(sentence_GGA);
+        indexOfGGA = static_cast<int>(nmeaArraystr.size() - 1);
+    }
+    //Send blank NMEA reports for non-final fixes
+    else {
+        strlcpy(sentence, "$GPGSA,A,1,,,,,,,,,,,,,,,,", sizeof(sentence));
+        length = loc_nmea_put_checksum(sentence, sizeof(sentence), false);
+        nmeaArraystr.push_back(sentence);
+
+        strlcpy(sentence, "$GPVTG,,T,,M,,N,,K,N", sizeof(sentence));
+        length = loc_nmea_put_checksum(sentence, sizeof(sentence), false);
+        nmeaArraystr.push_back(sentence);
+
+        strlcpy(sentence, "$GPDTM,,,,,,,,", sizeof(sentence));
+        length = loc_nmea_put_checksum(sentence, sizeof(sentence), false);
+        nmeaArraystr.push_back(sentence);
+
+        strlcpy(sentence, "$GPRMC,,V,,,,,,,,,,N,V", sizeof(sentence));
+        length = loc_nmea_put_checksum(sentence, sizeof(sentence), false);
+        nmeaArraystr.push_back(sentence);
+
+        strlcpy(sentence, "$GPGNS,,,,,,N,,,,,,,V", sizeof(sentence));
+        length = loc_nmea_put_checksum(sentence, sizeof(sentence), false);
+        nmeaArraystr.push_back(sentence);
+
+        strlcpy(sentence, "$GPGGA,,,,,,0,,,,,,,,", sizeof(sentence));
+        length = loc_nmea_put_checksum(sentence, sizeof(sentence), false);
+        nmeaArraystr.push_back(sentence);
+    }
+
+    EXIT_LOG(%d, 0);
+}
+
+
+
+/*===========================================================================
+FUNCTION    loc_nmea_generate_sv
+
+DESCRIPTION
+   Generate NMEA sentences generated based on sv report
+
+DEPENDENCIES
+   NONE
+
+RETURN VALUE
+   0
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+void loc_nmea_generate_sv(const GnssSvNotification &svNotify,
+                              std::vector<std::string> &nmeaArraystr)
+{
+    ENTRY_LOG();
+
+    char sentence[NMEA_SENTENCE_MAX_LENGTH] = {0};
+    loc_sv_cache_info sv_cache_info = {};
+
+    //Count GPS SVs for saparating GPS from GLONASS and throw others
+    for (uint32_t svOffset = 0; svOffset < svNotify.count; svOffset++) {
+        if ((GNSS_SV_TYPE_GPS == svNotify.gnssSvs[svOffset].type) ||
+            (GNSS_SV_TYPE_SBAS == svNotify.gnssSvs[svOffset].type))
+        {
+            if (GNSS_SIGNAL_GPS_L5 == svNotify.gnssSvs[svOffset].gnssSignalTypeMask) {
+                sv_cache_info.gps_l5_count++;
+            } else if (GNSS_SIGNAL_GPS_L2 == svNotify.gnssSvs[svOffset].gnssSignalTypeMask) {
+                sv_cache_info.gps_l2_count++;
+            } else {
+                // GNSS_SIGNAL_GPS_L1CA, GNSS_SIGNAL_SBAS_L1 or default
+                // If no signal type in report, it means default L1
+                sv_cache_info.gps_l1_count++;
+            }
+        }
+        else if (GNSS_SV_TYPE_GLONASS == svNotify.gnssSvs[svOffset].type)
+        {
+            if (GNSS_SIGNAL_GLONASS_G2 == svNotify.gnssSvs[svOffset].gnssSignalTypeMask){
+                sv_cache_info.glo_g2_count++;
+            } else {
+                // GNSS_SIGNAL_GLONASS_G1 or default
+                // If no signal type in report, it means default G1
+                sv_cache_info.glo_g1_count++;
+            }
+        }
+        else if (GNSS_SV_TYPE_GALILEO == svNotify.gnssSvs[svOffset].type)
+        {
+            if(GNSS_SIGNAL_GALILEO_E5A == svNotify.gnssSvs[svOffset].gnssSignalTypeMask){
+                sv_cache_info.gal_e5_count++;
+            } else if (GNSS_SIGNAL_GALILEO_E5B == svNotify.gnssSvs[svOffset].gnssSignalTypeMask) {
+                sv_cache_info.gal_e5b_count++;
+            } else {
+                // GNSS_SIGNAL_GALILEO_E1 or default
+                // If no signal type in report, it means default E1
+                sv_cache_info.gal_e1_count++;
+            }
+        }
+        else if (GNSS_SV_TYPE_QZSS == svNotify.gnssSvs[svOffset].type)
+        {
+            if (GNSS_SIGNAL_QZSS_L5 == svNotify.gnssSvs[svOffset].gnssSignalTypeMask) {
+                sv_cache_info.qzss_l5_count++;
+            } else if (GNSS_SIGNAL_QZSS_L2 == svNotify.gnssSvs[svOffset].gnssSignalTypeMask) {
+                sv_cache_info.qzss_l2_count++;
+            } else {
+                // GNSS_SIGNAL_QZSS_L1CA or default
+                // If no signal type in report, it means default L1
+                sv_cache_info.qzss_l1_count++;
+            }
+        }
+        else if (GNSS_SV_TYPE_BEIDOU == svNotify.gnssSvs[svOffset].type)
+        {
+            // cache the used in fix mask, as it will be needed to send $PQGSA
+            // during the position report
+            if (GNSS_SV_OPTIONS_USED_IN_FIX_BIT ==
+                (svNotify.gnssSvs[svOffset].gnssSvOptionsMask &
+                  GNSS_SV_OPTIONS_USED_IN_FIX_BIT))
+            {
+                setSvMask(sv_cache_info.bds_used_mask, svNotify.gnssSvs[svOffset].svId);
+            }
+            if ((GNSS_SIGNAL_BEIDOU_B2AI == svNotify.gnssSvs[svOffset].gnssSignalTypeMask) ||
+                   (GNSS_SIGNAL_BEIDOU_B2AQ == svNotify.gnssSvs[svOffset].gnssSignalTypeMask)) {
+                sv_cache_info.bds_b2_count++;
+            } else if (GNSS_SIGNAL_BEIDOU_B1C == svNotify.gnssSvs[svOffset].gnssSignalTypeMask) {
+                sv_cache_info.bds_b1c_count++;
+            } else {
+                // GNSS_SIGNAL_BEIDOU_B1I or default
+                // If no signal type in report, it means default B1I
+                sv_cache_info.bds_b1i_count++;
+            }
+        }
+        else if (GNSS_SV_TYPE_NAVIC == svNotify.gnssSvs[svOffset].type)
+        {
+            // GNSS_SIGNAL_NAVIC_L5 is the only signal type for NAVIC
+            sv_cache_info.navic_l5_count++;
+        }
+    }
+
+    loc_nmea_sv_meta sv_meta;
+    // ---------------------
+    // ------$GPGSV:L1CA----
+    // ---------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS,
+            GNSS_SIGNAL_GPS_L1CA, false), nmeaArraystr);
+
+    // ---------------------
+    // ------$GPGSV:L5------
+    // ---------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS,
+            GNSS_SIGNAL_GPS_L5, false), nmeaArraystr);
+
+    // ---------------------
+    // ------$GPGSV:L2------
+    // ---------------------
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GPS,
+            GNSS_SIGNAL_GPS_L2, false), nmeaArraystr);
+
+    // ---------------------
+    // ------$GLGSV:G1------
+    // ---------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GLONASS,
+            GNSS_SIGNAL_GLONASS_G1, false), nmeaArraystr);
+
+    // ---------------------
+    // ------$GLGSV:G2------
+    // ---------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GLONASS,
+            GNSS_SIGNAL_GLONASS_G2, false), nmeaArraystr);
+
+    // ---------------------
+    // ------$GAGSV:E1------
+    // ---------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO,
+            GNSS_SIGNAL_GALILEO_E1, false), nmeaArraystr);
+
+    // -------------------------
+    // ------$GAGSV:E5A---------
+    // -------------------------
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO,
+            GNSS_SIGNAL_GALILEO_E5A, false), nmeaArraystr);
+
+    // -------------------------
+    // ------$GAGSV:E5B---------
+    // -------------------------
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_GALILEO,
+            GNSS_SIGNAL_GALILEO_E5B, false), nmeaArraystr);
+
+    // -----------------------------
+    // ------$GQGSV (QZSS):L1CA-----
+    // -----------------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS,
+            GNSS_SIGNAL_QZSS_L1CA, false), nmeaArraystr);
+
+    // -----------------------------
+    // ------$GQGSV (QZSS):L5-------
+    // -----------------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS,
+            GNSS_SIGNAL_QZSS_L5, false), nmeaArraystr);
+
+    // -----------------------------
+    // ------$GQGSV (QZSS):L2-------
+    // -----------------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_QZSS,
+            GNSS_SIGNAL_QZSS_L2, false), nmeaArraystr);
+
+
+    // -----------------------------
+    // ------$GBGSV (BEIDOU:B1I)----
+    // -----------------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU,
+            GNSS_SIGNAL_BEIDOU_B1I, false), nmeaArraystr);
+
+    // -----------------------------
+    // ------$GBGSV (BEIDOU:B1C)----
+    // -----------------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU,
+            GNSS_SIGNAL_BEIDOU_B1C, false), nmeaArraystr);
+
+    // -----------------------------
+    // ------$GBGSV (BEIDOU:B2AI)---
+    // -----------------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_BEIDOU,
+            GNSS_SIGNAL_BEIDOU_B2AI, false), nmeaArraystr);
+
+    // -----------------------------
+    // ------$GIGSV (NAVIC:L5)------
+    // -----------------------------
+
+    loc_nmea_generate_GSV(svNotify, sentence, sizeof(sentence),
+            loc_nmea_sv_meta_init(sv_meta, sv_cache_info, GNSS_SV_TYPE_NAVIC,
+            GNSS_SIGNAL_NAVIC_L5,false), nmeaArraystr);
+
+    EXIT_LOG(%d, 0);
+}
diff --git a/gps/utils/loc_nmea.h b/gps/utils/loc_nmea.h
new file mode 100644
index 0000000..2d98f42
--- /dev/null
+++ b/gps/utils/loc_nmea.h
@@ -0,0 +1,95 @@
+/* Copyright (c) 2012-2013, 2015-2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef LOC_ENG_NMEA_H
+#define LOC_ENG_NMEA_H
+
+#include <gps_extended.h>
+#include <vector>
+#include <string>
+#define NMEA_SENTENCE_MAX_LENGTH 200
+
+/** gnss datum type */
+#define LOC_GNSS_DATUM_WGS84          0
+#define LOC_GNSS_DATUM_PZ90           1
+
+/* len of semi major axis of ref ellips*/
+#define MAJA               (6378137.0)
+/* flattening coef of ref ellipsoid*/
+#define FLAT               (1.0/298.2572235630)
+/* 1st eccentricity squared*/
+#define ESQR               (FLAT*(2.0 - FLAT))
+/*1 minus eccentricity squared*/
+#define OMES               (1.0 - ESQR)
+#define MILARCSEC2RAD      (4.848136811095361e-09)
+/*semi major axis */
+#define C_PZ90A            (6378136.0)
+/*semi minor axis */
+#define C_PZ90B            (6356751.3618)
+/* Transformation from WGS84 to PZ90
+ * Cx,Cy,Cz,Rs,Rx,Ry,Rz,C_SYS_A,C_SYS_B*/
+const double DatumConstFromWGS84[9] =
+        {+0.003, +0.001, 0.000, (1.0+(0.000*1E-6)), (-0.019*MILARCSEC2RAD),
+        (+0.042*MILARCSEC2RAD), (-0.002*MILARCSEC2RAD), C_PZ90A, C_PZ90B};
+
+/** Represents a LTP*/
+typedef struct {
+    double     lat;
+    double     lon;
+    double     alt;
+} LocLla;
+
+/** Represents a ECEF*/
+typedef struct {
+    double     X;
+    double     Y;
+    double     Z;
+} LocEcef;
+
+void loc_nmea_generate_sv(const GnssSvNotification &svNotify,
+                              std::vector<std::string> &nmeaArraystr);
+
+void loc_nmea_generate_pos(const UlpLocation &location,
+                               const GpsLocationExtended &locationExtended,
+                               const LocationSystemInfo &systemInfo,
+                               unsigned char generate_nmea,
+                               bool custom_gga_fix_quality,
+                               std::vector<std::string> &nmeaArraystr,
+                               int& indexOfGGA,
+                               bool isTagBlockGroupingEnabled);
+
+#define DEBUG_NMEA_MINSIZE 6
+#define DEBUG_NMEA_MAXSIZE 4096
+inline bool loc_nmea_is_debug(const char* nmea, int length) {
+    return ((nullptr != nmea) &&
+            (length >= DEBUG_NMEA_MINSIZE) && (length <= DEBUG_NMEA_MAXSIZE) &&
+            (nmea[0] == '$') && (nmea[1] == 'P') && (nmea[2] == 'Q') && (nmea[3] == 'W'));
+}
+
+#endif // LOC_ENG_NMEA_H
diff --git a/gps/utils/loc_target.cpp b/gps/utils/loc_target.cpp
new file mode 100644
index 0000000..3ee42e6
--- /dev/null
+++ b/gps/utils/loc_target.cpp
@@ -0,0 +1,249 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <log_util.h>
+#include "loc_target.h"
+#include "loc_log.h"
+#include <loc_pla.h>
+
+#define APQ8064_ID_1 "109"
+#define APQ8064_ID_2 "153"
+#define MPQ8064_ID_1 "130"
+#define MSM8930_ID_1 "142"
+#define MSM8930_ID_2 "116"
+#define APQ8030_ID_1 "157"
+#define APQ8074_ID_1 "184"
+
+#define LINE_LEN 100
+#define STR_LIQUID      "Liquid"
+#define STR_SURF        "Surf"
+#define STR_MTP         "MTP"
+#define STR_APQ         "apq"
+#define STR_SDC         "sdc"  // alternative string for APQ targets
+#define STR_QCS         "qcs"  // string for Gen9 APQ targets
+#define STR_MSM         "msm"
+#define STR_SDM         "sdm"  // alternative string for MSM targets
+#define STR_APQ_NO_WGR  "baseband_apq_nowgr"
+#define STR_AUTO        "auto"
+#define IS_STR_END(c) ((c) == '\0' || (c) == '\n' || (c) == '\r')
+#define LENGTH(s) (sizeof(s) - 1)
+#define GPS_CHECK_NO_ERROR 0
+#define GPS_CHECK_NO_GPS_HW 1
+
+static unsigned int gTarget = (unsigned int)-1;
+
+static int read_a_line(const char * file_path, char * line, int line_size)
+{
+    FILE *fp;
+    int result = 0;
+
+    * line = '\0';
+    fp = fopen(file_path, "r" );
+    if( fp == NULL ) {
+        LOC_LOGE("open failed: %s: %s\n", file_path, strerror(errno));
+        result = -1;
+    } else {
+        int len;
+        fgets(line, line_size, fp);
+        len = strlen(line);
+        while ('\n' == line[len-1]) {
+            // If there is a new line at end of string, replace it with NULL
+            line[len-1] = '\0';
+            len--;
+        }
+        len = len < line_size - 1? len : line_size - 1;
+        line[len] = '\0';
+        LOC_LOGD("cat %s: %s", file_path, line);
+        fclose(fp);
+    }
+    return result;
+}
+
+/*The character array passed to this function should have length
+  of atleast PROPERTY_VALUE_MAX*/
+void loc_get_target_baseband(char *baseband, int array_length)
+{
+    if(baseband && (array_length >= PROPERTY_VALUE_MAX)) {
+        property_get("ro.baseband", baseband, "");
+        LOC_LOGD("%s:%d]: Baseband: %s\n", __func__, __LINE__, baseband);
+    }
+    else {
+        LOC_LOGE("%s:%d]: NULL parameter or array length less than PROPERTY_VALUE_MAX\n",
+                 __func__, __LINE__);
+    }
+}
+
+/*The character array passed to this function should have length
+  of atleast PROPERTY_VALUE_MAX*/
+void loc_get_platform_name(char *platform_name, int array_length)
+{
+    if(platform_name && (array_length >= PROPERTY_VALUE_MAX)) {
+        property_get("ro.board.platform", platform_name, "");
+        LOC_LOGD("%s:%d]: Target name: %s\n", __func__, __LINE__, platform_name);
+    }
+    else {
+        LOC_LOGE("%s:%d]: Null parameter or array length less than PROPERTY_VALUE_MAX\n",
+                 __func__, __LINE__);
+    }
+}
+
+/*The character array passed to this function should have length
+  of atleast PROPERTY_VALUE_MAX*/
+void loc_get_auto_platform_name(char *platform_name, int array_length)
+{
+    if(platform_name && (array_length >= PROPERTY_VALUE_MAX)) {
+        property_get("ro.hardware.type", platform_name, "");
+        LOC_LOGD("%s:%d]: Autoplatform name: %s\n", __func__, __LINE__, platform_name);
+    }
+    else {
+        LOC_LOGE("%s:%d]: Null parameter or array length less than PROPERTY_VALUE_MAX\n",
+                 __func__, __LINE__);
+    }
+}
+
+/*Reads the property ro.config.low_ram to identify if this is a low ram target
+  Returns:
+  0 if not a low ram target
+  1 if this is a low ram target
+*/
+int loc_identify_low_ram_target()
+{
+    int ret = 0;
+    char low_ram_target[PROPERTY_VALUE_MAX];
+    property_get("ro.config.low_ram", low_ram_target, "");
+    LOC_LOGd("low ram target: %s\n", low_ram_target);
+    return !(strncmp(low_ram_target, "true", PROPERTY_VALUE_MAX));
+}
+
+/*The character array passed to this function should have length
+  of atleast PROPERTY_VALUE_MAX*/
+/* Reads the soc_id node and return the soc_id value */
+void loc_get_device_soc_id(char *soc_id_value, int array_length)
+{
+    static const char soc_id[]     = "/sys/devices/soc0/soc_id";
+    static const char soc_id_dep[] = "/sys/devices/system/soc/soc0/id";
+    int return_val = 0;
+
+    if (soc_id_value && (array_length >= PROPERTY_VALUE_MAX)) {
+        if (!access(soc_id, F_OK)) {
+            return_val = read_a_line(soc_id, soc_id_value, array_length);
+        } else {
+            return_val = read_a_line(soc_id_dep, soc_id_value, array_length);
+        }
+        if (0 == return_val) {
+            LOC_LOGd("SOC Id value: %s\n", soc_id_value);
+        } else {
+            LOC_LOGe("Unable to read the soc_id value\n");
+        }
+    } else {
+        LOC_LOGe("Null parameter or array length less than PROPERTY_VALUE_MAX\n");
+    }
+}
+
+unsigned int loc_get_target(void)
+{
+    if (gTarget != (unsigned int)-1)
+        return gTarget;
+
+    static const char hw_platform[]      = "/sys/devices/soc0/hw_platform";
+    static const char hw_platform_dep[]  =
+        "/sys/devices/system/soc/soc0/hw_platform";
+    static const char mdm[]              = "/target"; // mdm target we are using
+
+    char rd_hw_platform[LINE_LEN];
+    char rd_id[LINE_LEN];
+    char rd_mdm[LINE_LEN];
+    char baseband[LINE_LEN];
+    char rd_auto_platform[LINE_LEN];
+
+    loc_get_target_baseband(baseband, sizeof(baseband));
+
+    if (!access(hw_platform, F_OK)) {
+        read_a_line(hw_platform, rd_hw_platform, LINE_LEN);
+    } else {
+        read_a_line(hw_platform_dep, rd_hw_platform, LINE_LEN);
+    }
+    // Get the soc-id for this device.
+    loc_get_device_soc_id(rd_id, sizeof(rd_id));
+
+    /*check automotive platform*/
+    loc_get_auto_platform_name(rd_auto_platform, sizeof(rd_auto_platform));
+    if( !memcmp(rd_auto_platform, STR_AUTO, LENGTH(STR_AUTO)) )
+    {
+          gTarget = TARGET_AUTO;
+          goto detected;
+    }
+
+    if( !memcmp(baseband, STR_APQ_NO_WGR, LENGTH(STR_APQ_NO_WGR)) ){
+
+        gTarget = TARGET_NO_GNSS;
+        goto detected;
+    }
+
+    if( !memcmp(baseband, STR_APQ, LENGTH(STR_APQ)) ||
+        !memcmp(baseband, STR_SDC, LENGTH(STR_SDC)) ||
+        !memcmp(baseband, STR_QCS, LENGTH(STR_QCS)) ) {
+
+        if( !memcmp(rd_id, MPQ8064_ID_1, LENGTH(MPQ8064_ID_1))
+            && IS_STR_END(rd_id[LENGTH(MPQ8064_ID_1)]) )
+            gTarget = TARGET_NO_GNSS;
+        else
+            gTarget = TARGET_APQ_SA;
+    } else if (((!memcmp(rd_hw_platform, STR_LIQUID, LENGTH(STR_LIQUID))
+                 && IS_STR_END(rd_hw_platform[LENGTH(STR_LIQUID)])) ||
+                (!memcmp(rd_hw_platform, STR_SURF,   LENGTH(STR_SURF))
+                 && IS_STR_END(rd_hw_platform[LENGTH(STR_SURF)])) ||
+                (!memcmp(rd_hw_platform, STR_MTP,   LENGTH(STR_MTP))
+                 && IS_STR_END(rd_hw_platform[LENGTH(STR_MTP)]))) &&
+               !read_a_line( mdm, rd_mdm, LINE_LEN)) {
+        gTarget = TARGET_MDM;
+    } else if( (!memcmp(rd_id, MSM8930_ID_1, LENGTH(MSM8930_ID_1))
+                && IS_STR_END(rd_id[LENGTH(MSM8930_ID_1)])) ||
+               (!memcmp(rd_id, MSM8930_ID_2, LENGTH(MSM8930_ID_2))
+                && IS_STR_END(rd_id[LENGTH(MSM8930_ID_2)])) ) {
+        gTarget = TARGET_MSM_NO_SSC;
+    } else if ( !memcmp(baseband, STR_MSM, LENGTH(STR_MSM)) ||
+                !memcmp(baseband, STR_SDM, LENGTH(STR_SDM)) ) {
+        gTarget = TARGET_DEFAULT;
+    } else {
+        gTarget = TARGET_UNKNOWN;
+    }
+
+detected:
+    LOC_LOGW("HAL: %s returned %d", __FUNCTION__, gTarget);
+    return gTarget;
+}
diff --git a/gps/utils/loc_target.h b/gps/utils/loc_target.h
new file mode 100644
index 0000000..2dcd895
--- /dev/null
+++ b/gps/utils/loc_target.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#ifndef LOC_TARGET_H
+#define LOC_TARGET_H
+#define TARGET_SET(gnss,ssc) ( (gnss<<1)|ssc )
+#define TARGET_DEFAULT       TARGET_SET(GNSS_MSM, HAS_SSC)
+#define TARGET_MDM           TARGET_SET(GNSS_MDM, HAS_SSC)
+#define TARGET_APQ_SA        TARGET_SET(GNSS_GSS, NO_SSC)
+#define TARGET_NO_GNSS       TARGET_SET(GNSS_NONE, NO_SSC)
+#define TARGET_MSM_NO_SSC    TARGET_SET(GNSS_MSM, NO_SSC)
+#define TARGET_AUTO          TARGET_SET(GNSS_AUTO, NO_SSC)
+#define TARGET_UNKNOWN       TARGET_SET(GNSS_UNKNOWN, NO_SSC)
+#define getTargetGnssType(target)  (target>>1)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+unsigned int loc_get_target(void);
+
+/*The character array passed to this function should have length
+  of atleast PROPERTY_VALUE_MAX*/
+void loc_get_target_baseband(char *baseband, int array_length);
+/*The character array passed to this function should have length
+  of atleast PROPERTY_VALUE_MAX*/
+void loc_get_platform_name(char *platform_name, int array_length);
+/*The character array passed to this function should have length
+  of atleast PROPERTY_VALUE_MAX*/
+void loc_get_auto_platform_name(char *platform_name, int array_length);
+int loc_identify_low_ram_target();
+/*The character array passed to this function should have length
+  of atleast PROPERTY_VALUE_MAX*/
+void loc_get_device_soc_id(char *soc_id_value, int array_length);
+
+/* Please remember to update 'target_name' in loc_log.cpp,
+   if do any changes to this enum. */
+typedef enum {
+    GNSS_NONE = 0,
+    GNSS_MSM,
+    GNSS_GSS,
+    GNSS_MDM,
+    GNSS_AUTO,
+    GNSS_UNKNOWN
+}GNSS_TARGET;
+
+typedef enum {
+    NO_SSC = 0,
+    HAS_SSC
+}SSC_TYPE;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*LOC_TARGET_H*/
diff --git a/gps/utils/loc_timer.h b/gps/utils/loc_timer.h
new file mode 100644
index 0000000..fff0c46
--- /dev/null
+++ b/gps/utils/loc_timer.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2013,2015 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __LOC_DELAY_H__
+#define __LOC_DELAY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#include <stddef.h>
+#include <stdint.h>
+#include <loc_pla.h>
+/*
+    user_data: client context pointer, passthrough. Originally received
+               from calling client when loc_timer_start() is called.
+    result:    0 if timer successfully timed out; else timer failed.
+*/
+typedef void (*loc_timer_callback)(void *user_data, int32_t result);
+
+
+/*
+    delay_msec:         timeout value for the timer.
+    cb_func:            callback function pointer, implemented by client.
+                        Can not be NULL.
+    user_data:          client context pointer, passthrough.  Will be
+                        returned when loc_timer_callback() is called.
+    wakeOnExpire:       true if to wake up CPU (if sleeping) upon timer
+                                expiration and notify the client.
+                        false if to wait until next time CPU wakes up (if
+                                 sleeping) and then notify the client.
+    Returns the handle, which can be used to stop the timer
+                        NULL, if timer start fails (e.g. if cb_func is NULL).
+*/
+void* loc_timer_start(uint64_t delay_msec,
+                      loc_timer_callback cb_func,
+                      void *user_data,
+                      bool wake_on_expire=false);
+
+/*
+    handle becomes invalid upon the return of the callback
+*/
+void loc_timer_stop(void*& handle);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif //__LOC_DELAY_H__
diff --git a/gps/utils/log_util.h b/gps/utils/log_util.h
new file mode 100644
index 0000000..33aa6e2
--- /dev/null
+++ b/gps/utils/log_util.h
@@ -0,0 +1,291 @@
+/* Copyright (c) 2011-2014, 2020 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __LOG_UTIL_H__
+#define __LOG_UTIL_H__
+
+#include <stdbool.h>
+#include <loc_pla.h>
+#if defined (USE_ANDROID_LOGGING) || defined (ANDROID)
+// Android and LE targets with logcat support
+#include <utils/Log.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#elif defined (USE_GLIB)
+// LE targets with no logcat support
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef LOG_TAG
+#define LOG_TAG "GPS_UTILS"
+#endif /* LOG_TAG */
+
+// LE targets with no logcat support
+#if defined(FEATURE_EXTERNAL_AP) || defined(USE_SYSLOG_LOGGING)
+#include <syslog.h>
+#define ALOGE(...) syslog(LOG_ERR,     "LOC_LOGE: " __VA_ARGS__);
+#define ALOGW(...) syslog(LOG_WARNING, "LOC_LOGW: " __VA_ARGS__);
+#define ALOGI(...) syslog(LOG_NOTICE,  "LOC_LOGI: " __VA_ARGS__);
+#define ALOGD(...) syslog(LOG_DEBUG,   "LOC_LOGD: " __VA_ARGS__);
+#define ALOGV(...) syslog(LOG_NOTICE,  "LOC_LOGV: " __VA_ARGS__);
+#else /* FEATURE_EXTERNAL_AP */
+#define TS_PRINTF(format, x...)                                  \
+{                                                                \
+    struct timeval tv;                                           \
+    struct timezone tz;                                          \
+    int hh, mm, ss;                                              \
+    gettimeofday(&tv, &tz);                                      \
+    hh = tv.tv_sec/3600%24;                                      \
+    mm = (tv.tv_sec%3600)/60;                                    \
+    ss = tv.tv_sec%60;                                           \
+    fprintf(stdout,"%02d:%02d:%02d.%06ld]" format "\n", hh, mm, ss, tv.tv_usec, ##x);    \
+}
+
+#define ALOGE(format, x...) TS_PRINTF("E/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#define ALOGW(format, x...) TS_PRINTF("W/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#define ALOGI(format, x...) TS_PRINTF("I/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#define ALOGD(format, x...) TS_PRINTF("D/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#define ALOGV(format, x...) TS_PRINTF("V/%s (%d): " format , LOG_TAG, getpid(), ##x)
+#endif /* FEATURE_EXTERNAL_AP */
+
+#endif /* #if defined (USE_ANDROID_LOGGING) || defined (ANDROID) */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/*=============================================================================
+ *
+ *                         LOC LOGGER TYPE DECLARATION
+ *
+ *============================================================================*/
+/* LOC LOGGER */
+typedef struct loc_logger_s
+{
+  unsigned long  DEBUG_LEVEL;
+  unsigned long  TIMESTAMP;
+  bool           LOG_BUFFER_ENABLE;
+} loc_logger_s_type;
+
+
+/*=============================================================================
+ *
+ *                               EXTERNAL DATA
+ *
+ *============================================================================*/
+
+// Logging Improvements
+extern const char *loc_logger_boolStr[];
+
+extern loc_logger_s_type loc_logger;
+extern const char *boolStr[];
+extern const char VOID_RET[];
+extern const char FROM_AFW[];
+extern const char TO_MODEM[];
+extern const char FROM_MODEM[];
+extern const char TO_AFW[];
+extern const char EXIT_TAG[];
+extern const char ENTRY_TAG[];
+extern const char EXIT_ERROR_TAG[];
+
+#define BUILD_TYPE_PROP_NA 0
+#define BUILD_TYPE_PROP_USER 1
+#define BUILD_TYPE_PROP_USERDEBUG 2
+#define BUILD_TYPE_PROP_INVALID 3
+extern int build_type_prop;
+
+/*=============================================================================
+ *
+ *                        MODULE EXPORTED FUNCTIONS
+ *
+ *============================================================================*/
+inline void loc_logger_init(unsigned long debug, unsigned long timestamp)
+{
+    loc_logger.DEBUG_LEVEL = debug;
+
+    if (BUILD_TYPE_PROP_NA == build_type_prop) {
+        char value[PROPERTY_VALUE_MAX] = "NA";
+        property_get("ro.build.type", value, "userdebug");
+        if (0 == strcmp(value, "user")) {
+            build_type_prop = BUILD_TYPE_PROP_USER;
+        } else if (0 == strcmp(value, "userdebug")) {
+            build_type_prop = BUILD_TYPE_PROP_USERDEBUG;
+        } else {
+            build_type_prop = BUILD_TYPE_PROP_INVALID;
+        }
+    }
+
+    if (BUILD_TYPE_PROP_USER == build_type_prop) {
+        // force user builds to 2 or less
+        if (loc_logger.DEBUG_LEVEL > 2) {
+            loc_logger.DEBUG_LEVEL = 2;
+        }
+     }
+
+    loc_logger.TIMESTAMP = timestamp;
+}
+
+inline void log_buffer_init(bool enabled) {
+    loc_logger.LOG_BUFFER_ENABLE = enabled;
+}
+extern void log_tag_level_map_init();
+extern int get_tag_log_level(const char* tag);
+extern char* get_timestamp(char* str, unsigned long buf_size);
+extern void log_buffer_insert(char *str, unsigned long buf_size, int level);
+/*=============================================================================
+ *
+ *                          LOGGING BUFFER MACROS
+ *
+ *============================================================================*/
+#ifndef LOG_NDEBUG
+#define LOG_NDEBUG 0
+#endif
+#define TOTAL_LOG_LEVELS 5
+#define LOGGING_BUFFER_MAX_LEN 1024
+#define IF_LOG_BUFFER_ENABLE if (loc_logger.LOG_BUFFER_ENABLE)
+#define INSERT_BUFFER(flag, level, format, x...)                                              \
+{                                                                                             \
+    IF_LOG_BUFFER_ENABLE {                                                                    \
+        if (flag == 0) {                                                                      \
+            char timestr[32];                                                                 \
+            get_timestamp(timestr, sizeof(timestr));                                          \
+            char log_str[LOGGING_BUFFER_MAX_LEN];                                             \
+            snprintf(log_str, LOGGING_BUFFER_MAX_LEN, "%s %d %ld %s :" format "\n",           \
+                    timestr, getpid(), syscall(SYS_gettid), LOG_TAG==NULL ? "": LOG_TAG, ##x);\
+            log_buffer_insert(log_str, sizeof(log_str), level);                               \
+        }                                                                                     \
+    }                                                                                         \
+}
+
+#ifndef DEBUG_DMN_LOC_API
+
+/* LOGGING MACROS */
+/*loc_logger.DEBUG_LEVEL is initialized to 0xff in loc_cfg.cpp
+  if that value remains unchanged, it means gps.conf did not
+  provide a value and we default to the initial value to use
+  Android's logging levels*/
+
+
+/* Tag based logging control MACROS */
+/* The logic is like this:
+ * 1, LOCAL_LOG_LEVEL is defined as a static variable in log_util.h,
+ *    then all source files which includes log_util.h will have its own LOCAL_LOG_LEVEL variable;
+ * 2, For each source file,
+ *    2.1, First time when LOC_LOG* is invoked(its LOCAL_LOG_LEVEL == -1),
+ *         Set the tag based log level according to the <tag, level> map;
+ *         If this tag isn't found in map, set local debug level as global loc_logger.DEBUG_LEVEL;
+ *    2.2, If not the first time, use its LOCAL_LOG_LEVEL as the debug level of this tag.
+*/
+static int LOCAL_LOG_LEVEL = -1;
+#define IF_LOC_LOG(x) \
+    if (((LOCAL_LOG_LEVEL == -1 && (LOCAL_LOG_LEVEL = get_tag_log_level(LOG_TAG)) >= x) ||\
+            LOCAL_LOG_LEVEL >= x) && LOCAL_LOG_LEVEL <= 5)
+
+#define IF_LOC_LOGE IF_LOC_LOG(1)
+#define IF_LOC_LOGW IF_LOC_LOG(2)
+#define IF_LOC_LOGI IF_LOC_LOG(3)
+#define IF_LOC_LOGD IF_LOC_LOG(4)
+#define IF_LOC_LOGV IF_LOC_LOG(5)
+
+#define LOC_LOGE(...) IF_LOC_LOGE { ALOGE(__VA_ARGS__); INSERT_BUFFER(LOG_NDEBUG, 0, __VA_ARGS__);}
+#define LOC_LOGW(...) IF_LOC_LOGW { ALOGW(__VA_ARGS__); INSERT_BUFFER(LOG_NDEBUG, 1, __VA_ARGS__);}
+#define LOC_LOGI(...) IF_LOC_LOGI { ALOGI(__VA_ARGS__); INSERT_BUFFER(LOG_NDEBUG, 2, __VA_ARGS__);}
+#define LOC_LOGD(...) IF_LOC_LOGD { ALOGD(__VA_ARGS__); INSERT_BUFFER(LOG_NDEBUG, 3, __VA_ARGS__);}
+#define LOC_LOGV(...) IF_LOC_LOGV { ALOGV(__VA_ARGS__); INSERT_BUFFER(LOG_NDEBUG, 4, __VA_ARGS__);}
+
+#else /* DEBUG_DMN_LOC_API */
+
+#define LOC_LOGE(...) ALOGE(__VA_ARGS__)
+#define LOC_LOGW(...) ALOGW(__VA_ARGS__)
+#define LOC_LOGI(...) ALOGI(__VA_ARGS__)
+#define LOC_LOGD(...) ALOGD(__VA_ARGS__)
+#define LOC_LOGV(...) ALOGV(__VA_ARGS__)
+
+#endif /* DEBUG_DMN_LOC_API */
+
+/*=============================================================================
+ *
+ *                          LOGGING IMPROVEMENT MACROS
+ *
+ *============================================================================*/
+#define LOG_(LOC_LOG, ID, WHAT, SPEC, VAL)                                    \
+    do {                                                                      \
+        if (loc_logger.TIMESTAMP) {                                           \
+            char ts[32];                                                      \
+            LOC_LOG("[%s] %s %s line %d " #SPEC,                              \
+                     get_timestamp(ts, sizeof(ts)), ID, WHAT, __LINE__, VAL); \
+        } else {                                                              \
+            LOC_LOG("%s %s line %d " #SPEC,                                   \
+                     ID, WHAT, __LINE__, VAL);                                \
+        }                                                                     \
+    } while(0)
+
+#define LOC_LOG_HEAD(fmt) "%s:%d] " fmt
+#define LOC_LOGv(fmt,...) LOC_LOGV(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define LOC_LOGw(fmt,...) LOC_LOGW(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define LOC_LOGi(fmt,...) LOC_LOGI(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define LOC_LOGd(fmt,...) LOC_LOGD(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+#define LOC_LOGe(fmt,...) LOC_LOGE(LOC_LOG_HEAD(fmt), __FUNCTION__, __LINE__, ##__VA_ARGS__)
+
+#define LOG_I(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGI, ID, WHAT, SPEC, VAL)
+#define LOG_V(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGV, ID, WHAT, SPEC, VAL)
+#define LOG_E(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGE, ID, WHAT, SPEC, VAL)
+#define LOG_D(ID, WHAT, SPEC, VAL) LOG_(LOC_LOGD, ID, WHAT, SPEC, VAL)
+
+#define ENTRY_LOG() LOG_V(ENTRY_TAG, __FUNCTION__, %s, "")
+#define EXIT_LOG(SPEC, VAL) LOG_V(EXIT_TAG, __FUNCTION__, SPEC, VAL)
+#define EXIT_LOG_WITH_ERROR(SPEC, VAL)                       \
+    if (VAL != 0) {                                          \
+        LOG_E(EXIT_ERROR_TAG, __FUNCTION__, SPEC, VAL);          \
+    } else {                                                 \
+        LOG_V(EXIT_TAG, __FUNCTION__, SPEC, VAL);                \
+    }
+
+
+// Used for logging callflow from Android Framework
+#define ENTRY_LOG_CALLFLOW() LOG_I(FROM_AFW, __FUNCTION__, %s, "")
+// Used for logging callflow to Modem
+#define EXIT_LOG_CALLFLOW(SPEC, VAL) LOG_I(TO_MODEM, __FUNCTION__, SPEC, VAL)
+// Used for logging callflow from Modem(TO_MODEM, __FUNCTION__, %s, "")
+#define MODEM_LOG_CALLFLOW(SPEC, VAL) LOG_I(FROM_MODEM, __FUNCTION__, SPEC, VAL)
+// Used for logging high frequency callflow from Modem(TO_MODEM, __FUNCTION__, %s, "")
+#define MODEM_LOG_CALLFLOW_DEBUG(SPEC, VAL) LOG_D(FROM_MODEM, __FUNCTION__, SPEC, VAL)
+// Used for logging callflow to Android Framework
+#define CALLBACK_LOG_CALLFLOW(CB, SPEC, VAL) LOG_I(TO_AFW, CB, SPEC, VAL)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LOG_UTIL_H__
diff --git a/gps/utils/msg_q.c b/gps/utils/msg_q.c
new file mode 100644
index 0000000..3383960
--- /dev/null
+++ b/gps/utils/msg_q.c
@@ -0,0 +1,380 @@
+/* Copyright (c) 2011-2012, 2014, 2017 The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation, nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Uncomment to log verbose logs
+#define LOG_NDEBUG 1
+#define LOG_TAG "LocSvc_utils_q"
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <loc_pla.h>
+#include <log_util.h>
+#include "linked_list.h"
+#include "msg_q.h"
+
+typedef struct msg_q {
+   void* msg_list;                  /* Linked list to store information */
+   pthread_cond_t  list_cond;       /* Condition variable for waiting on msg queue */
+   pthread_mutex_t list_mutex;      /* Mutex for exclusive access to message queue */
+   int unblocked;                   /* Has this message queue been unblocked? */
+} msg_q;
+
+/*===========================================================================
+FUNCTION    convert_linked_list_err_type
+
+DESCRIPTION
+   Converts from one set of enum values to another.
+
+   linked_list_val: Value to convert to msg_q_enum_type
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Corresponding linked_list_enum_type in msg_q_enum_type
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+static msq_q_err_type convert_linked_list_err_type(linked_list_err_type linked_list_val)
+{
+   switch( linked_list_val )
+   {
+   case eLINKED_LIST_SUCCESS:
+      return eMSG_Q_SUCCESS;
+   case eLINKED_LIST_INVALID_PARAMETER:
+      return eMSG_Q_INVALID_PARAMETER;
+   case eLINKED_LIST_INVALID_HANDLE:
+      return eMSG_Q_INVALID_HANDLE;
+   case eLINKED_LIST_UNAVAILABLE_RESOURCE:
+      return eMSG_Q_UNAVAILABLE_RESOURCE;
+   case eLINKED_LIST_INSUFFICIENT_BUFFER:
+      return eMSG_Q_INSUFFICIENT_BUFFER;
+
+   case eLINKED_LIST_FAILURE_GENERAL:
+   default:
+      return eMSG_Q_FAILURE_GENERAL;
+   }
+}
+
+/* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */
+
+/*===========================================================================
+
+  FUNCTION:   msg_q_init
+
+  ===========================================================================*/
+msq_q_err_type msg_q_init(void** msg_q_data)
+{
+   if( msg_q_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_PARAMETER;
+   }
+
+   msg_q* tmp_msg_q;
+   tmp_msg_q = (msg_q*)calloc(1, sizeof(msg_q));
+   if( tmp_msg_q == NULL )
+   {
+      LOC_LOGE("%s: Unable to allocate space for message queue!\n", __FUNCTION__);
+      return eMSG_Q_FAILURE_GENERAL;
+   }
+
+   if( linked_list_init(&tmp_msg_q->msg_list) != 0 )
+   {
+      LOC_LOGE("%s: Unable to initialize storage list!\n", __FUNCTION__);
+      free(tmp_msg_q);
+      return eMSG_Q_FAILURE_GENERAL;
+   }
+
+   if( pthread_mutex_init(&tmp_msg_q->list_mutex, NULL) != 0 )
+   {
+      LOC_LOGE("%s: Unable to initialize list mutex!\n", __FUNCTION__);
+      linked_list_destroy(&tmp_msg_q->msg_list);
+      free(tmp_msg_q);
+      return eMSG_Q_FAILURE_GENERAL;
+   }
+
+   if( pthread_cond_init(&tmp_msg_q->list_cond, NULL) != 0 )
+   {
+      LOC_LOGE("%s: Unable to initialize msg q cond var!\n", __FUNCTION__);
+      linked_list_destroy(&tmp_msg_q->msg_list);
+      pthread_mutex_destroy(&tmp_msg_q->list_mutex);
+      free(tmp_msg_q);
+      return eMSG_Q_FAILURE_GENERAL;
+   }
+
+   tmp_msg_q->unblocked = 0;
+
+   *msg_q_data = tmp_msg_q;
+
+   return eMSG_Q_SUCCESS;
+}
+
+/*===========================================================================
+
+  FUNCTION:   msg_q_init2
+
+  ===========================================================================*/
+const void* msg_q_init2()
+{
+  void* q = NULL;
+  if (eMSG_Q_SUCCESS != msg_q_init(&q)) {
+    q = NULL;
+  }
+  return q;
+}
+
+/*===========================================================================
+
+  FUNCTION:   msg_q_destroy
+
+  ===========================================================================*/
+msq_q_err_type msg_q_destroy(void** msg_q_data)
+{
+   if( msg_q_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_HANDLE;
+   }
+
+   msg_q* p_msg_q = (msg_q*)*msg_q_data;
+
+   linked_list_destroy(&p_msg_q->msg_list);
+   pthread_mutex_destroy(&p_msg_q->list_mutex);
+   pthread_cond_destroy(&p_msg_q->list_cond);
+
+   p_msg_q->unblocked = 0;
+
+   free(*msg_q_data);
+   *msg_q_data = NULL;
+
+   return eMSG_Q_SUCCESS;
+}
+
+/*===========================================================================
+
+  FUNCTION:   msg_q_snd
+
+  ===========================================================================*/
+msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*))
+{
+   msq_q_err_type rv;
+   if( msg_q_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_HANDLE;
+   }
+   if( msg_obj == NULL )
+   {
+      LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_PARAMETER;
+   }
+
+   msg_q* p_msg_q = (msg_q*)msg_q_data;
+
+   pthread_mutex_lock(&p_msg_q->list_mutex);
+   LOC_LOGV("%s: Sending message with handle = %p\n", __FUNCTION__, msg_obj);
+
+   if( p_msg_q->unblocked )
+   {
+      LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
+      pthread_mutex_unlock(&p_msg_q->list_mutex);
+      return eMSG_Q_UNAVAILABLE_RESOURCE;
+   }
+
+   rv = convert_linked_list_err_type(linked_list_add(p_msg_q->msg_list, msg_obj, dealloc));
+
+   /* Show data is in the message queue. */
+   pthread_cond_signal(&p_msg_q->list_cond);
+
+   pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+   LOC_LOGV("%s: Finished Sending message with handle = %p\n", __FUNCTION__, msg_obj);
+
+   return rv;
+}
+
+/*===========================================================================
+
+  FUNCTION:   msg_q_rcv
+
+  ===========================================================================*/
+msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj)
+{
+   msq_q_err_type rv;
+   if( msg_q_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_HANDLE;
+   }
+
+   if( msg_obj == NULL )
+   {
+      LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_PARAMETER;
+   }
+
+   msg_q* p_msg_q = (msg_q*)msg_q_data;
+
+   pthread_mutex_lock(&p_msg_q->list_mutex);
+
+   if( p_msg_q->unblocked )
+   {
+      LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
+      pthread_mutex_unlock(&p_msg_q->list_mutex);
+      return eMSG_Q_UNAVAILABLE_RESOURCE;
+   }
+
+   /* Wait for data in the message queue */
+   while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked )
+   {
+      pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex);
+   }
+
+   rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
+
+   pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+   LOC_LOGV("%s: Received message %p rv = %d\n", __FUNCTION__, *msg_obj, rv);
+
+   return rv;
+}
+
+/*===========================================================================
+
+  FUNCTION:   msg_q_rmv
+
+  ===========================================================================*/
+msq_q_err_type msg_q_rmv(void* msg_q_data, void** msg_obj)
+{
+   msq_q_err_type rv;
+   if (msg_q_data == NULL) {
+      LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_HANDLE;
+   }
+
+   if (msg_obj == NULL) {
+      LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_PARAMETER;
+   }
+
+   msg_q* p_msg_q = (msg_q*)msg_q_data;
+
+   pthread_mutex_lock(&p_msg_q->list_mutex);
+
+   if (p_msg_q->unblocked) {
+      LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
+      pthread_mutex_unlock(&p_msg_q->list_mutex);
+      return eMSG_Q_UNAVAILABLE_RESOURCE;
+   }
+
+   if (linked_list_empty(p_msg_q->msg_list)) {
+      LOC_LOGW("%s: list is empty !!\n", __FUNCTION__);
+      pthread_mutex_unlock(&p_msg_q->list_mutex);
+      return eLINKED_LIST_EMPTY;
+   }
+
+   rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
+
+   pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+   LOC_LOGV("%s: Removed message %p rv = %d\n", __FUNCTION__, *msg_obj, rv);
+
+   return rv;
+}
+
+
+
+/*===========================================================================
+
+  FUNCTION:   msg_q_flush
+
+  ===========================================================================*/
+msq_q_err_type msg_q_flush(void* msg_q_data)
+{
+   msq_q_err_type rv;
+   if ( msg_q_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_HANDLE;
+   }
+
+   msg_q* p_msg_q = (msg_q*)msg_q_data;
+
+   LOC_LOGD("%s: Flushing Message Queue\n", __FUNCTION__);
+
+   pthread_mutex_lock(&p_msg_q->list_mutex);
+
+   /* Remove all elements from the list */
+   rv = convert_linked_list_err_type(linked_list_flush(p_msg_q->msg_list));
+
+   pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+   LOC_LOGD("%s: Message Queue flushed\n", __FUNCTION__);
+
+   return rv;
+}
+
+/*===========================================================================
+
+  FUNCTION:   msg_q_unblock
+
+  ===========================================================================*/
+msq_q_err_type msg_q_unblock(void* msg_q_data)
+{
+   if ( msg_q_data == NULL )
+   {
+      LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
+      return eMSG_Q_INVALID_HANDLE;
+   }
+
+   msg_q* p_msg_q = (msg_q*)msg_q_data;
+   pthread_mutex_lock(&p_msg_q->list_mutex);
+
+   if( p_msg_q->unblocked )
+   {
+      LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
+      pthread_mutex_unlock(&p_msg_q->list_mutex);
+      return eMSG_Q_UNAVAILABLE_RESOURCE;
+   }
+
+   LOC_LOGD("%s: Unblocking Message Queue\n", __FUNCTION__);
+   /* Unblocking message queue */
+   p_msg_q->unblocked = 1;
+
+   /* Allow all the waiters to wake up */
+   pthread_cond_broadcast(&p_msg_q->list_cond);
+
+   pthread_mutex_unlock(&p_msg_q->list_mutex);
+
+   LOC_LOGD("%s: Message Queue unblocked\n", __FUNCTION__);
+
+   return eMSG_Q_SUCCESS;
+}
diff --git a/gps/utils/msg_q.h b/gps/utils/msg_q.h
new file mode 100644
index 0000000..16df494
--- /dev/null
+++ b/gps/utils/msg_q.h
@@ -0,0 +1,230 @@
+/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __MSG_Q_H__
+#define __MSG_Q_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <stdlib.h>
+
+/** Linked List Return Codes */
+typedef enum
+{
+  eMSG_Q_SUCCESS                             = 0,
+     /**< Request was successful. */
+  eMSG_Q_FAILURE_GENERAL                     = -1,
+     /**< Failed because of a general failure. */
+  eMSG_Q_INVALID_PARAMETER                   = -2,
+     /**< Failed because the request contained invalid parameters. */
+  eMSG_Q_INVALID_HANDLE                      = -3,
+     /**< Failed because an invalid handle was specified. */
+  eMSG_Q_UNAVAILABLE_RESOURCE                = -4,
+     /**< Failed because an there were not enough resources. */
+  eMSG_Q_INSUFFICIENT_BUFFER                 = -5,
+     /**< Failed because an the supplied buffer was too small. */
+}msq_q_err_type;
+
+/*===========================================================================
+FUNCTION    msg_q_init
+
+DESCRIPTION
+   Initializes internal structures for message queue.
+
+   msg_q_data: pointer to an opaque Q handle to be returned; NULL if fails
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_init(void** msg_q_data);
+
+/*===========================================================================
+FUNCTION    msg_q_init2
+
+DESCRIPTION
+   Initializes internal structures for message queue.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   opaque handle to the Q created; NULL if create fails
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+const void* msg_q_init2();
+
+/*===========================================================================
+FUNCTION    msg_q_destroy
+
+DESCRIPTION
+   Releases internal structures for message queue.
+
+   msg_q_data: State of message queue to be released.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_destroy(void** msg_q_data);
+
+/*===========================================================================
+FUNCTION    msg_q_snd
+
+DESCRIPTION
+   Sends data to the message queue. The passed in data pointer
+   is not modified or freed. Passed in msg_obj is expected to live throughout
+   the use of the msg_q (i.e. data is not allocated internally)
+
+   msg_q_data: Message Queue to add the element to.
+   msgp:       Pointer to data to add into message queue.
+   dealloc:    Function used to deallocate memory for this element. Pass NULL
+               if you do not want data deallocated during a flush operation
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*));
+
+/*===========================================================================
+FUNCTION    msg_q_rcv
+
+DESCRIPTION
+   Retrieves data from the message queue. msg_obj is the oldest message received
+   and pointer is simply removed from message queue.
+
+   msg_q_data: Message Queue to copy data from into msgp.
+   msg_obj:    Pointer to space to copy msg_q contents to.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj);
+
+/*===========================================================================
+FUNCTION    msg_q_rmv
+
+DESCRIPTION
+   Remove data from the message queue. msg_obj is the oldest message received
+   and pointer is simply removed from message queue.
+
+   msg_q_data: Message Queue to copy data from into msgp.
+   msg_obj:    Pointer to space to copy msg_q contents to.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_rmv(void* msg_q_data, void** msg_obj);
+
+
+/*===========================================================================
+FUNCTION    msg_q_flush
+
+DESCRIPTION
+   Function removes all elements from the message queue.
+
+   msg_q_data: Message Queue to remove elements from.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_flush(void* msg_q_data);
+
+/*===========================================================================
+FUNCTION    msg_q_unblock
+
+DESCRIPTION
+   This function will stop use of the message queue. All waiters will wake up
+   and likely receive nothing from the queue resulting in a negative return
+   value. The message queue can no longer be used until it is destroyed
+   and initialized again after calling this function.
+
+   msg_q_data: Message queue to unblock.
+
+DEPENDENCIES
+   N/A
+
+RETURN VALUE
+   Look at error codes above.
+
+SIDE EFFECTS
+   N/A
+
+===========================================================================*/
+msq_q_err_type msg_q_unblock(void* msg_q_data);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MSG_Q_H__ */