• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.location.gnss;
18 
19 import android.content.Context;
20 import android.os.PersistableBundle;
21 import android.os.SystemProperties;
22 import android.telephony.CarrierConfigManager;
23 import android.telephony.SubscriptionManager;
24 import android.text.TextUtils;
25 import android.util.Log;
26 
27 import com.android.internal.util.FrameworkStatsLog;
28 
29 import libcore.io.IoUtils;
30 
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.IOException;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.Properties;
41 
42 /**
43  * A utility class to hold GNSS configuration properties.
44  *
45  * The trigger to load/reload the configuration parameters should be managed by the class
46  * that owns an instance of this class.
47  *
48  * Instances of this class are not thread-safe and should either be used from a single thread
49  * or with external synchronization when used by multiple threads.
50  */
51 public class GnssConfiguration {
52     private static final String TAG = "GnssConfiguration";
53 
54     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
55 
56     private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
57 
58     // config.xml properties
59     private static final String CONFIG_SUPL_HOST = "SUPL_HOST";
60     private static final String CONFIG_SUPL_PORT = "SUPL_PORT";
61     private static final String CONFIG_C2K_HOST = "C2K_HOST";
62     private static final String CONFIG_C2K_PORT = "C2K_PORT";
63     private static final String CONFIG_SUPL_VER = "SUPL_VER";
64     private static final String CONFIG_SUPL_MODE = "SUPL_MODE";
65     private static final String CONFIG_SUPL_ES = "SUPL_ES";
66     private static final String CONFIG_LPP_PROFILE = "LPP_PROFILE";
67     private static final String CONFIG_A_GLONASS_POS_PROTOCOL_SELECT =
68             "A_GLONASS_POS_PROTOCOL_SELECT";
69     private static final String CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL =
70             "USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL";
71     private static final String CONFIG_GPS_LOCK = "GPS_LOCK";
72     private static final String CONFIG_ES_EXTENSION_SEC = "ES_EXTENSION_SEC";
73     public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
74 
75     // Limit on NI emergency mode time extension after emergency sessions ends
76     private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
77 
78     // Persist property for LPP_PROFILE
79     static final String LPP_PROFILE = "persist.sys.gps.lpp";
80 
81     // Represents an HAL interface version. Instances of this class are created in the JNI layer
82     // and returned through native methods.
83     static class HalInterfaceVersion {
84         final int mMajor;
85         final int mMinor;
86 
HalInterfaceVersion(int major, int minor)87         HalInterfaceVersion(int major, int minor) {
88             mMajor = major;
89             mMinor = minor;
90         }
91     }
92 
93     /**
94      * Properties loaded from PROPERTIES_FILE.
95      */
96     private final Properties mProperties;
97 
98     private int mEsExtensionSec = 0;
99 
100     private final Context mContext;
101 
GnssConfiguration(Context context)102     public GnssConfiguration(Context context) {
103         mContext = context;
104         mProperties = new Properties();
105     }
106 
107     /**
108      * Returns the full set of properties loaded.
109      */
getProperties()110     Properties getProperties() {
111         return mProperties;
112     }
113 
114     /**
115      * Returns the value of config parameter ES_EXTENSION_SEC. The value is range checked
116      * and constrained to min/max limits.
117      */
getEsExtensionSec()118     public int getEsExtensionSec() {
119         return mEsExtensionSec;
120     }
121 
122     /**
123      * Returns the value of config parameter SUPL_HOST or {@code null} if no value is
124      * provided.
125      */
getSuplHost()126     String getSuplHost() {
127         return mProperties.getProperty(CONFIG_SUPL_HOST);
128     }
129 
130     /**
131      * Returns the value of config parameter SUPL_PORT or {@code defaultPort} if no value is
132      * provided or if there is an error parsing the configured value.
133      */
getSuplPort(int defaultPort)134     int getSuplPort(int defaultPort) {
135         return getIntConfig(CONFIG_SUPL_PORT, defaultPort);
136     }
137 
138     /**
139      * Returns the value of config parameter C2K_HOST or {@code null} if no value is
140      * provided.
141      */
getC2KHost()142     String getC2KHost() {
143         return mProperties.getProperty(CONFIG_C2K_HOST);
144     }
145 
146     /**
147      * Returns the value of config parameter C2K_PORT or {@code defaultPort} if no value is
148      * provided or if there is an error parsing the configured value.
149      */
getC2KPort(int defaultPort)150     int getC2KPort(int defaultPort) {
151         return getIntConfig(CONFIG_C2K_PORT, defaultPort);
152     }
153 
154     /**
155      * Returns the value of config parameter SUPL_MODE or {@code defaultMode} if no value is
156      * provided or if there is an error parsing the configured value.
157      */
getSuplMode(int defaultMode)158     int getSuplMode(int defaultMode) {
159         return getIntConfig(CONFIG_SUPL_MODE, defaultMode);
160     }
161 
162     /**
163      * Returns the value of config parameter SUPL_ES or {@code defaultSuplEs} if no value is
164      * provided or if there is an error parsing the configured value.
165      */
getSuplEs(int defaultSuplEs)166     public int getSuplEs(int defaultSuplEs) {
167         return getIntConfig(CONFIG_SUPL_ES, defaultSuplEs);
168     }
169 
170     /**
171      * Returns the value of config parameter LPP_PROFILE or {@code null} if no value is
172      * provided.
173      */
getLppProfile()174     String getLppProfile() {
175         return mProperties.getProperty(CONFIG_LPP_PROFILE);
176     }
177 
178     /**
179      * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS.
180      */
getProxyApps()181     List<String> getProxyApps() {
182         // Space separated list of Android proxy app package names.
183         String proxyAppsStr = mProperties.getProperty(CONFIG_NFW_PROXY_APPS);
184         if (TextUtils.isEmpty(proxyAppsStr)) {
185             return Collections.emptyList();
186         }
187 
188         String[] proxyAppsArray = proxyAppsStr.trim().split("\\s+");
189         if (proxyAppsArray.length == 0) {
190             return Collections.emptyList();
191         }
192 
193         return Arrays.asList(proxyAppsArray);
194     }
195 
196     /**
197      * Updates the GNSS HAL satellite denylist.
198      */
setSatelliteBlocklist(int[] constellations, int[] svids)199     void setSatelliteBlocklist(int[] constellations, int[] svids) {
200         native_set_satellite_blocklist(constellations, svids);
201     }
202 
getHalInterfaceVersion()203     HalInterfaceVersion getHalInterfaceVersion() {
204         return native_get_gnss_configuration_version();
205     }
206 
207     interface SetCarrierProperty {
set(int value)208         boolean set(int value);
209     }
210 
211     /**
212      * Loads the GNSS properties from carrier config file followed by the properties from
213      * gps debug config file.
214      */
reloadGpsProperties()215     void reloadGpsProperties() {
216         if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + mProperties.size());
217         loadPropertiesFromCarrierConfig();
218 
219         String lpp_prof = SystemProperties.get(LPP_PROFILE);
220         if (!TextUtils.isEmpty(lpp_prof)) {
221             // override default value of this if lpp_prof is not empty
222             mProperties.setProperty(CONFIG_LPP_PROFILE, lpp_prof);
223         }
224 
225         /*
226          * Overlay carrier properties from a debug configuration file.
227          */
228         loadPropertiesFromGpsDebugConfig(mProperties);
229         mEsExtensionSec = getRangeCheckedConfigEsExtensionSec();
230 
231         logConfigurations();
232 
233         final HalInterfaceVersion gnssConfigurationIfaceVersion = getHalInterfaceVersion();
234         if (gnssConfigurationIfaceVersion != null) {
235             // Set to a range checked value.
236             if (isConfigEsExtensionSecSupported(gnssConfigurationIfaceVersion)
237                     && !native_set_es_extension_sec(mEsExtensionSec)) {
238                 Log.e(TAG, "Unable to set " + CONFIG_ES_EXTENSION_SEC + ": " + mEsExtensionSec);
239             }
240 
241             Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
242                 {
243                     put(CONFIG_SUPL_VER, GnssConfiguration::native_set_supl_version);
244                     put(CONFIG_SUPL_MODE, GnssConfiguration::native_set_supl_mode);
245 
246                     if (isConfigSuplEsSupported(gnssConfigurationIfaceVersion)) {
247                         put(CONFIG_SUPL_ES, GnssConfiguration::native_set_supl_es);
248                     }
249 
250                     put(CONFIG_LPP_PROFILE, GnssConfiguration::native_set_lpp_profile);
251                     put(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT,
252                             GnssConfiguration::native_set_gnss_pos_protocol_select);
253                     put(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL,
254                             GnssConfiguration::native_set_emergency_supl_pdn);
255 
256                     if (isConfigGpsLockSupported(gnssConfigurationIfaceVersion)) {
257                         put(CONFIG_GPS_LOCK, GnssConfiguration::native_set_gps_lock);
258                     }
259                 }
260             };
261 
262             for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
263                 String propertyName = entry.getKey();
264                 String propertyValueString = mProperties.getProperty(propertyName);
265                 if (propertyValueString != null) {
266                     try {
267                         int propertyValueInt = Integer.decode(propertyValueString);
268                         boolean result = entry.getValue().set(propertyValueInt);
269                         if (!result) {
270                             Log.e(TAG, "Unable to set " + propertyName);
271                         }
272                     } catch (NumberFormatException e) {
273                         Log.e(TAG, "Unable to parse propertyName: " + propertyValueString);
274                     }
275                 }
276             }
277         } else if (DEBUG) {
278             Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
279                     + " supported");
280         }
281     }
282 
logConfigurations()283     private void logConfigurations() {
284         FrameworkStatsLog.write(FrameworkStatsLog.GNSS_CONFIGURATION_REPORTED,
285                 getSuplHost(),
286                 getSuplPort(0),
287                 getC2KHost(),
288                 getC2KPort(0),
289                 getIntConfig(CONFIG_SUPL_VER, 0),
290                 getSuplMode(0),
291                 getSuplEs(0) == 1,
292                 getIntConfig(CONFIG_LPP_PROFILE, 0),
293                 getIntConfig(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT, 0),
294                 getIntConfig(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL, 0) == 1,
295                 getIntConfig(CONFIG_GPS_LOCK, 0),
296                 getEsExtensionSec(),
297                 mProperties.getProperty(CONFIG_NFW_PROXY_APPS));
298     }
299 
300     /**
301      * Loads GNSS properties from carrier config file.
302      */
loadPropertiesFromCarrierConfig()303     void loadPropertiesFromCarrierConfig() {
304         CarrierConfigManager configManager = (CarrierConfigManager)
305                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
306         if (configManager == null) {
307             return;
308         }
309 
310         int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
311         PersistableBundle configs = SubscriptionManager.isValidSubscriptionId(ddSubId)
312                 ? configManager.getConfigForSubId(ddSubId) : configManager.getConfig();
313         if (configs == null) {
314             if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
315             configs = CarrierConfigManager.getDefaultConfig();
316         }
317         for (String configKey : configs.keySet()) {
318             if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) {
319                 String key = configKey
320                         .substring(CarrierConfigManager.Gps.KEY_PREFIX.length())
321                         .toUpperCase();
322                 Object value = configs.get(configKey);
323                 if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value);
324                 if (value instanceof String) {
325                     // Most GPS properties are of String type; convert so.
326                     mProperties.setProperty(key, (String) value);
327                 } else if (value != null) {
328                     mProperties.setProperty(key, value.toString());
329                 }
330             }
331         }
332     }
333 
loadPropertiesFromGpsDebugConfig(Properties properties)334     private void loadPropertiesFromGpsDebugConfig(Properties properties) {
335         try {
336             File file = new File(DEBUG_PROPERTIES_FILE);
337             FileInputStream stream = null;
338             try {
339                 stream = new FileInputStream(file);
340                 properties.load(stream);
341             } finally {
342                 IoUtils.closeQuietly(stream);
343             }
344         } catch (IOException e) {
345             if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
346         }
347     }
348 
getRangeCheckedConfigEsExtensionSec()349     private int getRangeCheckedConfigEsExtensionSec() {
350         int emergencyExtensionSeconds = getIntConfig(CONFIG_ES_EXTENSION_SEC, 0);
351         if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
352             Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
353                     + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
354             emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
355         } else if (emergencyExtensionSeconds < 0) {
356             Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
357                     + " is negative, reset to zero.");
358             emergencyExtensionSeconds = 0;
359         }
360         return emergencyExtensionSeconds;
361     }
362 
getIntConfig(String configParameter, int defaultValue)363     private int getIntConfig(String configParameter, int defaultValue) {
364         String valueString = mProperties.getProperty(configParameter);
365         if (TextUtils.isEmpty(valueString)) {
366             return defaultValue;
367         }
368         try {
369             return Integer.decode(valueString);
370         } catch (NumberFormatException e) {
371             Log.e(TAG, "Unable to parse config parameter " + configParameter + " value: "
372                     + valueString + ". Using default value: " + defaultValue);
373             return defaultValue;
374         }
375     }
376 
isConfigEsExtensionSecSupported( HalInterfaceVersion gnssConfiguartionIfaceVersion)377     private static boolean isConfigEsExtensionSecSupported(
378             HalInterfaceVersion gnssConfiguartionIfaceVersion) {
379         // ES_EXTENSION_SEC is introduced in @2.0::IGnssConfiguration.hal
380         return gnssConfiguartionIfaceVersion.mMajor >= 2;
381     }
382 
isConfigSuplEsSupported( HalInterfaceVersion gnssConfiguartionIfaceVersion)383     private static boolean isConfigSuplEsSupported(
384             HalInterfaceVersion gnssConfiguartionIfaceVersion) {
385         // SUPL_ES is deprecated in @2.0::IGnssConfiguration.hal
386         return gnssConfiguartionIfaceVersion.mMajor < 2;
387     }
388 
isConfigGpsLockSupported( HalInterfaceVersion gnssConfiguartionIfaceVersion)389     private static boolean isConfigGpsLockSupported(
390             HalInterfaceVersion gnssConfiguartionIfaceVersion) {
391         // GPS_LOCK is deprecated in @2.0::IGnssConfiguration.hal
392         return gnssConfiguartionIfaceVersion.mMajor < 2;
393     }
394 
native_get_gnss_configuration_version()395     private static native HalInterfaceVersion native_get_gnss_configuration_version();
396 
native_set_supl_version(int version)397     private static native boolean native_set_supl_version(int version);
398 
native_set_supl_mode(int mode)399     private static native boolean native_set_supl_mode(int mode);
400 
native_set_supl_es(int es)401     private static native boolean native_set_supl_es(int es);
402 
native_set_lpp_profile(int lppProfile)403     private static native boolean native_set_lpp_profile(int lppProfile);
404 
native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect)405     private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
406 
native_set_gps_lock(int gpsLock)407     private static native boolean native_set_gps_lock(int gpsLock);
408 
native_set_emergency_supl_pdn(int emergencySuplPdn)409     private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
410 
native_set_satellite_blocklist(int[] constellations, int[] svIds)411     private static native boolean native_set_satellite_blocklist(int[] constellations, int[] svIds);
412 
native_set_es_extension_sec(int emergencyExtensionSeconds)413     private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds);
414 }
415