2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.location;
19 import android.app.AlarmManager;
20 import android.app.AppOpsManager;
21 import android.app.PendingIntent;
22 import android.content.BroadcastReceiver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.pm.PackageManager;
27 import android.database.Cursor;
28 import android.hardware.location.GeofenceHardware;
29 import android.hardware.location.GeofenceHardwareImpl;
30 import android.location.Criteria;
31 import android.location.FusedBatchOptions;
32 import android.location.GnssStatus;
33 import android.location.IGnssStatusListener;
34 import android.location.IGnssStatusProvider;
35 import android.location.GnssMeasurementsEvent;
36 import android.location.GnssNavigationMessage;
37 import android.location.IGpsGeofenceHardware;
38 import android.location.ILocationManager;
39 import android.location.INetInitiatedListener;
40 import android.location.Location;
41 import android.location.LocationListener;
42 import android.location.LocationManager;
43 import android.location.LocationProvider;
44 import android.location.LocationRequest;
45 import android.net.ConnectivityManager;
46 import android.net.Network;
47 import android.net.NetworkCapabilities;
48 import android.net.NetworkInfo;
49 import android.net.NetworkRequest;
50 import android.net.Uri;
51 import android.os.AsyncTask;
52 import android.os.PowerSaveState;
53 import android.os.BatteryStats;
54 import android.os.Binder;
55 import android.os.Bundle;
56 import android.os.PersistableBundle;
57 import android.os.Handler;
58 import android.os.Looper;
59 import android.os.Message;
60 import android.os.PowerManager;
61 import android.os.RemoteException;
62 import android.os.ServiceManager;
63 import android.os.SystemClock;
64 import android.os.SystemProperties;
65 import android.os.UserHandle;
66 import android.os.WorkSource;
67 import android.provider.Settings;
68 import android.provider.Telephony.Carriers;
69 import android.provider.Telephony.Sms.Intents;
70 import android.telephony.SubscriptionManager;
71 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
72 import android.telephony.TelephonyManager;
73 import android.telephony.CarrierConfigManager;
74 import android.telephony.gsm.GsmCellLocation;
75 import android.text.TextUtils;
76 import android.util.Log;
77 import android.util.NtpTrustedTime;
79 import com.android.internal.app.IAppOpsService;
80 import com.android.internal.app.IBatteryStats;
81 import com.android.internal.location.gnssmetrics.GnssMetrics;
82 import com.android.internal.location.GpsNetInitiatedHandler;
83 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
84 import com.android.internal.location.ProviderProperties;
85 import com.android.internal.location.ProviderRequest;
87 import com.android.server.power.BatterySaverPolicy;
88 import com.android.server.power.BatterySaverPolicy.ServiceType;
90 import libcore.io.IoUtils;
93 import java.io.FileDescriptor;
94 import java.io.FileInputStream;
95 import java.io.IOException;
96 import java.io.PrintWriter;
97 import java.net.InetAddress;
98 import java.net.UnknownHostException;
99 import java.util.ArrayList;
100 import java.util.Arrays;
101 import java.util.Date;
102 import java.util.List;
103 import java.util.Map.Entry;
104 import java.util.Properties;
105 import java.util.Map;
106 import java.util.HashMap;
109 * A GNSS implementation of LocationProvider used by LocationManager.
113 public class GnssLocationProvider implements LocationProviderInterface {
115 private static final String TAG = "GnssLocationProvider";
117 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
118 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
120 private static final ProviderProperties PROPERTIES = new ProviderProperties(
121 true, true, false, false, true, true, true,
122 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
124 // these need to match GnssPositionMode enum in IGnss.hal
125 private static final int GPS_POSITION_MODE_STANDALONE = 0;
126 private static final int GPS_POSITION_MODE_MS_BASED = 1;
127 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
129 // these need to match GnssPositionRecurrence enum in IGnss.hal
130 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
131 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
133 // these need to match GnssStatusValue enum in IGnssCallback.hal
134 private static final int GPS_STATUS_NONE = 0;
135 private static final int GPS_STATUS_SESSION_BEGIN = 1;
136 private static final int GPS_STATUS_SESSION_END = 2;
137 private static final int GPS_STATUS_ENGINE_ON = 3;
138 private static final int GPS_STATUS_ENGINE_OFF = 4;
140 // these need to match AGnssStatusValue enum in IAGnssCallback.hal
141 /** AGPS status event values. */
142 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
143 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
144 private static final int GPS_AGPS_DATA_CONNECTED = 3;
145 private static final int GPS_AGPS_DATA_CONN_DONE = 4;
146 private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
148 // these need to match GnssLocationFlags enum in types.hal
149 private static final int LOCATION_INVALID = 0;
150 private static final int LOCATION_HAS_LAT_LONG = 1;
151 private static final int LOCATION_HAS_ALTITUDE = 2;
152 private static final int LOCATION_HAS_SPEED = 4;
153 private static final int LOCATION_HAS_BEARING = 8;
154 private static final int LOCATION_HAS_HORIZONTAL_ACCURACY = 16;
155 private static final int LOCATION_HAS_VERTICAL_ACCURACY = 32;
156 private static final int LOCATION_HAS_SPEED_ACCURACY = 64;
157 private static final int LOCATION_HAS_BEARING_ACCURACY = 128;
160 // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal
161 private static final int GPS_DELETE_EPHEMERIS = 0x0001;
162 private static final int GPS_DELETE_ALMANAC = 0x0002;
163 private static final int GPS_DELETE_POSITION = 0x0004;
164 private static final int GPS_DELETE_TIME = 0x0008;
165 private static final int GPS_DELETE_IONO = 0x0010;
166 private static final int GPS_DELETE_UTC = 0x0020;
167 private static final int GPS_DELETE_HEALTH = 0x0040;
168 private static final int GPS_DELETE_SVDIR = 0x0080;
169 private static final int GPS_DELETE_SVSTEER = 0x0100;
170 private static final int GPS_DELETE_SADATA = 0x0200;
171 private static final int GPS_DELETE_RTI = 0x0400;
172 private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
173 private static final int GPS_DELETE_ALL = 0xFFFF;
175 // The GPS_CAPABILITY_* flags must match Capabilities enum in IGnssCallback.hal
176 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
177 private static final int GPS_CAPABILITY_MSB = 0x0000002;
178 private static final int GPS_CAPABILITY_MSA = 0x0000004;
179 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
180 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
181 private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
182 private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
183 private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
185 // The AGPS SUPL mode
186 private static final int AGPS_SUPL_MODE_MSA = 0x02;
187 private static final int AGPS_SUPL_MODE_MSB = 0x01;
189 // these need to match AGnssType enum in IAGnssCallback.hal
190 private static final int AGPS_TYPE_SUPL = 1;
191 private static final int AGPS_TYPE_C2K = 2;
193 // these must match the ApnIpType enum in IAGnss.hal
194 private static final int APN_INVALID = 0;
195 private static final int APN_IPV4 = 1;
196 private static final int APN_IPV6 = 2;
197 private static final int APN_IPV4V6 = 3;
199 // for mAGpsDataConnectionState
200 private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
201 private static final int AGPS_DATA_CONNECTION_OPENING = 1;
202 private static final int AGPS_DATA_CONNECTION_OPEN = 2;
205 private static final int CHECK_LOCATION = 1;
206 private static final int ENABLE = 2;
207 private static final int SET_REQUEST = 3;
208 private static final int UPDATE_NETWORK_STATE = 4;
209 private static final int INJECT_NTP_TIME = 5;
210 private static final int DOWNLOAD_XTRA_DATA = 6;
211 private static final int UPDATE_LOCATION = 7;
212 private static final int ADD_LISTENER = 8;
213 private static final int REMOVE_LISTENER = 9;
214 private static final int INJECT_NTP_TIME_FINISHED = 10;
215 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
216 private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
217 private static final int INITIALIZE_HANDLER = 13;
218 private static final int REQUEST_SUPL_CONNECTION = 14;
219 private static final int RELEASE_SUPL_CONNECTION = 15;
222 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
223 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
225 //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
226 private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
228 // ref. location info
229 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
230 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
233 private static final int AGPS_SETID_TYPE_NONE = 0;
234 private static final int AGPS_SETID_TYPE_IMSI = 1;
235 private static final int AGPS_SETID_TYPE_MSISDN = 2;
237 private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
238 private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
240 // GPS Geofence errors. Should match GeofenceStatus enum in IGnssGeofenceCallback.hal.
241 private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
242 private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
243 private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
244 private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
245 private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
246 private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
249 // Valid TCP/UDP port range is (0, 65535].
250 private static final int TCP_MIN_PORT = 0;
251 private static final int TCP_MAX_PORT = 0xffff;
253 /** simpler wrapper for ProviderRequest + Worksource */
254 private static class GpsRequest {
255 public ProviderRequest request;
256 public WorkSource source;
257 public GpsRequest(ProviderRequest request, WorkSource source) {
258 this.request = request;
259 this.source = source;
263 private Object mLock = new Object();
266 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
268 // time for last status update
269 private long mStatusUpdateTime = SystemClock.elapsedRealtime();
271 // turn off GPS fix icon if we haven't received a fix in 10 seconds
272 private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
274 // stop trying if we do not receive a fix within 60 seconds
275 private static final int NO_FIX_TIMEOUT = 60 * 1000;
277 // if the fix interval is below this we leave GPS on,
278 // if above then we cycle the GPS driver.
279 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
280 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
282 // how often to request NTP time, in milliseconds
283 // current setting 24 hours
284 private static final long NTP_INTERVAL = 24*60*60*1000;
285 // how long to wait if we have a network error in NTP or XTRA downloading
286 // the initial value of the exponential backoff
287 // current setting - 5 minutes
288 private static final long RETRY_INTERVAL = 5*60*1000;
289 // how long to wait if we have a network error in NTP or XTRA downloading
290 // the max value of the exponential backoff
291 // current setting - 4 hours
292 private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
294 // Timeout when holding wakelocks for downloading XTRA data.
295 private static final long DOWNLOAD_XTRA_DATA_TIMEOUT_MS = 60 * 1000;
297 private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
298 private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
300 // true if we are enabled, protected by this
301 private boolean mEnabled;
303 // states for injecting ntp and downloading xtra data
304 private static final int STATE_PENDING_NETWORK = 0;
305 private static final int STATE_DOWNLOADING = 1;
306 private static final int STATE_IDLE = 2;
308 // flags to trigger NTP or XTRA data download when network becomes available
309 // initialized to true so we do NTP and XTRA when the network comes up after booting
310 private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
311 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
313 // set to true if the GPS engine requested on-demand NTP time requests
314 private boolean mOnDemandTimeInjection;
316 // true if GPS is navigating
317 private boolean mNavigating;
319 // true if GPS engine is on
320 private boolean mEngineOn;
322 // requested frequency of fixes, in milliseconds
323 private int mFixInterval = 1000;
325 // true if we started navigation
326 private boolean mStarted;
328 // true if single shot request is in progress
329 private boolean mSingleShot;
331 // capabilities of the GPS engine
332 private int mEngineCapabilities;
334 // true if XTRA is supported
335 private boolean mSupportsXtra;
337 // for calculating time to first fix
338 private long mFixRequestTime = 0;
339 // time to first fix for most recent session
340 private int mTimeToFirstFix = 0;
341 // time we received our last fix
342 private long mLastFixTime;
344 private int mPositionMode;
346 // Current request from underlying location clients.
347 private ProviderRequest mProviderRequest = null;
348 // Current list of underlying location clients.
349 private WorkSource mWorkSource = null;
350 // True if gps should be disabled (used to support battery saver mode in settings).
351 private boolean mDisableGps = false;
354 * Properties loaded from PROPERTIES_FILE.
355 * It must be accessed only inside {@link #mHandler}.
357 private Properties mProperties;
359 private String mSuplServerHost;
360 private int mSuplServerPort = TCP_MIN_PORT;
361 private String mC2KServerHost;
362 private int mC2KServerPort;
363 private boolean mSuplEsEnabled = false;
365 private final Context mContext;
366 private final NtpTrustedTime mNtpTime;
367 private final ILocationManager mILocationManager;
368 private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
369 private Bundle mLocationExtras = new Bundle();
370 private final GnssStatusListenerHelper mListenerHelper;
371 private final GnssMeasurementsProvider mGnssMeasurementsProvider;
372 private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
374 // Handler for processing events
375 private Handler mHandler;
377 /** It must be accessed only inside {@link #mHandler}. */
378 private int mAGpsDataConnectionState;
379 /** It must be accessed only inside {@link #mHandler}. */
380 private InetAddress mAGpsDataConnectionIpAddr;
382 private final ConnectivityManager mConnMgr;
383 private final GpsNetInitiatedHandler mNIHandler;
386 private final static String WAKELOCK_KEY = "GnssLocationProvider";
387 private final PowerManager.WakeLock mWakeLock;
388 private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderXtraDownload";
389 private final PowerManager.WakeLock mDownloadXtraWakeLock;
392 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
393 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
396 private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
398 // Persist property for LPP_PROFILE
399 private final static String LPP_PROFILE = "persist.sys.gps.lpp";
403 private final PowerManager mPowerManager;
404 private final AlarmManager mAlarmManager;
405 private final PendingIntent mWakeupIntent;
406 private final PendingIntent mTimeoutIntent;
408 private final IAppOpsService mAppOpsService;
409 private final IBatteryStats mBatteryStats;
411 // only modified on handler thread
412 private WorkSource mClientSource = new WorkSource();
414 private GeofenceHardwareImpl mGeofenceHardwareImpl;
415 private int mYearOfHardware = 0;
417 // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
418 // stops output right at 600m/s, depriving this of the information of a device that reaches
419 // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
420 private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
421 private boolean mItarSpeedLimitExceeded = false;
424 private GnssMetrics mGnssMetrics;
426 private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
428 public void registerGnssStatusCallback(IGnssStatusListener callback) {
429 mListenerHelper.addListener(callback);
433 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
434 mListenerHelper.removeListener(callback);
438 public IGnssStatusProvider getGnssStatusProvider() {
439 return mGnssStatusProvider;
442 public IGpsGeofenceHardware getGpsGeofenceProxy() {
443 return mGpsGeofenceBinder;
446 public GnssMeasurementsProvider getGnssMeasurementsProvider() {
447 return mGnssMeasurementsProvider;
450 public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
451 return mGnssNavigationMessageProvider;
455 * Callback used to listen for data connectivity changes.
457 private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
458 new ConnectivityManager.NetworkCallback() {
460 public void onAvailable(Network network) {
461 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
464 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
465 xtraDownloadRequest();
467 // Always on, notify HAL so it can get data it needs
468 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
472 public void onLost(Network network) {
473 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
478 * Callback used to listen for availability of a requested SUPL connection.
479 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
480 * manage the registration/un-registration lifetimes separate.
482 private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
483 new ConnectivityManager.NetworkCallback() {
485 public void onAvailable(Network network) {
486 // Specific to a change to a SUPL enabled network becoming ready
487 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
491 public void onLost(Network network) {
492 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
496 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
497 @Override public void onReceive(Context context, Intent intent) {
498 String action = intent.getAction();
499 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
500 if (action == null) {
504 if (action.equals(ALARM_WAKEUP)) {
505 startNavigating(false);
506 } else if (action.equals(ALARM_TIMEOUT)) {
508 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
509 || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
510 || Intent.ACTION_SCREEN_OFF.equals(action)
511 || Intent.ACTION_SCREEN_ON.equals(action)) {
512 updateLowPowerMode();
513 } else if (action.equals(SIM_STATE_CHANGED)) {
514 subscriptionOrSimChanged(context);
519 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
520 new OnSubscriptionsChangedListener() {
522 public void onSubscriptionsChanged() {
523 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
527 private void subscriptionOrSimChanged(Context context) {
528 if (DEBUG) Log.d(TAG, "received SIM related action: ");
529 TelephonyManager phone = (TelephonyManager)
530 mContext.getSystemService(Context.TELEPHONY_SERVICE);
531 CarrierConfigManager configManager = (CarrierConfigManager)
532 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
533 String mccMnc = phone.getSimOperator();
534 boolean isKeepLppProfile = false;
535 if (!TextUtils.isEmpty(mccMnc)) {
536 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
537 synchronized (mLock) {
538 if (configManager != null) {
539 PersistableBundle b = configManager.getConfig();
540 isKeepLppProfile = b.getBoolean(CarrierConfigManager.KEY_PERSIST_LPP_MODE_BOOL);
542 if (isKeepLppProfile) {
543 // load current properties for the carrier
544 loadPropertiesFromResource(context, mProperties);
545 String lpp_profile = mProperties.getProperty("LPP_PROFILE");
546 // set the persist property LPP_PROFILE for the value
547 if (lpp_profile != null) {
548 SystemProperties.set(LPP_PROFILE, lpp_profile);
551 // reset the persist property
552 SystemProperties.set(LPP_PROFILE, "");
554 reloadGpsProperties(context, mProperties);
555 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
558 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
562 private void updateLowPowerMode() {
563 // Disable GPS if we are in device idle mode.
564 boolean disableGps = mPowerManager.isDeviceIdleMode();
565 final PowerSaveState result =
566 mPowerManager.getPowerSaveState(ServiceType.GPS);
567 switch (result.gpsMode) {
568 case BatterySaverPolicy.GPS_MODE_DISABLED_WHEN_SCREEN_OFF:
569 // If we are in battery saver mode and the screen is off, disable GPS.
570 disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive();
573 if (disableGps != mDisableGps) {
574 mDisableGps = disableGps;
575 updateRequirements();
579 public static boolean isSupported() {
580 return native_is_supported();
583 interface SetCarrierProperty {
584 public boolean set(int value);
587 private void reloadGpsProperties(Context context, Properties properties) {
588 if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
589 loadPropertiesFromResource(context, properties);
591 String lpp_prof = SystemProperties.get(LPP_PROFILE);
592 if (!TextUtils.isEmpty(lpp_prof)) {
593 // override default value of this if lpp_prof is not empty
594 properties.setProperty("LPP_PROFILE", lpp_prof);
597 * Overlay carrier properties from a debug configuration file.
599 loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
600 // TODO: we should get rid of C2K specific setting.
601 setSuplHostPort(properties.getProperty("SUPL_HOST"),
602 properties.getProperty("SUPL_PORT"));
603 mC2KServerHost = properties.getProperty("C2K_HOST");
604 String portString = properties.getProperty("C2K_PORT");
605 if (mC2KServerHost != null && portString != null) {
607 mC2KServerPort = Integer.parseInt(portString);
608 } catch (NumberFormatException e) {
609 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
612 if (native_is_gnss_configuration_supported()) {
613 Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
615 put("SUPL_VER", (val) -> native_set_supl_version(val));
616 put("SUPL_MODE", (val) -> native_set_supl_mode(val));
617 put("SUPL_ES", (val) -> native_set_supl_es(val));
618 put("LPP_PROFILE", (val) -> native_set_lpp_profile(val));
619 put("A_GLONASS_POS_PROTOCOL_SELECT", (val) -> native_set_gnss_pos_protocol_select(val));
620 put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", (val) -> native_set_emergency_supl_pdn(val));
621 put("GPS_LOCK", (val) -> native_set_gps_lock(val));
625 for(Entry<String, SetCarrierProperty> entry : map.entrySet()) {
626 String propertyName = entry.getKey();
627 String propertyValueString = properties.getProperty(propertyName);
628 if (propertyValueString != null) {
630 int propertyValueInt = Integer.decode(propertyValueString);
631 boolean result = entry.getValue().set(propertyValueInt);
632 if (result == false) {
633 Log.e(TAG, "Unable to set " + propertyName);
635 } catch (NumberFormatException e) {
636 Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
641 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
645 // SUPL_ES configuration.
646 String suplESProperty = mProperties.getProperty("SUPL_ES");
647 if (suplESProperty != null) {
649 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
650 } catch (NumberFormatException e) {
651 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
655 String emergencyExtensionSecondsString
656 = properties.getProperty("ES_EXTENSION_SEC", "0");
658 int emergencyExtensionSeconds =
659 Integer.parseInt(emergencyExtensionSecondsString);
660 mNIHandler.setEmergencyExtensionSeconds(emergencyExtensionSeconds);
661 } catch (NumberFormatException e) {
662 Log.e(TAG, "unable to parse ES_EXTENSION_SEC: "
663 + emergencyExtensionSecondsString);
667 private void loadPropertiesFromResource(Context context,
668 Properties properties) {
669 String[] configValues = context.getResources().getStringArray(
670 com.android.internal.R.array.config_gpsParameters);
671 for (String item : configValues) {
672 if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
673 // We need to support "KEY =", but not "=VALUE".
674 String[] split = item.split("=");
675 if (split.length == 2) {
676 properties.setProperty(split[0].trim().toUpperCase(), split[1]);
678 Log.w(TAG, "malformed contents: " + item);
683 private boolean loadPropertiesFromFile(String filename,
684 Properties properties) {
686 File file = new File(filename);
687 FileInputStream stream = null;
689 stream = new FileInputStream(file);
690 properties.load(stream);
692 IoUtils.closeQuietly(stream);
695 } catch (IOException e) {
696 if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename);
702 public GnssLocationProvider(Context context, ILocationManager ilocationManager,
705 mNtpTime = NtpTrustedTime.getInstance(context);
706 mILocationManager = ilocationManager;
708 mLocation.setExtras(mLocationExtras);
710 // Create a wake lock
711 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
712 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
713 mWakeLock.setReferenceCounted(true);
715 // Create a separate wake lock for xtra downloader as it may be released due to timeout.
716 mDownloadXtraWakeLock = mPowerManager.newWakeLock(
717 PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY);
718 mDownloadXtraWakeLock.setReferenceCounted(true);
720 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
721 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
722 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
724 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
726 // App ops service to keep track of who is accessing the GPS
727 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
728 Context.APP_OPS_SERVICE));
730 // Battery statistics service to be notified when GPS turns on or off
731 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
732 BatteryStats.SERVICE_NAME));
734 // Construct internal handler
735 mHandler = new ProviderHandler(looper);
737 // Load GPS configuration and register listeners in the background:
738 // some operations, such as opening files and registering broadcast receivers, can take a
739 // relative long time, so the ctor() is kept to create objects needed by this instance,
740 // while IO initialization and registration is delegated to our internal handler
741 // this approach is just fine because events are posted to our handler anyway
742 mProperties = new Properties();
743 // Create a GPS net-initiated handler (also needed by handleInitialize)
744 mNIHandler = new GpsNetInitiatedHandler(context,
745 mNetInitiatedListener,
747 sendMessage(INITIALIZE_HANDLER, 0, null);
749 mListenerHelper = new GnssStatusListenerHelper(mHandler) {
751 protected boolean isAvailableInPlatform() {
752 return isSupported();
756 protected boolean isGpsEnabled() {
761 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) {
763 public boolean isAvailableInPlatform() {
764 return native_is_measurement_supported();
768 protected boolean registerWithService() {
769 return native_start_measurement_collection();
773 protected void unregisterFromService() {
774 native_stop_measurement_collection();
778 protected boolean isGpsEnabled() {
783 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
785 protected boolean isAvailableInPlatform() {
786 return native_is_navigation_message_supported();
790 protected boolean registerWithService() {
791 return native_start_navigation_message_collection();
795 protected void unregisterFromService() {
796 native_stop_navigation_message_collection();
800 protected boolean isGpsEnabled() {
804 mGnssMetrics = new GnssMetrics();
807 * A cycle of native_init() and native_cleanup() is needed so that callbacks are registered
808 * after bootup even when location is disabled. This will allow Emergency SUPL to work even
809 * when location is disabled before device restart.
811 boolean isInitialized = native_init();
813 Log.d(TAG, "Failed to initialize at bootup");
820 * Returns the name of this provider.
823 public String getName() {
824 return LocationManager.GPS_PROVIDER;
828 public ProviderProperties getProperties() {
832 private void handleUpdateNetworkState(Network network) {
833 // retrieve NetworkInfo for this UID
834 NetworkInfo info = mConnMgr.getNetworkInfo(network);
836 boolean networkAvailable = false;
837 boolean isConnected = false;
838 int type = ConnectivityManager.TYPE_NONE;
839 boolean isRoaming = false;
840 String apnName = null;
843 networkAvailable = info.isAvailable() && TelephonyManager.getDefault().getDataEnabled();
844 isConnected = info.isConnected();
845 type = info.getType();
846 isRoaming = info.isRoaming();
847 apnName = info.getExtraInfo();
851 String message = String.format(
852 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
853 agpsDataConnStateAsString(),
856 mConnMgr.getNetworkCapabilities(network));
860 if (native_is_agps_ril_supported()) {
861 String defaultApn = getSelectedApn();
862 if (defaultApn == null) {
863 defaultApn = "dummy-apn";
866 native_update_network_state(
874 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
877 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
879 if (apnName == null) {
880 // assign a dummy value in the case of C2K as otherwise we will have a runtime
881 // exception in the following call to native_agps_data_conn_open
882 apnName = "dummy-apn";
884 int apnIpType = getApnIpType(apnName);
887 String message = String.format(
888 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
893 native_agps_data_conn_open(apnName, apnIpType);
894 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
896 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
901 private void handleRequestSuplConnection(InetAddress address) {
903 String message = String.format(
904 "requestSuplConnection, state=%s, address=%s",
905 agpsDataConnStateAsString(),
910 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
913 mAGpsDataConnectionIpAddr = address;
914 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
916 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
917 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
918 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
919 NetworkRequest request = requestBuilder.build();
920 mConnMgr.requestNetwork(
922 mSuplConnectivityCallback);
925 private void handleReleaseSuplConnection(int agpsDataConnStatus) {
927 String message = String.format(
928 "releaseSuplConnection, state=%s, status=%s",
929 agpsDataConnStateAsString(),
930 agpsDataConnStatusAsString(agpsDataConnStatus));
934 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
937 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
939 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
940 switch (agpsDataConnStatus) {
941 case GPS_AGPS_DATA_CONN_FAILED:
942 native_agps_data_conn_failed();
944 case GPS_RELEASE_AGPS_DATA_CONN:
945 native_agps_data_conn_closed();
948 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
952 private void handleInjectNtpTime() {
953 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
954 // already downloading data
957 if (!isDataNetworkConnected()) {
958 // try again when network is up
959 mInjectNtpTimePending = STATE_PENDING_NETWORK;
962 mInjectNtpTimePending = STATE_DOWNLOADING;
964 // hold wake lock while task runs
966 Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
967 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
972 // force refresh NTP cache when outdated
973 boolean refreshSuccess = true;
974 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
975 refreshSuccess = mNtpTime.forceRefresh();
978 // only update when NTP time is fresh
979 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
980 long time = mNtpTime.getCachedNtpTime();
981 long timeReference = mNtpTime.getCachedNtpTimeReference();
982 long certainty = mNtpTime.getCacheCertainty();
985 long now = System.currentTimeMillis();
986 Log.d(TAG, "NTP server returned: "
987 + time + " (" + new Date(time)
988 + ") reference: " + timeReference
989 + " certainty: " + certainty
990 + " system time offset: " + (time - now));
993 native_inject_time(time, timeReference, (int) certainty);
994 delay = NTP_INTERVAL;
997 Log.e(TAG, "requestTime failed");
998 delay = mNtpBackOff.nextBackoffMillis();
1001 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
1004 String message = String.format(
1005 "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
1006 mOnDemandTimeInjection,
1009 Log.d(TAG, message);
1011 if (mOnDemandTimeInjection || !refreshSuccess) {
1012 // send delayed message for next NTP injection
1013 // since this is delayed and not urgent we do not hold a wake lock here
1014 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
1017 // release wake lock held by task
1018 mWakeLock.release();
1019 Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
1024 private void handleDownloadXtraData() {
1025 if (!mSupportsXtra) {
1026 // native code reports xtra not supported, don't try
1027 Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
1030 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
1031 // already downloading data
1034 if (!isDataNetworkConnected()) {
1035 // try again when network is up
1036 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
1039 mDownloadXtraDataPending = STATE_DOWNLOADING;
1041 // hold wake lock while task runs
1042 mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
1043 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
1044 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1047 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
1048 byte[] data = xtraDownloader.downloadXtraData();
1050 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
1051 native_inject_xtra_data(data, data.length);
1052 mXtraBackOff.reset();
1055 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
1059 // since this is delayed and not urgent we do not hold a wake lock here
1060 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
1061 mXtraBackOff.nextBackoffMillis());
1064 // Release wake lock held by task, synchronize on mLock in case multiple
1065 // download tasks overrun.
1066 synchronized (mLock) {
1067 if (mDownloadXtraWakeLock.isHeld()) {
1068 // This wakelock may have time-out, if a timeout was specified.
1069 // Catch (and ignore) any timeout exceptions.
1071 mDownloadXtraWakeLock.release();
1072 if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
1073 } catch (Exception e) {
1074 Log.i(TAG, "Wakelock timeout & release race exception in "
1075 + "handleDownloadXtraData()", e);
1078 Log.e(TAG, "WakeLock expired before release in "
1079 + "handleDownloadXtraData()");
1086 private void handleUpdateLocation(Location location) {
1087 if (location.hasAccuracy()) {
1088 native_inject_location(location.getLatitude(), location.getLongitude(),
1089 location.getAccuracy());
1094 * Enables this provider. When enabled, calls to getStatus()
1095 * must be handled. Hardware may be started up
1096 * when the provider is enabled.
1099 public void enable() {
1100 synchronized (mLock) {
1101 if (mEnabled) return;
1105 sendMessage(ENABLE, 1, null);
1108 private void setSuplHostPort(String hostString, String portString) {
1109 if (hostString != null) {
1110 mSuplServerHost = hostString;
1112 if (portString != null) {
1114 mSuplServerPort = Integer.parseInt(portString);
1115 } catch (NumberFormatException e) {
1116 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1119 if (mSuplServerHost != null
1120 && mSuplServerPort > TCP_MIN_PORT
1121 && mSuplServerPort <= TCP_MAX_PORT) {
1122 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1127 * Checks what SUPL mode to use, according to the AGPS mode as well as the
1128 * allowed mode from properties.
1130 * @param properties GPS properties
1131 * @param agpsEnabled whether AGPS is enabled by settings value
1132 * @param singleShot whether "singleshot" is needed
1133 * @return SUPL mode (MSA vs MSB vs STANDALONE)
1135 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1137 String modeString = properties.getProperty("SUPL_MODE");
1139 if (!TextUtils.isEmpty(modeString)) {
1141 suplMode = Integer.parseInt(modeString);
1142 } catch (NumberFormatException e) {
1143 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1144 return GPS_POSITION_MODE_STANDALONE;
1147 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1148 // such mode when it is available
1149 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1150 return GPS_POSITION_MODE_MS_BASED;
1152 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1153 // do fallback only for single-shot requests, because it is too expensive to do for
1154 // periodic requests as well
1156 && hasCapability(GPS_CAPABILITY_MSA)
1157 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1158 return GPS_POSITION_MODE_MS_ASSISTED;
1161 return GPS_POSITION_MODE_STANDALONE;
1164 private void handleEnable() {
1165 if (DEBUG) Log.d(TAG, "handleEnable");
1167 boolean enabled = native_init();
1170 mSupportsXtra = native_supports_xtra();
1172 // TODO: remove the following native calls if we can make sure they are redundant.
1173 if (mSuplServerHost != null) {
1174 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1176 if (mC2KServerHost != null) {
1177 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1180 mGnssMeasurementsProvider.onGpsEnabledChanged();
1181 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1184 synchronized (mLock) {
1187 Log.w(TAG, "Failed to enable location provider");
1192 * Disables this provider. When disabled, calls to getStatus()
1193 * need not be handled. Hardware may be shut
1194 * down while the provider is disabled.
1197 public void disable() {
1198 synchronized (mLock) {
1199 if (!mEnabled) return;
1203 sendMessage(ENABLE, 0, null);
1206 private void handleDisable() {
1207 if (DEBUG) Log.d(TAG, "handleDisable");
1209 updateClientUids(new WorkSource());
1211 mAlarmManager.cancel(mWakeupIntent);
1212 mAlarmManager.cancel(mTimeoutIntent);
1215 // do this before releasing wakelock
1218 mGnssMeasurementsProvider.onGpsEnabledChanged();
1219 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1223 public boolean isEnabled() {
1224 synchronized (mLock) {
1230 public int getStatus(Bundle extras) {
1231 setLocationExtras(extras);
1235 private void updateStatus(int status, int svCount, int meanCn0, int maxCn0) {
1236 if (status != mStatus || svCount != mSvCount || meanCn0 != mMeanCn0 || maxCn0 != mMaxCn0 ) {
1241 setLocationExtras(mLocationExtras);
1242 mStatusUpdateTime = SystemClock.elapsedRealtime();
1246 private void setLocationExtras(Bundle extras) {
1247 if (extras != null) {
1248 extras.putInt("satellites", mSvCount);
1249 extras.putInt("meanCn0", mMeanCn0);
1250 extras.putInt("maxCn0", mMaxCn0);
1255 public long getStatusUpdateTime() {
1256 return mStatusUpdateTime;
1260 public void setRequest(ProviderRequest request, WorkSource source) {
1261 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1264 private void handleSetRequest(ProviderRequest request, WorkSource source) {
1265 mProviderRequest = request;
1266 mWorkSource = source;
1267 updateRequirements();
1270 // Called when the requirements for GPS may have changed
1271 private void updateRequirements() {
1272 if (mProviderRequest == null || mWorkSource == null) {
1276 boolean singleShot = false;
1278 // see if the request is for a single update
1279 if (mProviderRequest.locationRequests != null
1280 && mProviderRequest.locationRequests.size() > 0) {
1281 // if any request has zero or more than one updates
1282 // requested, then this is not single-shot mode
1285 for (LocationRequest lr : mProviderRequest.locationRequests) {
1286 if (lr.getNumUpdates() != 1) {
1292 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1293 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1294 // update client uids
1295 updateClientUids(mWorkSource);
1297 mFixInterval = (int) mProviderRequest.interval;
1299 // check for overflow
1300 if (mFixInterval != mProviderRequest.interval) {
1301 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1302 mFixInterval = Integer.MAX_VALUE;
1305 // apply request to GPS engine
1306 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1308 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1309 mFixInterval, 0, 0)) {
1310 Log.e(TAG, "set_position_mode failed in setMinTime()");
1312 } else if (!mStarted) {
1314 startNavigating(singleShot);
1317 updateClientUids(new WorkSource());
1320 mAlarmManager.cancel(mWakeupIntent);
1321 mAlarmManager.cancel(mTimeoutIntent);
1325 private void updateClientUids(WorkSource source) {
1326 // Update work source.
1327 WorkSource[] changes = mClientSource.setReturningDiffs(source);
1328 if (changes == null) {
1331 WorkSource newWork = changes[0];
1332 WorkSource goneWork = changes[1];
1334 // Update sources that were not previously tracked.
1335 if (newWork != null) {
1337 for (int i=0; i<newWork.size(); i++) {
1339 int uid = newWork.get(i);
1340 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
1341 AppOpsManager.OP_GPS, uid, newWork.getName(i));
1342 if (uid != lastuid) {
1344 mBatteryStats.noteStartGps(uid);
1346 } catch (RemoteException e) {
1347 Log.w(TAG, "RemoteException", e);
1352 // Update sources that are no longer tracked.
1353 if (goneWork != null) {
1355 for (int i=0; i<goneWork.size(); i++) {
1357 int uid = goneWork.get(i);
1358 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
1359 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
1360 if (uid != lastuid) {
1362 mBatteryStats.noteStopGps(uid);
1364 } catch (RemoteException e) {
1365 Log.w(TAG, "RemoteException", e);
1372 public boolean sendExtraCommand(String command, Bundle extras) {
1374 long identity = Binder.clearCallingIdentity();
1375 boolean result = false;
1377 if ("delete_aiding_data".equals(command)) {
1378 result = deleteAidingData(extras);
1379 } else if ("force_time_injection".equals(command)) {
1382 } else if ("force_xtra_injection".equals(command)) {
1383 if (mSupportsXtra) {
1384 xtraDownloadRequest();
1388 Log.w(TAG, "sendExtraCommand: unknown command " + command);
1391 Binder.restoreCallingIdentity(identity);
1395 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
1396 public boolean isHardwareGeofenceSupported() {
1397 return native_is_geofence_supported();
1400 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
1401 double longitude, double radius, int lastTransition, int monitorTransitions,
1402 int notificationResponsiveness, int unknownTimer) {
1403 return native_add_geofence(geofenceId, latitude, longitude, radius,
1404 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
1407 public boolean removeHardwareGeofence(int geofenceId) {
1408 return native_remove_geofence(geofenceId);
1411 public boolean pauseHardwareGeofence(int geofenceId) {
1412 return native_pause_geofence(geofenceId);
1415 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
1416 return native_resume_geofence(geofenceId, monitorTransition);
1420 private boolean deleteAidingData(Bundle extras) {
1423 if (extras == null) {
1424 flags = GPS_DELETE_ALL;
1427 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1428 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1429 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1430 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1431 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1432 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1433 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1434 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1435 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1436 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1437 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1438 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1439 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1443 native_delete_aiding_data(flags);
1450 private void startNavigating(boolean singleShot) {
1452 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1453 mTimeToFirstFix = 0;
1456 mSingleShot = singleShot;
1457 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1458 // Notify about suppressed output, if speed limit was previously exceeded.
1459 // Elsewhere, we check again with every speed output reported.
1460 if (mItarSpeedLimitExceeded) {
1461 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited " +
1462 "until slow enough speed reported.");
1465 boolean agpsEnabled =
1466 (Settings.Global.getInt(mContext.getContentResolver(),
1467 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1468 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1473 switch(mPositionMode) {
1474 case GPS_POSITION_MODE_STANDALONE:
1475 mode = "standalone";
1477 case GPS_POSITION_MODE_MS_ASSISTED:
1478 mode = "MS_ASSISTED";
1480 case GPS_POSITION_MODE_MS_BASED:
1487 Log.d(TAG, "setting position_mode to " + mode);
1490 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1491 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1494 Log.e(TAG, "set_position_mode failed in startNavigating()");
1497 if (!native_start()) {
1499 Log.e(TAG, "native_start failed in startNavigating()");
1503 // reset SV count to zero
1504 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
1505 mFixRequestTime = SystemClock.elapsedRealtime();
1506 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1507 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1508 // and our fix interval is not short
1509 if (mFixInterval >= NO_FIX_TIMEOUT) {
1510 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1511 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1517 private void stopNavigating() {
1518 if (DEBUG) Log.d(TAG, "stopNavigating");
1521 mSingleShot = false;
1523 mTimeToFirstFix = 0;
1526 // reset SV count to zero
1527 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
1531 private void hibernate() {
1532 // stop GPS until our next fix interval arrives
1534 mAlarmManager.cancel(mTimeoutIntent);
1535 mAlarmManager.cancel(mWakeupIntent);
1536 long now = SystemClock.elapsedRealtime();
1537 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1540 private boolean hasCapability(int capability) {
1541 return ((mEngineCapabilities & capability) != 0);
1546 * called from native code to update our position.
1548 private void reportLocation(boolean hasLatLong, Location location) {
1549 if (location.hasSpeed()) {
1550 mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
1553 if (mItarSpeedLimitExceeded) {
1554 Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
1555 " GPS/GNSS Navigation output blocked.");
1556 mGnssMetrics.logReceivedLocationStatus(false);
1557 return; // No output of location allowed
1560 if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString());
1562 synchronized (mLocation) {
1563 mLocation = location;
1564 // It would be nice to push the elapsed real-time timestamp
1565 // further down the stack, but this is still useful
1566 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1567 mLocation.setExtras(mLocationExtras);
1570 mILocationManager.reportLocation(mLocation, false);
1571 } catch (RemoteException e) {
1572 Log.e(TAG, "RemoteException calling reportLocation");
1576 mGnssMetrics.logReceivedLocationStatus(hasLatLong);
1578 if (location.hasAccuracy()) {
1579 mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy());
1581 if (mTimeToFirstFix > 0) {
1582 int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime);
1583 mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
1587 mLastFixTime = SystemClock.elapsedRealtime();
1588 // report time to first fix
1589 if (mTimeToFirstFix == 0 && hasLatLong) {
1590 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1591 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1592 mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
1594 // notify status listeners
1595 mListenerHelper.onFirstFix(mTimeToFirstFix);
1602 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1603 // we want to time out if we do not receive a fix
1604 // within the time out and we are requesting infrequent fixes
1605 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1606 mAlarmManager.cancel(mTimeoutIntent);
1609 // send an intent to notify that the GPS is receiving fixes.
1610 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1611 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1612 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1613 updateStatus(LocationProvider.AVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
1616 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1617 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1618 if (DEBUG) Log.d(TAG, "got fix, hibernating");
1624 * called from native code to update our status
1626 private void reportStatus(int status) {
1627 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1629 boolean wasNavigating = mNavigating;
1631 case GPS_STATUS_SESSION_BEGIN:
1635 case GPS_STATUS_SESSION_END:
1636 mNavigating = false;
1638 case GPS_STATUS_ENGINE_ON:
1641 case GPS_STATUS_ENGINE_OFF:
1643 mNavigating = false;
1647 if (wasNavigating != mNavigating) {
1648 mListenerHelper.onStatusChanged(mNavigating);
1650 // send an intent to notify that the GPS has been enabled or disabled
1651 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1652 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1653 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1658 * called from native code to update SV info
1660 private void reportSvStatus() {
1661 int svCount = native_read_sv_status(mSvidWithFlags,
1666 mListenerHelper.onSvStatusChanged(
1674 // Log CN0 as part of GNSS metrics
1675 mGnssMetrics.logCn0(mCn0s, svCount);
1678 Log.v(TAG, "SV count: " + svCount);
1680 // Calculate number of satellites used in fix.
1681 int usedInFixCount = 0;
1684 for (int i = 0; i < svCount; i++) {
1685 if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1687 if (mCn0s[i] > maxCn0) {
1688 maxCn0 = (int)mCn0s[i];
1690 meanCn0 += mCn0s[i];
1693 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1694 " cn0: " + mCn0s[i] +
1695 " elev: " + mSvElevations[i] +
1696 " azimuth: " + mSvAzimuths[i] +
1697 " carrier frequency: " + mSvCarrierFreqs[i] +
1698 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1700 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1702 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1704 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0
1708 if (usedInFixCount > 0) {
1709 meanCn0 /= usedInFixCount;
1711 // return number of sats used in fix instead of total reported
1712 updateStatus(mStatus, usedInFixCount, meanCn0, maxCn0);
1714 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1715 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1716 // send an intent to notify that the GPS is no longer receiving fixes.
1717 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1718 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1719 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1720 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
1725 * called from native code to update AGPS status
1727 private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1729 case GPS_REQUEST_AGPS_DATA_CONN:
1730 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1731 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1732 InetAddress connectionIpAddress = null;
1733 if (ipaddr != null) {
1735 connectionIpAddress = InetAddress.getByAddress(ipaddr);
1736 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1737 } catch (UnknownHostException e) {
1738 Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1741 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1743 case GPS_RELEASE_AGPS_DATA_CONN:
1744 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1745 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1747 case GPS_AGPS_DATA_CONNECTED:
1748 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1750 case GPS_AGPS_DATA_CONN_DONE:
1751 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1753 case GPS_AGPS_DATA_CONN_FAILED:
1754 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1757 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1761 private void releaseSuplConnection(int connStatus) {
1762 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1766 * called from native code to report NMEA data received
1768 private void reportNmea(long timestamp) {
1769 if (!mItarSpeedLimitExceeded) {
1770 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1771 String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1772 mListenerHelper.onNmeaReceived(timestamp, nmea);
1777 * called from native code - GNSS measurements callback
1779 private void reportMeasurementData(GnssMeasurementsEvent event) {
1780 if (!mItarSpeedLimitExceeded) {
1781 // send to handler to allow native to return quickly
1782 mHandler.post(new Runnable() {
1785 mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1792 * called from native code - GNSS navigation message callback
1794 private void reportNavigationMessage(GnssNavigationMessage event) {
1795 if (!mItarSpeedLimitExceeded) {
1796 // send to handler to allow native to return quickly
1797 mHandler.post(new Runnable() {
1800 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1807 * called from native code to inform us what the GPS engine capabilities are
1809 private void setEngineCapabilities(int capabilities) {
1810 mEngineCapabilities = capabilities;
1812 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1813 mOnDemandTimeInjection = true;
1817 mGnssMeasurementsProvider.onCapabilitiesUpdated(
1818 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
1819 mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1820 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
1824 * Called from native code to inform us the hardware information.
1826 private void setGnssYearOfHardware(int yearOfHardware) {
1827 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1828 mYearOfHardware = yearOfHardware;
1831 public interface GnssSystemInfoProvider {
1833 * Returns the year of GPS hardware.
1835 int getGnssYearOfHardware();
1841 public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1842 return new GnssSystemInfoProvider() {
1844 public int getGnssYearOfHardware() {
1845 return mYearOfHardware;
1850 public interface GnssBatchingProvider {
1852 * Returns the GNSS batching size
1856 * Starts the hardware batching operation
1858 boolean start(long periodNanos, boolean wakeOnFifoFull);
1860 * Forces a flush of existing locations from the hardware batching
1864 * Stops the batching operation
1872 public GnssBatchingProvider getGnssBatchingProvider() {
1873 return new GnssBatchingProvider() {
1875 public int getSize() {
1876 return native_get_batch_size();
1879 public boolean start(long periodNanos, boolean wakeOnFifoFull) {
1880 if (periodNanos <= 0) {
1881 Log.e(TAG, "Invalid periodNanos " + periodNanos +
1882 "in batching request, not started");
1885 return native_start_batch(periodNanos, wakeOnFifoFull);
1888 public void flush() {
1889 native_flush_batch();
1892 public boolean stop() {
1893 return native_stop_batch();
1898 public interface GnssMetricsProvider {
1900 * Returns GNSS metrics as proto string
1902 String getGnssMetricsAsProtoString();
1908 public GnssMetricsProvider getGnssMetricsProvider() {
1909 return new GnssMetricsProvider() {
1911 public String getGnssMetricsAsProtoString() {
1912 return mGnssMetrics.dumpGnssMetricsAsProtoString();
1918 * Initialize Batching if enabled
1920 private void enableBatching() {
1921 if (!native_init_batching()) {
1922 Log.e(TAG, "Failed to initialize GNSS batching");
1929 private void disableBatching() {
1930 native_stop_batch();
1931 native_cleanup_batching();
1935 * called from native code - GNSS location batch callback
1937 private void reportLocationBatch(Location[] locationArray) {
1938 List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
1939 if(DEBUG) { Log.d(TAG, "Location batch of size " + locationArray.length + "reported"); }
1941 mILocationManager.reportLocationBatch(locations);
1942 } catch (RemoteException e) {
1943 Log.e(TAG, "RemoteException calling reportLocationBatch");
1948 * called from native code to request XTRA data
1950 private void xtraDownloadRequest() {
1951 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1952 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1956 * Converts the GPS HAL status to the internal Geofence Hardware status.
1958 private int getGeofenceStatus(int status) {
1960 case GPS_GEOFENCE_OPERATION_SUCCESS:
1961 return GeofenceHardware.GEOFENCE_SUCCESS;
1962 case GPS_GEOFENCE_ERROR_GENERIC:
1963 return GeofenceHardware.GEOFENCE_FAILURE;
1964 case GPS_GEOFENCE_ERROR_ID_EXISTS:
1965 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1966 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1967 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1968 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1969 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1970 case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1971 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1978 * Called from native to report GPS Geofence transition
1979 * All geofence callbacks are called on the same thread
1981 private void reportGeofenceTransition(int geofenceId, Location location, int transition,
1982 long transitionTimestamp) {
1983 if (mGeofenceHardwareImpl == null) {
1984 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1987 mGeofenceHardwareImpl.reportGeofenceTransition(
1991 transitionTimestamp,
1992 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1993 FusedBatchOptions.SourceTechnologies.GNSS);
1997 * called from native code to report GPS status change.
1999 private void reportGeofenceStatus(int status, Location location) {
2000 if (mGeofenceHardwareImpl == null) {
2001 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2003 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
2004 if(status == GPS_GEOFENCE_AVAILABLE) {
2005 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
2007 mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
2008 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
2011 FusedBatchOptions.SourceTechnologies.GNSS);
2015 * called from native code - Geofence Add callback
2017 private void reportGeofenceAddStatus(int geofenceId, int status) {
2018 if (mGeofenceHardwareImpl == null) {
2019 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2021 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
2025 * called from native code - Geofence Remove callback
2027 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
2028 if (mGeofenceHardwareImpl == null) {
2029 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2031 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
2035 * called from native code - Geofence Pause callback
2037 private void reportGeofencePauseStatus(int geofenceId, int status) {
2038 if (mGeofenceHardwareImpl == null) {
2039 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2041 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
2045 * called from native code - Geofence Resume callback
2047 private void reportGeofenceResumeStatus(int geofenceId, int status) {
2048 if (mGeofenceHardwareImpl == null) {
2049 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2051 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
2054 //=============================================================
2055 // NI Client support
2056 //=============================================================
2057 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
2058 // Sends a response for an NI request to HAL.
2060 public boolean sendNiResponse(int notificationId, int userResponse)
2062 // TODO Add Permission check
2064 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
2065 ", response: " + userResponse);
2066 native_send_ni_response(notificationId, userResponse);
2071 public INetInitiatedListener getNetInitiatedListener() {
2072 return mNetInitiatedListener;
2075 // Called by JNI function to report an NI request.
2076 public void reportNiNotification(
2081 int defaultResponse,
2084 int requestorIdEncoding,
2088 Log.i(TAG, "reportNiNotification: entered");
2089 Log.i(TAG, "notificationId: " + notificationId +
2090 ", niType: " + niType +
2091 ", notifyFlags: " + notifyFlags +
2092 ", timeout: " + timeout +
2093 ", defaultResponse: " + defaultResponse);
2095 Log.i(TAG, "requestorId: " + requestorId +
2097 ", requestorIdEncoding: " + requestorIdEncoding +
2098 ", textEncoding: " + textEncoding);
2100 GpsNiNotification notification = new GpsNiNotification();
2102 notification.notificationId = notificationId;
2103 notification.niType = niType;
2104 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
2105 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
2106 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
2107 notification.timeout = timeout;
2108 notification.defaultResponse = defaultResponse;
2109 notification.requestorId = requestorId;
2110 notification.text = text;
2111 notification.requestorIdEncoding = requestorIdEncoding;
2112 notification.textEncoding = textEncoding;
2114 mNIHandler.handleNiNotification(notification);
2118 * Called from native code to request set id info.
2119 * We should be careful about receiving null string from the TelephonyManager,
2120 * because sending null String to JNI function would cause a crash.
2123 private void requestSetID(int flags) {
2124 TelephonyManager phone = (TelephonyManager)
2125 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2126 int type = AGPS_SETID_TYPE_NONE;
2129 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
2130 String data_temp = phone.getSubscriberId();
2131 if (data_temp == null) {
2132 // This means the framework does not have the SIM card ready.
2134 // This means the framework has the SIM card.
2136 type = AGPS_SETID_TYPE_IMSI;
2139 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
2140 String data_temp = phone.getLine1Number();
2141 if (data_temp == null) {
2142 // This means the framework does not have the SIM card ready.
2144 // This means the framework has the SIM card.
2146 type = AGPS_SETID_TYPE_MSISDN;
2149 native_agps_set_id(type, data);
2153 * Called from native code to request utc time info
2155 private void requestUtcTime() {
2156 if (DEBUG) Log.d(TAG, "utcTimeRequest");
2157 sendMessage(INJECT_NTP_TIME, 0, null);
2161 * Called from native code to request reference location info
2164 private void requestRefLocation() {
2165 TelephonyManager phone = (TelephonyManager)
2166 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2167 final int phoneType = phone.getPhoneType();
2168 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2169 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2170 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2171 && (phone.getNetworkOperator().length() > 3)) {
2173 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
2174 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2175 int networkType = phone.getNetworkType();
2176 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2177 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2178 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2179 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2180 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2181 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2183 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2185 native_agps_set_ref_location_cellid(type, mcc, mnc,
2186 gsm_cell.getLac(), gsm_cell.getCid());
2188 Log.e(TAG,"Error getting cell location info.");
2190 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2191 Log.e(TAG, "CDMA not supported.");
2195 private void sendMessage(int message, int arg, Object obj) {
2196 // hold a wake lock until this message is delivered
2197 // note that this assumes the message will not be removed from the queue before
2198 // it is handled (otherwise the wake lock would be leaked).
2199 mWakeLock.acquire();
2200 if (Log.isLoggable(TAG, Log.INFO)) {
2201 Log.i(TAG, "WakeLock acquired by sendMessage(" + messageIdAsString(message) + ", " + arg
2202 + ", " + obj + ")");
2204 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2207 private final class ProviderHandler extends Handler {
2208 public ProviderHandler(Looper looper) {
2209 super(looper, null, true /*async*/);
2213 public void handleMessage(Message msg) {
2214 int message = msg.what;
2217 if (msg.arg1 == 1) {
2224 GpsRequest gpsRequest = (GpsRequest) msg.obj;
2225 handleSetRequest(gpsRequest.request, gpsRequest.source);
2227 case UPDATE_NETWORK_STATE:
2228 handleUpdateNetworkState((Network) msg.obj);
2230 case REQUEST_SUPL_CONNECTION:
2231 handleRequestSuplConnection((InetAddress) msg.obj);
2233 case RELEASE_SUPL_CONNECTION:
2234 handleReleaseSuplConnection(msg.arg1);
2236 case INJECT_NTP_TIME:
2237 handleInjectNtpTime();
2239 case DOWNLOAD_XTRA_DATA:
2240 handleDownloadXtraData();
2242 case INJECT_NTP_TIME_FINISHED:
2243 mInjectNtpTimePending = STATE_IDLE;
2245 case DOWNLOAD_XTRA_DATA_FINISHED:
2246 mDownloadXtraDataPending = STATE_IDLE;
2248 case UPDATE_LOCATION:
2249 handleUpdateLocation((Location) msg.obj);
2251 case SUBSCRIPTION_OR_SIM_CHANGED:
2252 subscriptionOrSimChanged(mContext);
2254 case INITIALIZE_HANDLER:
2258 if (msg.arg2 == 1) {
2259 // wakelock was taken for this message, release it
2260 mWakeLock.release();
2261 if (Log.isLoggable(TAG, Log.INFO)) {
2262 Log.i(TAG, "WakeLock released by handleMessage(" + messageIdAsString(message)
2263 + ", " + msg.arg1 + ", " + msg.obj + ")");
2269 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2270 * It is in charge of loading properties and registering for events that will be posted to
2273 private void handleInitialize() {
2274 // load default GPS configuration
2275 // (this configuration might change in the future based on SIM changes)
2276 reloadGpsProperties(mContext, mProperties);
2278 // TODO: When this object "finishes" we should unregister by invoking
2279 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
2280 // This is not strictly necessary because it will be unregistered if the
2281 // notification fails but it is good form.
2283 // Register for SubscriptionInfo list changes which is guaranteed
2284 // to invoke onSubscriptionsChanged the first time.
2285 SubscriptionManager.from(mContext)
2286 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2288 // listen for events
2289 IntentFilter intentFilter;
2290 if (native_is_agps_ril_supported()) {
2291 intentFilter = new IntentFilter();
2292 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2293 intentFilter.addDataScheme("sms");
2294 intentFilter.addDataAuthority("localhost", "7275");
2295 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2297 intentFilter = new IntentFilter();
2298 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2300 intentFilter.addDataType("application/vnd.omaloc-supl-init");
2301 } catch (IntentFilter.MalformedMimeTypeException e) {
2302 Log.w(TAG, "Malformed SUPL init mime type");
2304 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2306 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2307 + " HAL is not supported");
2310 intentFilter = new IntentFilter();
2311 intentFilter.addAction(ALARM_WAKEUP);
2312 intentFilter.addAction(ALARM_TIMEOUT);
2313 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2314 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2315 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2316 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2317 intentFilter.addAction(SIM_STATE_CHANGED);
2318 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2320 // register for connectivity change events, this is equivalent to the deprecated way of
2321 // registering for CONNECTIVITY_ACTION broadcasts
2322 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2323 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
2324 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
2325 // On watches, Bluetooth is the most important network type.
2327 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
2329 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH);
2331 NetworkRequest networkRequest = networkRequestBuilder.build();
2332 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2334 // listen for PASSIVE_PROVIDER updates
2335 LocationManager locManager =
2336 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2338 float minDistance = 0;
2339 boolean oneShot = false;
2340 LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2341 LocationManager.PASSIVE_PROVIDER,
2345 // Don't keep track of this request since it's done on behalf of other clients
2346 // (which are kept track of separately).
2347 request.setHideFromAppOps(true);
2348 locManager.requestLocationUpdates(
2350 new NetworkLocationListener(),
2355 private final class NetworkLocationListener implements LocationListener {
2357 public void onLocationChanged(Location location) {
2358 // this callback happens on mHandler looper
2359 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2360 handleUpdateLocation(location);
2364 public void onStatusChanged(String provider, int status, Bundle extras) { }
2366 public void onProviderEnabled(String provider) { }
2368 public void onProviderDisabled(String provider) { }
2371 private String getSelectedApn() {
2372 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2373 Cursor cursor = null;
2375 cursor = mContext.getContentResolver().query(
2377 new String[] { "apn" },
2378 null /* selection */,
2379 null /* selectionArgs */,
2380 Carriers.DEFAULT_SORT_ORDER);
2381 if (cursor != null && cursor.moveToFirst()) {
2382 return cursor.getString(0);
2384 Log.e(TAG, "No APN found to select.");
2386 } catch (Exception e) {
2387 Log.e(TAG, "Error encountered on selecting the APN.", e);
2389 if (cursor != null) {
2397 private int getApnIpType(String apn) {
2398 ensureInHandlerThread();
2403 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2404 Cursor cursor = null;
2406 cursor = mContext.getContentResolver().query(
2407 Carriers.CONTENT_URI,
2408 new String[] { Carriers.PROTOCOL },
2411 Carriers.DEFAULT_SORT_ORDER);
2413 if (null != cursor && cursor.moveToFirst()) {
2414 return translateToApnIpType(cursor.getString(0), apn);
2416 Log.e(TAG, "No entry found in query for APN: " + apn);
2418 } catch (Exception e) {
2419 Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2421 if (cursor != null) {
2429 private int translateToApnIpType(String ipProtocol, String apn) {
2430 if ("IP".equals(ipProtocol)) {
2433 if ("IPV6".equals(ipProtocol)) {
2436 if ("IPV4V6".equals(ipProtocol)) {
2440 // we hit the default case so the ipProtocol is not recognized
2441 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2442 Log.e(TAG, message);
2446 private void setRouting() {
2447 if (mAGpsDataConnectionIpAddr == null) {
2451 // TODO: replace the use of this deprecated API
2452 boolean result = mConnMgr.requestRouteToHostAddress(
2453 ConnectivityManager.TYPE_MOBILE_SUPL,
2454 mAGpsDataConnectionIpAddr);
2457 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2459 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2464 * @return {@code true} if there is a data network available for outgoing connections,
2465 * {@code false} otherwise.
2467 private boolean isDataNetworkConnected() {
2468 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2469 return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2473 * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2475 private void ensureInHandlerThread() {
2476 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2479 throw new RuntimeException("This method must run on the Handler thread.");
2483 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2485 private String agpsDataConnStateAsString() {
2486 switch(mAGpsDataConnectionState) {
2487 case AGPS_DATA_CONNECTION_CLOSED:
2489 case AGPS_DATA_CONNECTION_OPEN:
2491 case AGPS_DATA_CONNECTION_OPENING:
2499 * @return A string representing the given GPS_AGPS_DATA status.
2501 private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2502 switch (agpsDataConnStatus) {
2503 case GPS_AGPS_DATA_CONNECTED:
2505 case GPS_AGPS_DATA_CONN_DONE:
2507 case GPS_AGPS_DATA_CONN_FAILED:
2509 case GPS_RELEASE_AGPS_DATA_CONN:
2511 case GPS_REQUEST_AGPS_DATA_CONN:
2519 * @return A string representing the given message ID.
2521 private String messageIdAsString(int message) {
2526 return "SET_REQUEST";
2527 case UPDATE_NETWORK_STATE:
2528 return "UPDATE_NETWORK_STATE";
2529 case REQUEST_SUPL_CONNECTION:
2530 return "REQUEST_SUPL_CONNECTION";
2531 case RELEASE_SUPL_CONNECTION:
2532 return "RELEASE_SUPL_CONNECTION";
2533 case INJECT_NTP_TIME:
2534 return "INJECT_NTP_TIME";
2535 case DOWNLOAD_XTRA_DATA:
2536 return "DOWNLOAD_XTRA_DATA";
2537 case INJECT_NTP_TIME_FINISHED:
2538 return "INJECT_NTP_TIME_FINISHED";
2539 case DOWNLOAD_XTRA_DATA_FINISHED:
2540 return "DOWNLOAD_XTRA_DATA_FINISHED";
2541 case UPDATE_LOCATION:
2542 return "UPDATE_LOCATION";
2543 case SUBSCRIPTION_OR_SIM_CHANGED:
2544 return "SUBSCRIPTION_OR_SIM_CHANGED";
2545 case INITIALIZE_HANDLER:
2546 return "INITIALIZE_HANDLER";
2555 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2556 StringBuilder s = new StringBuilder();
2557 s.append(" mStarted=").append(mStarted).append('\n');
2558 s.append(" mFixInterval=").append(mFixInterval).append('\n');
2559 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2560 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2562 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2563 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2564 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2565 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2566 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2567 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2568 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2569 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2571 s.append(mGnssMetrics.dumpGnssMetricsAsText());
2572 s.append(" native internal state: ").append(native_get_internal_state());
2578 * A simple implementation of exponential backoff.
2580 private static final class BackOff {
2581 private static final int MULTIPLIER = 2;
2582 private final long mInitIntervalMillis;
2583 private final long mMaxIntervalMillis;
2584 private long mCurrentIntervalMillis;
2586 public BackOff(long initIntervalMillis, long maxIntervalMillis) {
2587 mInitIntervalMillis = initIntervalMillis;
2588 mMaxIntervalMillis = maxIntervalMillis;
2590 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2593 public long nextBackoffMillis() {
2594 if (mCurrentIntervalMillis > mMaxIntervalMillis) {
2595 return mMaxIntervalMillis;
2598 mCurrentIntervalMillis *= MULTIPLIER;
2599 return mCurrentIntervalMillis;
2602 public void reset() {
2603 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2607 // for GPS SV statistics
2608 private static final int MAX_SVS = 64;
2610 // preallocated arrays, to avoid memory allocation in reportStatus()
2611 private int mSvidWithFlags[] = new int[MAX_SVS];
2612 private float mCn0s[] = new float[MAX_SVS];
2613 private float mSvElevations[] = new float[MAX_SVS];
2614 private float mSvAzimuths[] = new float[MAX_SVS];
2615 private float mSvCarrierFreqs[] = new float[MAX_SVS];
2616 private int mSvCount;
2617 private int mMeanCn0;
2618 private int mMaxCn0;
2619 // preallocated to avoid memory allocation in reportNmea()
2620 private byte[] mNmeaBuffer = new byte[120];
2622 static { class_init_native(); }
2623 private static native void class_init_native();
2624 private static native boolean native_is_supported();
2625 private static native boolean native_is_agps_ril_supported();
2626 private static native boolean native_is_gnss_configuration_supported();
2628 private native boolean native_init();
2629 private native void native_cleanup();
2630 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2631 int preferred_accuracy, int preferred_time);
2632 private native boolean native_start();
2633 private native boolean native_stop();
2634 private native void native_delete_aiding_data(int flags);
2635 // returns number of SVs
2636 // mask[0] is ephemeris mask and mask[1] is almanac mask
2637 private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
2638 float[] azimuths, float[] carrierFrequencies);
2639 private native int native_read_nmea(byte[] buffer, int bufferSize);
2640 private native void native_inject_location(double latitude, double longitude, float accuracy);
2643 private native void native_inject_time(long time, long timeReference, int uncertainty);
2644 private native boolean native_supports_xtra();
2645 private native void native_inject_xtra_data(byte[] data, int length);
2648 private native String native_get_internal_state();
2651 private native void native_agps_data_conn_open(String apn, int apnIpType);
2652 private native void native_agps_data_conn_closed();
2653 private native void native_agps_data_conn_failed();
2654 private native void native_agps_ni_message(byte [] msg, int length);
2655 private native void native_set_agps_server(int type, String hostname, int port);
2657 // Network-initiated (NI) Support
2658 private native void native_send_ni_response(int notificationId, int userResponse);
2661 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2663 private native void native_agps_set_id(int type, String setid);
2665 private native void native_update_network_state(boolean connected, int type,
2666 boolean roaming, boolean available, String extraInfo, String defaultAPN);
2668 // Hardware Geofence support.
2669 private static native boolean native_is_geofence_supported();
2670 private static native boolean native_add_geofence(int geofenceId, double latitude,
2671 double longitude, double radius, int lastTransition,int monitorTransitions,
2672 int notificationResponsivenes, int unknownTimer);
2673 private static native boolean native_remove_geofence(int geofenceId);
2674 private static native boolean native_resume_geofence(int geofenceId, int transitions);
2675 private static native boolean native_pause_geofence(int geofenceId);
2677 // Gps Hal measurements support.
2678 private static native boolean native_is_measurement_supported();
2679 private native boolean native_start_measurement_collection();
2680 private native boolean native_stop_measurement_collection();
2682 // Gps Navigation message support.
2683 private static native boolean native_is_navigation_message_supported();
2684 private native boolean native_start_navigation_message_collection();
2685 private native boolean native_stop_navigation_message_collection();
2687 // GNSS Configuration
2688 private static native boolean native_set_supl_version(int version);
2689 private static native boolean native_set_supl_mode(int mode);
2690 private static native boolean native_set_supl_es(int es);
2691 private static native boolean native_set_lpp_profile(int lppProfile);
2692 private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
2693 private static native boolean native_set_gps_lock(int gpsLock);
2694 private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
2697 private static native int native_get_batch_size();
2698 private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
2699 private static native void native_flush_batch();
2700 private static native boolean native_stop_batch();
2701 private static native boolean native_init_batching();
2702 private static native void native_cleanup_batching();