blob: b3546dc795724b86c89472158cd27226826590d8 [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;
Muhammad Qureshi6f207102020-01-28 10:37:41 -080026
27import com.android.internal.util.FrameworkStatsLog;
Anil Admald71cf142018-12-21 14:59:36 -080028
29import libcore.io.IoUtils;
30
31import java.io.File;
32import java.io.FileInputStream;
33import java.io.IOException;
Anil Admal94ec76a2019-01-15 09:42:01 -080034import java.util.ArrayList;
35import java.util.Collections;
Anil Admald71cf142018-12-21 14:59:36 -080036import java.util.HashMap;
Anil Admal94ec76a2019-01-15 09:42:01 -080037import java.util.List;
Anil Admald71cf142018-12-21 14:59:36 -080038import java.util.Map;
39import java.util.Map.Entry;
40import 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 */
51class GnssConfiguration {
52 private static final String TAG = "GnssConfiguration";
53
54 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
55
Anil Admald71cf142018-12-21 14:59:36 -080056 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";
Anil Admal94ec76a2019-01-15 09:42:01 -080073 public static final String CONFIG_NFW_PROXY_APPS = "NFW_PROXY_APPS";
Anil Admald71cf142018-12-21 14:59:36 -080074
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 private static class HalInterfaceVersion {
84 final int mMajor;
85 final int mMinor;
86
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 Properties mProperties;
97
98 private int mEsExtensionSec = 0;
99
100 private final Context mContext;
101
102 GnssConfiguration(Context context) {
103 mContext = context;
104 mProperties = new Properties();
105 }
106
107 /**
108 * Returns the full set of properties loaded.
109 */
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 */
118 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 */
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 */
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 */
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 */
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 */
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 */
166 int getSuplEs(int defaulSuplEs) {
167 return getIntConfig(CONFIG_SUPL_ES, defaulSuplEs);
168 }
169
170 /**
171 * Returns the value of config parameter LPP_PROFILE or {@code null} if no value is
172 * provided.
173 */
174 String getLppProfile() {
175 return mProperties.getProperty(CONFIG_LPP_PROFILE);
176 }
177
178 /**
Anil Admal94ec76a2019-01-15 09:42:01 -0800179 * Returns the list of proxy apps from the value of config parameter NFW_PROXY_APPS or
180 * {@Collections.EMPTY_LIST} if no value is provided.
181 */
182 List<String> getProxyApps() {
183 // Space separated list of Android proxy app package names.
184 String proxyAppsStr = mProperties.getProperty(CONFIG_NFW_PROXY_APPS);
185 if (TextUtils.isEmpty(proxyAppsStr)) {
186 return Collections.EMPTY_LIST;
187 }
188
189 String[] proxyAppsArray = proxyAppsStr.trim().split("\\s+");
190 if (proxyAppsArray.length == 0) {
191 return Collections.EMPTY_LIST;
192 }
193
Anil Admal94ec76a2019-01-15 09:42:01 -0800194 ArrayList proxyApps = new ArrayList(proxyAppsArray.length);
195 for (String proxyApp : proxyAppsArray) {
196 proxyApps.add(proxyApp);
197 }
198
199 return proxyApps;
200 }
201
202 /**
Anil Admald71cf142018-12-21 14:59:36 -0800203 * Updates the GNSS HAL satellite blacklist.
204 */
205 void setSatelliteBlacklist(int[] constellations, int[] svids) {
206 native_set_satellite_blacklist(constellations, svids);
207 }
208
209 interface SetCarrierProperty {
210 boolean set(int value);
211 }
212
213 /**
214 * Loads the GNSS properties from carrier config file followed by the properties from
215 * gps debug config file.
216 */
217 void reloadGpsProperties() {
218 if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + mProperties.size());
219 loadPropertiesFromCarrierConfig();
220
221 String lpp_prof = SystemProperties.get(LPP_PROFILE);
222 if (!TextUtils.isEmpty(lpp_prof)) {
223 // override default value of this if lpp_prof is not empty
224 mProperties.setProperty(CONFIG_LPP_PROFILE, lpp_prof);
225 }
226 /*
227 * Overlay carrier properties from a debug configuration file.
228 */
229 loadPropertiesFromGpsDebugConfig(mProperties);
230
231 mEsExtensionSec = getRangeCheckedConfigEsExtensionSec();
232
Yu-Han Yang14d5fb42019-01-16 12:42:59 -0800233 logConfigurations();
234
Anil Admald71cf142018-12-21 14:59:36 -0800235 final HalInterfaceVersion gnssConfigurationIfaceVersion =
236 native_get_gnss_configuration_version();
237 if (gnssConfigurationIfaceVersion != null) {
238 // Set to a range checked value.
239 if (isConfigEsExtensionSecSupported(gnssConfigurationIfaceVersion)
240 && !native_set_es_extension_sec(mEsExtensionSec)) {
241 Log.e(TAG, "Unable to set " + CONFIG_ES_EXTENSION_SEC + ": " + mEsExtensionSec);
242 }
243
244 Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
245 {
246 put(CONFIG_SUPL_VER, GnssConfiguration::native_set_supl_version);
247 put(CONFIG_SUPL_MODE, GnssConfiguration::native_set_supl_mode);
248
249 if (isConfigSuplEsSupported(gnssConfigurationIfaceVersion)) {
250 put(CONFIG_SUPL_ES, GnssConfiguration::native_set_supl_es);
251 }
252
253 put(CONFIG_LPP_PROFILE, GnssConfiguration::native_set_lpp_profile);
254 put(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT,
255 GnssConfiguration::native_set_gnss_pos_protocol_select);
256 put(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL,
257 GnssConfiguration::native_set_emergency_supl_pdn);
258
259 if (isConfigGpsLockSupported(gnssConfigurationIfaceVersion)) {
260 put(CONFIG_GPS_LOCK, GnssConfiguration::native_set_gps_lock);
261 }
262 }
263 };
264
265 for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
266 String propertyName = entry.getKey();
267 String propertyValueString = mProperties.getProperty(propertyName);
268 if (propertyValueString != null) {
269 try {
270 int propertyValueInt = Integer.decode(propertyValueString);
271 boolean result = entry.getValue().set(propertyValueInt);
272 if (!result) {
273 Log.e(TAG, "Unable to set " + propertyName);
274 }
275 } catch (NumberFormatException e) {
276 Log.e(TAG, "Unable to parse propertyName: " + propertyValueString);
277 }
278 }
279 }
280 } else if (DEBUG) {
281 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
282 + " supported");
283 }
284 }
285
Yu-Han Yang14d5fb42019-01-16 12:42:59 -0800286 private void logConfigurations() {
Muhammad Qureshi6f207102020-01-28 10:37:41 -0800287 FrameworkStatsLog.write(FrameworkStatsLog.GNSS_CONFIGURATION_REPORTED,
Yu-Han Yang14d5fb42019-01-16 12:42:59 -0800288 getSuplHost(),
289 getSuplPort(0),
290 getC2KHost(),
291 getC2KPort(0),
292 getIntConfig(CONFIG_SUPL_VER, 0),
293 getSuplMode(0),
294 getSuplEs(0) == 1,
295 getIntConfig(CONFIG_LPP_PROFILE, 0),
296 getIntConfig(CONFIG_A_GLONASS_POS_PROTOCOL_SELECT, 0),
297 getIntConfig(CONFIG_USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL, 0) == 1,
298 getIntConfig(CONFIG_GPS_LOCK, 0),
299 getEsExtensionSec(),
300 mProperties.getProperty(CONFIG_NFW_PROXY_APPS));
301 }
302
Anil Admald71cf142018-12-21 14:59:36 -0800303 /**
304 * Loads GNSS properties from carrier config file.
305 */
306 void loadPropertiesFromCarrierConfig() {
307 CarrierConfigManager configManager = (CarrierConfigManager)
308 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
309 if (configManager == null) {
310 return;
311 }
Anil Admale1539e82019-05-09 15:05:04 -0700312
313 int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
314 PersistableBundle configs = SubscriptionManager.isValidSubscriptionId(ddSubId)
315 ? configManager.getConfigForSubId(ddSubId) : null;
Anil Admald71cf142018-12-21 14:59:36 -0800316 if (configs == null) {
317 if (DEBUG) Log.d(TAG, "SIM not ready, use default carrier config.");
318 configs = CarrierConfigManager.getDefaultConfig();
319 }
320 for (String configKey : configs.keySet()) {
321 if (configKey.startsWith(CarrierConfigManager.Gps.KEY_PREFIX)) {
322 String key = configKey
323 .substring(CarrierConfigManager.Gps.KEY_PREFIX.length())
324 .toUpperCase();
325 Object value = configs.get(configKey);
Anil Admalbefd4832019-05-09 19:58:13 -0700326 if (DEBUG) Log.d(TAG, "Gps config: " + key + " = " + value);
Anil Admald71cf142018-12-21 14:59:36 -0800327 if (value instanceof String) {
Anil Admalbefd4832019-05-09 19:58:13 -0700328 // Most GPS properties are of String type; convert so.
Anil Admald71cf142018-12-21 14:59:36 -0800329 mProperties.setProperty(key, (String) value);
Anil Admalbefd4832019-05-09 19:58:13 -0700330 } else if (value != null) {
331 mProperties.setProperty(key, value.toString());
Anil Admald71cf142018-12-21 14:59:36 -0800332 }
333 }
334 }
335 }
336
337 private void loadPropertiesFromGpsDebugConfig(Properties properties) {
338 try {
339 File file = new File(DEBUG_PROPERTIES_FILE);
340 FileInputStream stream = null;
341 try {
342 stream = new FileInputStream(file);
343 properties.load(stream);
344 } finally {
345 IoUtils.closeQuietly(stream);
346 }
347 } catch (IOException e) {
348 if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
349 }
350 }
351
352 private int getRangeCheckedConfigEsExtensionSec() {
353 int emergencyExtensionSeconds = getIntConfig(CONFIG_ES_EXTENSION_SEC, 0);
354 if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
355 Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
356 + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
357 emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
358 } else if (emergencyExtensionSeconds < 0) {
359 Log.w(TAG, CONFIG_ES_EXTENSION_SEC + ": " + emergencyExtensionSeconds
360 + " is negative, reset to zero.");
361 emergencyExtensionSeconds = 0;
362 }
363 return emergencyExtensionSeconds;
364 }
365
366 private int getIntConfig(String configParameter, int defaultValue) {
367 String valueString = mProperties.getProperty(configParameter);
368 if (TextUtils.isEmpty(valueString)) {
369 return defaultValue;
370 }
371 try {
gomoad2a2402019-02-08 23:08:40 -0800372 return Integer.decode(valueString);
Anil Admald71cf142018-12-21 14:59:36 -0800373 } catch (NumberFormatException e) {
374 Log.e(TAG, "Unable to parse config parameter " + configParameter + " value: "
375 + valueString + ". Using default value: " + defaultValue);
376 return defaultValue;
377 }
378 }
379
380 private static boolean isConfigEsExtensionSecSupported(
381 HalInterfaceVersion gnssConfiguartionIfaceVersion) {
382 // ES_EXTENSION_SEC is introduced in @2.0::IGnssConfiguration.hal
383 return gnssConfiguartionIfaceVersion.mMajor >= 2;
384 }
385
386 private static boolean isConfigSuplEsSupported(
387 HalInterfaceVersion gnssConfiguartionIfaceVersion) {
388 // SUPL_ES is deprecated in @2.0::IGnssConfiguration.hal
389 return gnssConfiguartionIfaceVersion.mMajor < 2;
390 }
391
392 private static boolean isConfigGpsLockSupported(
393 HalInterfaceVersion gnssConfiguartionIfaceVersion) {
394 // GPS_LOCK is deprecated in @2.0::IGnssConfiguration.hal
395 return gnssConfiguartionIfaceVersion.mMajor < 2;
396 }
397
398 private static native HalInterfaceVersion native_get_gnss_configuration_version();
399
400 private static native boolean native_set_supl_version(int version);
401
402 private static native boolean native_set_supl_mode(int mode);
403
404 private static native boolean native_set_supl_es(int es);
405
406 private static native boolean native_set_lpp_profile(int lppProfile);
407
408 private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
409
410 private static native boolean native_set_gps_lock(int gpsLock);
411
412 private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
413
414 private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
415
416 private static native boolean native_set_es_extension_sec(int emergencyExtensionSeconds);
417}