Merge "Add emergency session extension duration (framework)"
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index b531325..866634e 100644
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -16,9 +16,6 @@
 
 package com.android.internal.location;
 
-import java.io.UnsupportedEncodingException;
-import java.util.concurrent.TimeUnit;
-
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -26,20 +23,23 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.location.LocationManager;
 import android.location.INetInitiatedListener;
+import android.location.LocationManager;
+import android.os.RemoteException;
 import android.os.SystemClock;
-import android.telephony.TelephonyManager;
+import android.os.UserHandle;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.PhoneStateListener;
-import android.os.RemoteException;
-import android.os.UserHandle;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 
-import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.telephony.GsmAlphabet;
 
+import java.io.UnsupportedEncodingException;
+import java.util.concurrent.TimeUnit;
+
 /**
  * A GPS Network-initiated Handler class used by LocationManager.
  *
@@ -92,9 +92,6 @@
     public static final int GPS_ENC_SUPL_UCS2 = 3;
     public static final int GPS_ENC_UNKNOWN = -1;
 
-    // Limit on SUPL NI emergency mode time extension after emergency sessions ends
-    private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
-
     private final Context mContext;
     private final TelephonyManager mTelephonyManager;
     private final PhoneStateListener mPhoneStateListener;
@@ -252,19 +249,9 @@
     }
 
     public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) {
-        if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
-            Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
-                    + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
-            emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
-        } else if (emergencyExtensionSeconds < 0) {
-            Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
-                    + " is negative, reset to zero.");
-            emergencyExtensionSeconds = 0;
-        }
         mEmergencyExtensionMillis = TimeUnit.SECONDS.toMillis(emergencyExtensionSeconds);
     }
 
-
     // Handles NI events from HAL
     public void handleNiNotification(GpsNiNotification notif) {
         if (DEBUG) Log.d(TAG, "in handleNiNotification () :"
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
new file mode 100644
index 0000000..29465ad
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.content.Context;
+import android.os.PersistableBundle;
+import android.os.SystemProperties;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+/**
+ * A utility class to hold GNSS configuration properties.
+ *
+ * The trigger to load/reload the configuration parameters should be managed by the class
+ * that owns an instance of this class.
+ *
+ * Instances of this class are not thread-safe and should either be used from a single thread
+ * or with external synchronization when used by multiple threads.
+ */
+class GnssConfiguration {
+    private static final String TAG = "GnssConfiguration";
+
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
+    private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
+
+    // config.xml properties
+    private static final String CONFIG_SUPL_HOST = "SUPL_HOST";
+    private static final String CONFIG_SUPL_PORT = "SUPL_PORT";
+    private static final String CONFIG_C2K_HOST = "C2K_HOST";
+    private static final String CONFIG_C2K_PORT = "C2K_PORT";
+    private static final String CONFIG_SUPL_VER = "SUPL_VER";
+    private static final String CONFIG_SUPL_MODE = "SUPL_MODE";
+    private static final String CONFIG_SUPL_ES = "SUPL_ES";
+    private static final String CONFIG_LPP_PROFILE = "LPP_PROFILE";
+    private static final String CONFIG_A_GLONASS_POS_PROTOCOL_SELECT =
+            "A_GLONASS_POS_PROTOCOL_SELECT";
+    private static final String CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL =
+            "USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL";
+    private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
+    private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
+
+    // Limit on NI emergency mode time extension after emergency sessions ends
+    private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
+
+    // Persist property for LPP_PROFILE
+    static final String LPP_PROFILE = "persist.sys.gps.lpp";
+
+    // Represents an HAL interface version. Instances of this class are created in the JNI layer
+    // and returned through native methods.
+    private static class HalInterfaceVersion {
+        final int mMajor;
+        final int mMinor;
+
+        HalInterfaceVersion(int major, int minor) {
+            mMajor = major;
+            mMinor = minor;
+        }
+    }
+
+    /**
+     * Properties loaded from PROPERTIES_FILE.
+     */
+    private Properties mProperties;
+
+    private int mEsExtensionSec = 0;
+
+    private final Context mContext;
+
+    GnssConfiguration(Context context) {
+        mContext = context;
+        mProperties = new Properties();
+    }
+
+    /**
+     * Returns the full set of properties loaded.
+     */
+    Properties getProperties() {
+        return mProperties;
+    }
+
+    /**
+     * Returns the value of config parameter ES_EXTENSION_SEC. The value is range checked
+     * and constrained to min/max limits.
+     */
+    int getEsExtensionSec() {
+        return mEsExtensionSec;
+    }
+
+    /**
+     * Returns the value of config parameter SUPL_HOST or {@code null} if no value is
+     * provided.
+     */
+    String getSuplHost() {
+        return mProperties.getProperty(CONFIG_SUPL_HOST);
+    }
+
+    /**
+     * Returns the value of config parameter SUPL_PORT or {@code defaultPort} if no value is
+     * provided or if there is an error parsing the configured value.
+     */
+    int getSuplPort(int defaultPort) {
+        return getIntConfig(CONFIG_SUPL_PORT, defaultPort);
+    }
+
+    /**
+     * Returns the value of config parameter C2K_HOST or {@code null} if no value is
+     * provided.
+     */
+    String getC2KHost() {
+        return mProperties.getProperty(CONFIG_C2K_HOST);
+    }
+
+    /**
+     * Returns the value of config parameter C2K_PORT or {@code defaultPort} if no value is
+     * provided or if there is an error parsing the configured value.
+     */
+    int getC2KPort(int defaultPort) {
+        return getIntConfig(CONFIG_C2K_PORT, defaultPort);
+    }
+
+    /**
+     * Returns the value of config parameter SUPL_MODE or {@code defaultMode} if no value is
+     * provided or if there is an error parsing the configured value.
+     */
+    int getSuplMode(int defaultMode) {
+        return getIntConfig(CONFIG_SUPL_MODE, defaultMode);
+    }
+
+    /**
+     * Returns the value of config parameter SUPL_ES or {@code defaultSuplEs} if no value is
+     * provided or if there is an error parsing the configured value.
+     */
+    int getSuplEs(int defaulSuplEs) {
+        return getIntConfig(CONFIG_SUPL_ES, defaulSuplEs);
+    }
+
+    /**
+     * Returns the value of config parameter LPP_PROFILE or {@code null} if no value is
+     * provided.
+     */
+    String getLppProfile() {
+        return mProperties.getProperty(CONFIG_LPP_PROFILE);
+    }
+
+    /**
+     * Updates the GNSS HAL satellite blacklist.
+     */
+    void setSatelliteBlacklist(int[] constellations, int[] svids) {
+        native_set_satellite_blacklist(constellations, svids);
+    }
+
+    interface SetCarrierProperty {
+        boolean set(int value);
+    }
+
+    /**
+     * Loads the GNSS properties from carrier config file followed by the properties from
+     * gps debug config file.
+     */
+    void reloadGpsProperties() {
+        if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + mProperties.size());
+        loadPropertiesFromCarrierConfig();
+
+        String lpp_prof = SystemProperties.get(LPP_PROFILE);
+        if (!TextUtils.isEmpty(lpp_prof)) {
+            // override default value of this if lpp_prof is not empty
+            mProperties.setProperty(CONFIG_LPP_PROFILE, lpp_prof);
+        }
+        /*
+         * Overlay carrier properties from a debug configuration file.
+         */
+        loadPropertiesFromGpsDebugConfig(mProperties);
+
+        mEsExtensionSec = getRangeCheckedConfigEsExtensionSec();
+
+        final HalInterfaceVersion gnssConfigurationIfaceVersion =
+                native_get_gnss_configuration_version();
+        if (gnssConfigurationIfaceVersion != null) {
+            // Set to a range checked value.
+            if (isConfigEsExtensionSecSupported(gnssConfigurationIfaceVersion)
+                    && !native_set_es_extension_sec(mEsExtensionSec)) {
+                Log.e(TAG, "Unable to set " + CONFIG_ES_EXTENSION_SEC + ": " + mEsExtensionSec);
+            }
+
+            Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
+                {
+                    put(CONFIG_SUPL_VER, GnssConfiguration::native_set_supl_version);
+                    put(CONFIG_SUPL_MODE, GnssConfiguration::native_set_supl_mode);
+
+                    if (isConfigSuplEsSupported(gnssConfigurationIfaceVersion)) {
+                        put(CONFIG_SUPL_ES, GnssConfiguration::native_set_supl_es);
+                    }
+
+                    put(CONFIG_LPP_PROFILE, GnssConfiguration::native_set_lpp_profile);
+                    put(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT,
+                            GnssConfiguration::native_set_gnss_pos_protocol_select);
+                    put(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL,
+                            GnssConfiguration::native_set_emergency_supl_pdn);
+
+                    if (isConfigGpsLockSupported(gnssConfigurationIfaceVersion)) {
+                        put(CONFIG_GPS_LOCK, GnssConfiguration::native_set_gps_lock);
+                    }
+                }
+            };
+
+            for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
+                String propertyName = entry.getKey();
+                String propertyValueString = mProperties.getProperty(propertyName);
+                if (propertyValueString != null) {
+                    try {
+                        int propertyValueInt = Integer.decode(propertyValueString);
+                        boolean result = entry.getValue().set(propertyValueInt);
+                        if (!result) {
+                            Log.e(TAG, "Unable to set " + propertyName);
+                        }
+                    } catch (NumberFormatException e) {
+                        Log.e(TAG, "Unable to parse propertyName: " + propertyValueString);
+                    }
+                }
+            }
+        } else if (DEBUG) {
+            Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
+                    + " supported");
+        }
+    }
+
+    /**
+     * Loads GNSS properties from carrier config file.
+     */
+    void loadPropertiesFromCarrierConfig() {
+        CarrierConfigManager configManager = (CarrierConfigManager)
+                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (configManager == null) {
+            return;
+        }
+        PersistableBundle configs = configManager.getConfigForSubId(
+                SubscriptionManager.getDefaultDataSubscriptionId());
+        if (configs == null) {
+            if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
+            configs = CarrierConfigManager.getDefaultConfig();
+        }
+        for (String configKey : configs.keySet()) {
+            if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) {
+                String key = configKey
+                        .substring(CarrierConfigManager.Gps.KEY_PREFIX.length())
+                        .toUpperCase();
+                Object value = configs.get(configKey);
+                if (value instanceof String) {
+                    // All GPS properties are of String type; convert so.
+                    if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value);
+                    mProperties.setProperty(key, (String) value);
+                }
+            }
+        }
+    }
+
+    private void loadPropertiesFromGpsDebugConfig(Properties properties) {
+        try {
+            File file = new File(DEBUG_PROPERTIES_FILE);
+            FileInputStream stream = null;
+            try {
+                stream = new FileInputStream(file);
+                properties.load(stream);
+            } finally {
+                IoUtils.closeQuietly(stream);
+            }
+        } catch (IOException e) {
+            if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
+        }
+    }
+
+    private int getRangeCheckedConfigEsExtensionSec() {
+        int emergencyExtensionSeconds = getIntConfig(CONFIG_ES_EXTENSION_SEC, 0);
+        if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
+            Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
+                    + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
+            emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
+        } else if (emergencyExtensionSeconds < 0) {
+            Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
+                    + " is negative, reset to zero.");
+            emergencyExtensionSeconds = 0;
+        }
+        return emergencyExtensionSeconds;
+    }
+
+    private int getIntConfig(String configParameter, int defaultValue) {
+        String valueString = mProperties.getProperty(configParameter);
+        if (TextUtils.isEmpty(valueString)) {
+            return defaultValue;
+        }
+        try {
+            return Integer.parseInt(valueString);
+        } catch (NumberFormatException e) {
+            Log.e(TAG, "Unable to parse config parameter " + configParameter + " value: "
+                    + valueString + ". Using default value: " + defaultValue);
+            return defaultValue;
+        }
+    }
+
+    private static boolean isConfigEsExtensionSecSupported(
+            HalInterfaceVersion gnssConfiguartionIfaceVersion) {
+        // ES_EXTENSION_SEC is introduced in @2.0::IGnssConfiguration.hal
+        return gnssConfiguartionIfaceVersion.mMajor >= 2;
+    }
+
+    private static boolean isConfigSuplEsSupported(
+            HalInterfaceVersion gnssConfiguartionIfaceVersion) {
+        // SUPL_ES is deprecated in @2.0::IGnssConfiguration.hal
+        return gnssConfiguartionIfaceVersion.mMajor < 2;
+    }
+
+    private static boolean isConfigGpsLockSupported(
+            HalInterfaceVersion gnssConfiguartionIfaceVersion) {
+        // GPS_LOCK is deprecated in @2.0::IGnssConfiguration.hal
+        return gnssConfiguartionIfaceVersion.mMajor < 2;
+    }
+
+    private static native HalInterfaceVersion native_get_gnss_configuration_version();
+
+    private static native boolean native_set_supl_version(int version);
+
+    private static native boolean native_set_supl_mode(int mode);
+
+    private static native boolean native_set_supl_es(int es);
+
+    private static native boolean native_set_lpp_profile(int lppProfile);
+
+    private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
+
+    private static native boolean native_set_gps_lock(int gpsLock);
+
+    private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
+
+    private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
+
+    private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds);
+}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 05d77ab..3c81a45 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -74,12 +74,7 @@
 import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
 import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
 
-import libcore.io.IoUtils;
-
-import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -87,11 +82,7 @@
 import java.lang.annotation.Target;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
 
 /**
  * A GNSS implementation of LocationProvider used by LocationManager.
@@ -147,7 +138,6 @@
     private static final int LOCATION_HAS_SPEED_ACCURACY = 64;
     private static final int LOCATION_HAS_BEARING_ACCURACY = 128;
 
-
     // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal
     private static final int GPS_DELETE_EPHEMERIS = 0x0001;
     private static final int GPS_DELETE_ALMANAC = 0x0002;
@@ -200,9 +190,6 @@
     private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
     private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
 
-    //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
-    private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
-
     // ref. location info
     private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
     private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
@@ -375,7 +362,7 @@
      * Properties loaded from PROPERTIES_FILE.
      * It must be accessed only inside {@link #mHandler}.
      */
-    private Properties mProperties;
+    private GnssConfiguration mGnssConfiguration;
 
     private String mSuplServerHost;
     private int mSuplServerPort = TCP_MIN_PORT;
@@ -411,10 +398,6 @@
     private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
     private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
 
-    // Persist property for LPP_PROFILE
-    private final static String LPP_PROFILE = "persist.sys.gps.lpp";
-
-
     private final PowerManager mPowerManager;
     private final AlarmManager mAlarmManager;
     private final PendingIntent mWakeupIntent;
@@ -502,7 +485,7 @@
      */
     @Override
     public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
-        mHandler.post(() -> native_set_satellite_blacklist(constellations, svids));
+        mHandler.post(() -> mGnssConfiguration.setSatelliteBlacklist(constellations, svids));
     }
 
     private void subscriptionOrCarrierConfigChanged(Context context) {
@@ -525,17 +508,17 @@
                 }
                 if (isKeepLppProfile) {
                     // load current properties for the carrier
-                    loadPropertiesFromCarrierConfig(context, mProperties);
-                    String lpp_profile = mProperties.getProperty("LPP_PROFILE");
+                    mGnssConfiguration.loadPropertiesFromCarrierConfig();
+                    String lpp_profile = mGnssConfiguration.getLppProfile();
                     // set the persist property LPP_PROFILE for the value
                     if (lpp_profile != null) {
-                        SystemProperties.set(LPP_PROFILE, lpp_profile);
+                        SystemProperties.set(GnssConfiguration.LPP_PROFILE, lpp_profile);
                     }
                 } else {
                     // reset the persist property
-                    SystemProperties.set(LPP_PROFILE, "");
+                    SystemProperties.set(GnssConfiguration.LPP_PROFILE, "");
                 }
-                reloadGpsProperties(context, mProperties);
+                reloadGpsProperties();
                 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
             }
         } else {
@@ -564,133 +547,14 @@
         return native_is_supported();
     }
 
-    interface SetCarrierProperty {
-        boolean set(int value);
-    }
-
-    private void reloadGpsProperties(Context context, Properties properties) {
-        if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
-        loadPropertiesFromCarrierConfig(context, properties);
-
-        String lpp_prof = SystemProperties.get(LPP_PROFILE);
-        if (!TextUtils.isEmpty(lpp_prof)) {
-            // override default value of this if lpp_prof is not empty
-            properties.setProperty("LPP_PROFILE", lpp_prof);
-        }
-        /*
-         * Overlay carrier properties from a debug configuration file.
-         */
-        loadPropertiesFromGpsDebugConfig(properties);
+    private void reloadGpsProperties() {
+        mGnssConfiguration.reloadGpsProperties();
+        setSuplHostPort();
         // TODO: we should get rid of C2K specific setting.
-        setSuplHostPort(properties.getProperty("SUPL_HOST"),
-                properties.getProperty("SUPL_PORT"));
-        mC2KServerHost = properties.getProperty("C2K_HOST");
-        String portString = properties.getProperty("C2K_PORT");
-        if (mC2KServerHost != null && portString != null) {
-            try {
-                mC2KServerPort = Integer.parseInt(portString);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "unable to parse C2K_PORT: " + portString);
-            }
-        }
-        if (native_is_gnss_configuration_supported()) {
-            Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
-                {
-                    put("SUPL_VER", GnssLocationProvider::native_set_supl_version);
-                    put("SUPL_MODE", GnssLocationProvider::native_set_supl_mode);
-                    put("SUPL_ES", GnssLocationProvider::native_set_supl_es);
-                    put("LPP_PROFILE", GnssLocationProvider::native_set_lpp_profile);
-                    put("A_GLONASS_POS_PROTOCOL_SELECT",
-                            GnssLocationProvider::native_set_gnss_pos_protocol_select);
-                    put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL",
-                            GnssLocationProvider::native_set_emergency_supl_pdn);
-                    put("GPS_LOCK", GnssLocationProvider::native_set_gps_lock);
-                }
-            };
-
-            for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
-                String propertyName = entry.getKey();
-                String propertyValueString = properties.getProperty(propertyName);
-                if (propertyValueString != null) {
-                    try {
-                        int propertyValueInt = Integer.decode(propertyValueString);
-                        boolean result = entry.getValue().set(propertyValueInt);
-                        if (!result) {
-                            Log.e(TAG, "Unable to set " + propertyName);
-                        }
-                    } catch (NumberFormatException e) {
-                        Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
-                    }
-                }
-            }
-        } else if (DEBUG) {
-            Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
-                    + " supported");
-        }
-
-        // SUPL_ES configuration.
-        String suplESProperty = mProperties.getProperty("SUPL_ES");
-        if (suplESProperty != null) {
-            try {
-                mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
-            }
-        }
-
-        String emergencyExtensionSecondsString
-                = properties.getProperty("ES_EXTENSION_SEC", "0");
-        try {
-            int emergencyExtensionSeconds =
-                    Integer.parseInt(emergencyExtensionSecondsString);
-            mNIHandler.setEmergencyExtensionSeconds(emergencyExtensionSeconds);
-        } catch (NumberFormatException e) {
-            Log.e(TAG, "unable to parse ES_EXTENSION_SEC: "
-                    + emergencyExtensionSecondsString);
-        }
-    }
-
-    private void loadPropertiesFromCarrierConfig(Context context, Properties properties) {
-        CarrierConfigManager configManager = (CarrierConfigManager)
-                mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        if (configManager == null) {
-            return;
-        }
-        PersistableBundle configs = configManager.getConfigForSubId(
-                SubscriptionManager.getDefaultDataSubscriptionId());
-        if (configs == null) {
-            if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
-            configs = CarrierConfigManager.getDefaultConfig();
-        }
-        for (String configKey : configs.keySet()) {
-            if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) {
-                String key = configKey
-                        .substring(CarrierConfigManager.Gps.KEY_PREFIX.length())
-                        .toUpperCase();
-                Object value = configs.get(configKey);
-                if (value instanceof String) {
-                    // All GPS properties are of String type; convert so.
-                    if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value);
-                    properties.setProperty(key, (String) value);
-                }
-            }
-        }
-    }
-
-    private void loadPropertiesFromGpsDebugConfig(Properties properties) {
-        try {
-            File file = new File(DEBUG_PROPERTIES_FILE);
-            FileInputStream stream = null;
-            try {
-                stream = new FileInputStream(file);
-                properties.load(stream);
-            } finally {
-                IoUtils.closeQuietly(stream);
-            }
-
-        } catch (IOException e) {
-            if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
-        }
+        mC2KServerHost = mGnssConfiguration.getC2KHost();
+        mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT);
+        mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec());
+        mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1;
     }
 
     public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
@@ -733,7 +597,7 @@
         // relative long time, so the ctor() is kept to create objects needed by this instance,
         // while IO initialization and registration is delegated to our internal handler
         // this approach is just fine because events are posted to our handler anyway
-        mProperties = new Properties();
+        mGnssConfiguration = new GnssConfiguration(mContext);
         sendMessage(INITIALIZE_HANDLER, 0, null);
 
         // Create a GPS net-initiated handler.
@@ -918,7 +782,8 @@
         mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
         Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
         AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
-            GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
+            GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(
+                    mGnssConfiguration.getProperties());
             byte[] data = xtraDownloader.downloadXtraData();
             if (data != null) {
                 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
@@ -963,17 +828,9 @@
         }
     }
 
-    private void setSuplHostPort(String hostString, String portString) {
-        if (hostString != null) {
-            mSuplServerHost = hostString;
-        }
-        if (portString != null) {
-            try {
-                mSuplServerPort = Integer.parseInt(portString);
-            } catch (NumberFormatException e) {
-                Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
-            }
-        }
+    private void setSuplHostPort() {
+        mSuplServerHost = mGnssConfiguration.getSuplHost();
+        mSuplServerPort = mGnssConfiguration.getSuplPort(TCP_MIN_PORT);
         if (mSuplServerHost != null
                 && mSuplServerPort > TCP_MIN_PORT
                 && mSuplServerPort <= TCP_MAX_PORT) {
@@ -986,23 +843,17 @@
      * Checks what SUPL mode to use, according to the AGPS mode as well as the
      * allowed mode from properties.
      *
-     * @param properties  GPS properties
      * @param agpsEnabled whether AGPS is enabled by settings value
      * @param singleShot  whether "singleshot" is needed
      * @return SUPL mode (MSA vs MSB vs STANDALONE)
      */
-    private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
+    private int getSuplMode(boolean agpsEnabled, boolean singleShot) {
         if (agpsEnabled) {
-            String modeString = properties.getProperty("SUPL_MODE");
-            int suplMode = 0;
-            if (!TextUtils.isEmpty(modeString)) {
-                try {
-                    suplMode = Integer.parseInt(modeString);
-                } catch (NumberFormatException e) {
-                    Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
-                    return GPS_POSITION_MODE_STANDALONE;
-                }
+            int suplMode = mGnssConfiguration.getSuplMode(0);
+            if (suplMode == 0) {
+                return GPS_POSITION_MODE_STANDALONE;
             }
+
             // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
             // such mode when it is available
             if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
@@ -1307,7 +1158,7 @@
             boolean agpsEnabled =
                     (Settings.Global.getInt(mContext.getContentResolver(),
                             Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
-            mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
+            mPositionMode = getSuplMode(agpsEnabled, singleShot);
 
             if (DEBUG) {
                 String mode;
@@ -1670,7 +1521,7 @@
                 // re-calls native_init() and other setup.
                 handleEnable();
                 // resend configuration into the restarted HAL service.
-                reloadGpsProperties(mContext, mProperties);
+                reloadGpsProperties();
             }
         });
     }
@@ -2072,7 +1923,7 @@
 
             // load default GPS configuration
             // (this configuration might change in the future based on SIM changes)
-            reloadGpsProperties(mContext, mProperties);
+            reloadGpsProperties();
 
             // TODO: When this object "finishes" we should unregister by invoking
             // SubscriptionManager.getInstance(mContext).unregister
@@ -2227,8 +2078,6 @@
 
     private static native boolean native_is_supported();
 
-    private static native boolean native_is_gnss_configuration_supported();
-
     private static native void native_init_once();
 
     private native boolean native_init();
@@ -2284,21 +2133,4 @@
             int lac, int cid);
 
     private native void native_agps_set_id(int type, String setid);
-
-    // GNSS Configuration
-    private static native boolean native_set_supl_version(int version);
-
-    private static native boolean native_set_supl_mode(int mode);
-
-    private static native boolean native_set_supl_es(int es);
-
-    private static native boolean native_set_lpp_profile(int lppProfile);
-
-    private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
-
-    private static native boolean native_set_gps_lock(int gpsLock);
-
-    private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
-
-    private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
-}
+}
\ No newline at end of file
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 6d8fc1c..b290bc5 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -135,6 +135,7 @@
 using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss;
 using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
 using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
+using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
 using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
 using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
 using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
@@ -179,6 +180,7 @@
 sp<IGnssDebug> gnssDebugIface = nullptr;
 sp<IGnssConfiguration_V1_0> gnssConfigurationIface = nullptr;
 sp<IGnssConfiguration_V1_1> gnssConfigurationIface_V1_1 = nullptr;
+sp<IGnssConfiguration_V2_0> gnssConfigurationIface_V2_0 = nullptr;
 sp<IGnssNi> gnssNiIface = nullptr;
 sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr;
 sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr;
@@ -313,6 +315,15 @@
     }
 }
 
+static jobject createHalInterfaceVersionJavaObject(JNIEnv* env, jint major, jint minor) {
+    jclass versionClass =
+            env->FindClass("com/android/server/location/GnssConfiguration$HalInterfaceVersion");
+    jmethodID versionCtor = env->GetMethodID(versionClass, "<init>", "(II)V");
+    jobject version = env->NewObject(versionClass, versionCtor, major, minor);
+    env->DeleteLocalRef(versionClass);
+    return version;
+}
+
 struct ScopedJniString {
     ScopedJniString(JNIEnv* env, jstring javaString) : mEnv(env), mJavaString(javaString) {
         mNativeString = mEnv->GetStringUTFChars(mJavaString, nullptr);
@@ -1421,10 +1432,19 @@
         gnssNiIface = gnssNi;
     }
 
-    if (gnssHal_V1_1 != nullptr) {
+    if (gnssHal_V2_0 != nullptr) {
+        auto gnssConfiguration = gnssHal_V2_0->getExtensionGnssConfiguration_2_0();
+        if (!gnssConfiguration.isOk()) {
+            ALOGD("Unable to get a handle to GnssConfiguration_V2_0");
+        } else {
+            gnssConfigurationIface_V2_0 = gnssConfiguration;
+            gnssConfigurationIface_V1_1 = gnssConfigurationIface_V2_0;
+            gnssConfigurationIface = gnssConfigurationIface_V2_0;
+        }
+    } else if (gnssHal_V1_1 != nullptr) {
         auto gnssConfiguration = gnssHal_V1_1->getExtensionGnssConfiguration_1_1();
         if (!gnssConfiguration.isOk()) {
-            ALOGD("Unable to get a handle to GnssConfiguration");
+            ALOGD("Unable to get a handle to GnssConfiguration_V1_1");
         } else {
             gnssConfigurationIface_V1_1 = gnssConfiguration;
             gnssConfigurationIface = gnssConfigurationIface_V1_1;
@@ -1463,9 +1483,23 @@
     return (agnssRilIface != nullptr) ? JNI_TRUE : JNI_FALSE;
 }
 
-static jboolean android_location_gpsLocationProvider_is_gnss_configuration_supported(
-        JNIEnv* /* env */, jclass /* jclazz */) {
-    return (gnssConfigurationIface != nullptr) ? JNI_TRUE : JNI_FALSE;
+static jobject android_location_GnssConfiguration_get_gnss_configuration_version(
+        JNIEnv* env, jclass /* jclazz */) {
+    jint major, minor;
+    if (gnssConfigurationIface_V2_0 != nullptr) {
+        major = 2;
+        minor = 0;
+    } else if (gnssConfigurationIface_V1_1 != nullptr) {
+        major = 1;
+        minor = 1;
+    } else if (gnssConfigurationIface != nullptr) {
+        major = 1;
+        minor = 0;
+    } else {
+        return nullptr;
+    }
+
+    return createHalInterfaceVersionJavaObject(env, major, minor);
 }
 
 static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject obj) {
@@ -2278,9 +2312,9 @@
     return boolToJbool(result.isOk());
 }
 
-static jboolean android_location_GnssLocationProvider_set_emergency_supl_pdn(JNIEnv*,
-                                                                    jobject,
-                                                                    jint emergencySuplPdn) {
+static jboolean android_location_GnssConfiguration_set_emergency_supl_pdn(JNIEnv*,
+                                                                          jobject,
+                                                                          jint emergencySuplPdn) {
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2294,7 +2328,7 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_supl_version(JNIEnv*,
+static jboolean android_location_GnssConfiguration_set_supl_version(JNIEnv*,
                                                                     jobject,
                                                                     jint version) {
     if (gnssConfigurationIface == nullptr) {
@@ -2309,9 +2343,14 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_supl_es(JNIEnv*,
-                                                                    jobject,
-                                                                    jint suplEs) {
+static jboolean android_location_GnssConfiguration_set_supl_es(JNIEnv*,
+                                                               jobject,
+                                                               jint suplEs) {
+    if (gnssConfigurationIface_V2_0 != nullptr) {
+        ALOGI("Config parameter SUPL_ES is deprecated in IGnssConfiguration.hal version 2.0.");
+        return JNI_FALSE;
+    }
+
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2325,9 +2364,9 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_supl_mode(JNIEnv*,
-                                                                    jobject,
-                                                                    jint mode) {
+static jboolean android_location_GnssConfiguration_set_supl_mode(JNIEnv*,
+                                                                 jobject,
+                                                                 jint mode) {
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2341,9 +2380,14 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_gps_lock(JNIEnv*,
-                                                                   jobject,
-                                                                   jint gpsLock) {
+static jboolean android_location_GnssConfiguration_set_gps_lock(JNIEnv*,
+                                                                jobject,
+                                                                jint gpsLock) {
+    if (gnssConfigurationIface_V2_0 != nullptr) {
+        ALOGI("Config parameter GPS_LOCK is deprecated in IGnssConfiguration.hal version 2.0.");
+        return JNI_FALSE;
+    }
+
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2357,7 +2401,7 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_lpp_profile(JNIEnv*,
+static jboolean android_location_GnssConfiguration_set_lpp_profile(JNIEnv*,
                                                                    jobject,
                                                                    jint lppProfile) {
     if (gnssConfigurationIface == nullptr) {
@@ -2374,9 +2418,9 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_gnss_pos_protocol_select(JNIEnv*,
-                                                                   jobject,
-                                                                   jint gnssPosProtocol) {
+static jboolean android_location_GnssConfiguration_set_gnss_pos_protocol_select(JNIEnv*,
+                                                                            jobject,
+                                                                            jint gnssPosProtocol) {
     if (gnssConfigurationIface == nullptr) {
         ALOGE("no GNSS configuration interface available");
         return JNI_FALSE;
@@ -2390,7 +2434,7 @@
     }
 }
 
-static jboolean android_location_GnssLocationProvider_set_satellite_blacklist(
+static jboolean android_location_GnssConfiguration_set_satellite_blacklist(
         JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) {
     if (gnssConfigurationIface_V1_1 == nullptr) {
         ALOGI("No GNSS Satellite Blacklist interface available");
@@ -2431,6 +2475,27 @@
     }
 }
 
+static jboolean android_location_GnssConfiguration_set_es_extension_sec(
+        JNIEnv*, jobject, jint emergencyExtensionSeconds) {
+    if (gnssConfigurationIface == nullptr) {
+        ALOGE("no GNSS configuration interface available");
+        return JNI_FALSE;
+    }
+
+    if (gnssConfigurationIface_V2_0 == nullptr) {
+        ALOGI("Config parameter ES_EXTENSION_SEC is not supported in IGnssConfiguration.hal"
+                " versions earlier than 2.0.");
+        return JNI_FALSE;
+    }
+
+    auto result = gnssConfigurationIface_V2_0->setEsExtensionSec(emergencyExtensionSeconds);
+    if (result.isOk()) {
+        return result;
+    } else {
+        return JNI_FALSE;
+    }
+}
+
 static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass) {
     if (gnssBatchingIface == nullptr) {
         return 0; // batching not supported, size = 0
@@ -2498,17 +2563,14 @@
             android_location_GnssLocationProvider_class_init_native)},
     {"native_is_supported", "()Z", reinterpret_cast<void *>(
             android_location_GnssLocationProvider_is_supported)},
-    {"native_is_gnss_configuration_supported", "()Z",
-            reinterpret_cast<void *>(
-                    android_location_gpsLocationProvider_is_gnss_configuration_supported)},
     {"native_init_once", "()V", reinterpret_cast<void *>(
             android_location_GnssLocationProvider_init_once)},
     {"native_init", "()Z", reinterpret_cast<void *>(android_location_GnssLocationProvider_init)},
     {"native_cleanup", "()V", reinterpret_cast<void *>(
             android_location_GnssLocationProvider_cleanup)},
     {"native_set_position_mode",
-                "(IIIIIZ)Z",
-                reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
+            "(IIIIIZ)Z",
+            reinterpret_cast<void*>(android_location_GnssLocationProvider_set_position_mode)},
     {"native_start", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_start)},
     {"native_stop", "()Z", reinterpret_cast<void*>(android_location_GnssLocationProvider_stop)},
     {"native_delete_aiding_data",
@@ -2545,31 +2607,6 @@
     {"native_get_internal_state",
             "()Ljava/lang/String;",
             reinterpret_cast<void *>(android_location_GnssLocationProvider_get_internal_state)},
-    {"native_set_supl_es",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_es)},
-    {"native_set_supl_version",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_version)},
-    {"native_set_supl_mode",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_mode)},
-    {"native_set_lpp_profile",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_lpp_profile)},
-    {"native_set_gnss_pos_protocol_select",
-            "(I)Z",
-            reinterpret_cast<void *>(
-                    android_location_GnssLocationProvider_set_gnss_pos_protocol_select)},
-    {"native_set_gps_lock",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_gps_lock)},
-    {"native_set_emergency_supl_pdn",
-            "(I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_emergency_supl_pdn)},
-    {"native_set_satellite_blacklist",
-            "([I[I)Z",
-            reinterpret_cast<void *>(android_location_GnssLocationProvider_set_satellite_blacklist)},
 };
 
 static const JNINativeMethod sMethodsBatching[] = {
@@ -2663,6 +2700,42 @@
             reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)},
 };
 
+static const JNINativeMethod sConfigurationMethods[] = {
+     /* name, signature, funcPtr */
+    {"native_get_gnss_configuration_version",
+            "()Lcom/android/server/location/GnssConfiguration$HalInterfaceVersion;",
+            reinterpret_cast<void *>(
+                    android_location_GnssConfiguration_get_gnss_configuration_version)},
+    {"native_set_supl_es",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_es)},
+    {"native_set_supl_version",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_version)},
+    {"native_set_supl_mode",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_mode)},
+    {"native_set_lpp_profile",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_lpp_profile)},
+    {"native_set_gnss_pos_protocol_select",
+            "(I)Z",
+            reinterpret_cast<void *>(
+                    android_location_GnssConfiguration_set_gnss_pos_protocol_select)},
+    {"native_set_gps_lock",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_gps_lock)},
+    {"native_set_emergency_supl_pdn",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_emergency_supl_pdn)},
+    {"native_set_satellite_blacklist",
+            "([I[I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_satellite_blacklist)},
+    {"native_set_es_extension_sec",
+            "(I)Z",
+            reinterpret_cast<void *>(android_location_GnssConfiguration_set_es_extension_sec)},
+};
+
 int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
     jniRegisterNativeMethods(
             env,
@@ -2689,6 +2762,11 @@
             "com/android/server/location/GnssNetworkConnectivityHandler",
             sNetworkConnectivityMethods,
             NELEM(sNetworkConnectivityMethods));
+    jniRegisterNativeMethods(
+            env,
+            "com/android/server/location/GnssConfiguration",
+            sConfigurationMethods,
+            NELEM(sConfigurationMethods));
     return jniRegisterNativeMethods(
             env,
             "com/android/server/location/GnssLocationProvider",