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