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.UserManager;
67 import android.os.WorkSource;
68 import android.provider.Settings;
69 import android.provider.Telephony.Carriers;
70 import android.provider.Telephony.Sms.Intents;
71 import android.telephony.SubscriptionManager;
72 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
73 import android.telephony.TelephonyManager;
74 import android.telephony.CarrierConfigManager;
75 import android.telephony.gsm.GsmCellLocation;
76 import android.text.TextUtils;
77 import android.util.Log;
78 import android.util.NtpTrustedTime;
80 import com.android.internal.app.IAppOpsService;
81 import com.android.internal.app.IBatteryStats;
82 import com.android.internal.location.gnssmetrics.GnssMetrics;
83 import com.android.internal.location.GpsNetInitiatedHandler;
84 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
85 import com.android.internal.location.ProviderProperties;
86 import com.android.internal.location.ProviderRequest;
88 import com.android.server.power.BatterySaverPolicy;
89 import com.android.server.power.BatterySaverPolicy.ServiceType;
91 import libcore.io.IoUtils;
94 import java.io.FileDescriptor;
95 import java.io.FileInputStream;
96 import java.io.IOException;
97 import java.io.PrintWriter;
98 import java.net.InetAddress;
99 import java.net.UnknownHostException;
100 import java.util.ArrayList;
101 import java.util.Arrays;
102 import java.util.Date;
103 import java.util.List;
104 import java.util.Map.Entry;
105 import java.util.Properties;
106 import java.util.Map;
107 import java.util.HashMap;
110 * A GNSS implementation of LocationProvider used by LocationManager.
114 public class GnssLocationProvider implements LocationProviderInterface {
116 private static final String TAG = "GnssLocationProvider";
118 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
119 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
121 private static final ProviderProperties PROPERTIES = new ProviderProperties(
122 true, true, false, false, true, true, true,
123 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
125 // these need to match GnssPositionMode enum in IGnss.hal
126 private static final int GPS_POSITION_MODE_STANDALONE = 0;
127 private static final int GPS_POSITION_MODE_MS_BASED = 1;
128 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
130 // these need to match GnssPositionRecurrence enum in IGnss.hal
131 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
132 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
134 // these need to match GnssStatusValue enum in IGnssCallback.hal
135 private static final int GPS_STATUS_NONE = 0;
136 private static final int GPS_STATUS_SESSION_BEGIN = 1;
137 private static final int GPS_STATUS_SESSION_END = 2;
138 private static final int GPS_STATUS_ENGINE_ON = 3;
139 private static final int GPS_STATUS_ENGINE_OFF = 4;
141 // these need to match AGnssStatusValue enum in IAGnssCallback.hal
142 /** AGPS status event values. */
143 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
144 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
145 private static final int GPS_AGPS_DATA_CONNECTED = 3;
146 private static final int GPS_AGPS_DATA_CONN_DONE = 4;
147 private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
149 // these need to match GnssLocationFlags enum in types.hal
150 private static final int LOCATION_INVALID = 0;
151 private static final int LOCATION_HAS_LAT_LONG = 1;
152 private static final int LOCATION_HAS_ALTITUDE = 2;
153 private static final int LOCATION_HAS_SPEED = 4;
154 private static final int LOCATION_HAS_BEARING = 8;
155 private static final int LOCATION_HAS_HORIZONTAL_ACCURACY = 16;
156 private static final int LOCATION_HAS_VERTICAL_ACCURACY = 32;
157 private static final int LOCATION_HAS_SPEED_ACCURACY = 64;
158 private static final int LOCATION_HAS_BEARING_ACCURACY = 128;
161 // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal
162 private static final int GPS_DELETE_EPHEMERIS = 0x0001;
163 private static final int GPS_DELETE_ALMANAC = 0x0002;
164 private static final int GPS_DELETE_POSITION = 0x0004;
165 private static final int GPS_DELETE_TIME = 0x0008;
166 private static final int GPS_DELETE_IONO = 0x0010;
167 private static final int GPS_DELETE_UTC = 0x0020;
168 private static final int GPS_DELETE_HEALTH = 0x0040;
169 private static final int GPS_DELETE_SVDIR = 0x0080;
170 private static final int GPS_DELETE_SVSTEER = 0x0100;
171 private static final int GPS_DELETE_SADATA = 0x0200;
172 private static final int GPS_DELETE_RTI = 0x0400;
173 private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
174 private static final int GPS_DELETE_ALL = 0xFFFF;
176 // The GPS_CAPABILITY_* flags must match Capabilities enum in IGnssCallback.hal
177 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
178 private static final int GPS_CAPABILITY_MSB = 0x0000002;
179 private static final int GPS_CAPABILITY_MSA = 0x0000004;
180 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
181 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
182 private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
183 private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
184 private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
186 // The AGPS SUPL mode
187 private static final int AGPS_SUPL_MODE_MSA = 0x02;
188 private static final int AGPS_SUPL_MODE_MSB = 0x01;
190 // these need to match AGnssType enum in IAGnssCallback.hal
191 private static final int AGPS_TYPE_SUPL = 1;
192 private static final int AGPS_TYPE_C2K = 2;
194 // these must match the ApnIpType enum in IAGnss.hal
195 private static final int APN_INVALID = 0;
196 private static final int APN_IPV4 = 1;
197 private static final int APN_IPV6 = 2;
198 private static final int APN_IPV4V6 = 3;
200 // for mAGpsDataConnectionState
201 private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
202 private static final int AGPS_DATA_CONNECTION_OPENING = 1;
203 private static final int AGPS_DATA_CONNECTION_OPEN = 2;
206 private static final int CHECK_LOCATION = 1;
207 private static final int ENABLE = 2;
208 private static final int SET_REQUEST = 3;
209 private static final int UPDATE_NETWORK_STATE = 4;
210 private static final int INJECT_NTP_TIME = 5;
211 private static final int DOWNLOAD_XTRA_DATA = 6;
212 private static final int UPDATE_LOCATION = 7;
213 private static final int ADD_LISTENER = 8;
214 private static final int REMOVE_LISTENER = 9;
215 private static final int INJECT_NTP_TIME_FINISHED = 10;
216 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
217 private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
218 private static final int INITIALIZE_HANDLER = 13;
219 private static final int REQUEST_SUPL_CONNECTION = 14;
220 private static final int RELEASE_SUPL_CONNECTION = 15;
223 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
224 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
226 //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
227 private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
229 // ref. location info
230 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
231 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
234 private static final int AGPS_SETID_TYPE_NONE = 0;
235 private static final int AGPS_SETID_TYPE_IMSI = 1;
236 private static final int AGPS_SETID_TYPE_MSISDN = 2;
238 private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
239 private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
241 // GPS Geofence errors. Should match GeofenceStatus enum in IGnssGeofenceCallback.hal.
242 private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
243 private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
244 private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
245 private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
246 private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
247 private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
250 // Valid TCP/UDP port range is (0, 65535].
251 private static final int TCP_MIN_PORT = 0;
252 private static final int TCP_MAX_PORT = 0xffff;
254 /** simpler wrapper for ProviderRequest + Worksource */
255 private static class GpsRequest {
256 public ProviderRequest request;
257 public WorkSource source;
258 public GpsRequest(ProviderRequest request, WorkSource source) {
259 this.request = request;
260 this.source = source;
264 private Object mLock = new Object();
267 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
269 // time for last status update
270 private long mStatusUpdateTime = SystemClock.elapsedRealtime();
272 // turn off GPS fix icon if we haven't received a fix in 10 seconds
273 private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
275 // stop trying if we do not receive a fix within 60 seconds
276 private static final int NO_FIX_TIMEOUT = 60 * 1000;
278 // if the fix interval is below this we leave GPS on,
279 // if above then we cycle the GPS driver.
280 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
281 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
283 // how often to request NTP time, in milliseconds
284 // current setting 24 hours
285 private static final long NTP_INTERVAL = 24*60*60*1000;
286 // how long to wait if we have a network error in NTP or XTRA downloading
287 // the initial value of the exponential backoff
288 // current setting - 5 minutes
289 private static final long RETRY_INTERVAL = 5*60*1000;
290 // how long to wait if we have a network error in NTP or XTRA downloading
291 // the max value of the exponential backoff
292 // current setting - 4 hours
293 private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
295 // Timeout when holding wakelocks for downloading XTRA data.
296 private static final long DOWNLOAD_XTRA_DATA_TIMEOUT_MS = 60 * 1000;
298 private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
299 private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
301 // true if we are enabled, protected by this
302 private boolean mEnabled;
304 // states for injecting ntp and downloading xtra data
305 private static final int STATE_PENDING_NETWORK = 0;
306 private static final int STATE_DOWNLOADING = 1;
307 private static final int STATE_IDLE = 2;
309 // flags to trigger NTP or XTRA data download when network becomes available
310 // initialized to true so we do NTP and XTRA when the network comes up after booting
311 private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
312 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
314 // set to true if the GPS engine requested on-demand NTP time requests
315 private boolean mOnDemandTimeInjection;
317 // true if GPS is navigating
318 private boolean mNavigating;
320 // true if GPS engine is on
321 private boolean mEngineOn;
323 // requested frequency of fixes, in milliseconds
324 private int mFixInterval = 1000;
326 // true if we started navigation
327 private boolean mStarted;
329 // true if single shot request is in progress
330 private boolean mSingleShot;
332 // capabilities of the GPS engine
333 private int mEngineCapabilities;
335 // true if XTRA is supported
336 private boolean mSupportsXtra;
338 // for calculating time to first fix
339 private long mFixRequestTime = 0;
340 // time to first fix for most recent session
341 private int mTimeToFirstFix = 0;
342 // time we received our last fix
343 private long mLastFixTime;
345 private int mPositionMode;
347 // Current request from underlying location clients.
348 private ProviderRequest mProviderRequest = null;
349 // Current list of underlying location clients.
350 private WorkSource mWorkSource = null;
351 // True if gps should be disabled (used to support battery saver mode in settings).
352 private boolean mDisableGps = false;
355 * Properties loaded from PROPERTIES_FILE.
356 * It must be accessed only inside {@link #mHandler}.
358 private Properties mProperties;
360 private String mSuplServerHost;
361 private int mSuplServerPort = TCP_MIN_PORT;
362 private String mC2KServerHost;
363 private int mC2KServerPort;
364 private boolean mSuplEsEnabled = false;
366 private final Context mContext;
367 private final NtpTrustedTime mNtpTime;
368 private final ILocationManager mILocationManager;
369 private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
370 private Bundle mLocationExtras = new Bundle();
371 private final GnssStatusListenerHelper mListenerHelper;
372 private final GnssMeasurementsProvider mGnssMeasurementsProvider;
373 private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
375 // Handler for processing events
376 private Handler mHandler;
378 /** It must be accessed only inside {@link #mHandler}. */
379 private int mAGpsDataConnectionState;
380 /** It must be accessed only inside {@link #mHandler}. */
381 private InetAddress mAGpsDataConnectionIpAddr;
383 private final ConnectivityManager mConnMgr;
384 private final GpsNetInitiatedHandler mNIHandler;
387 private final static String WAKELOCK_KEY = "GnssLocationProvider";
388 private final PowerManager.WakeLock mWakeLock;
389 private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderXtraDownload";
390 private final PowerManager.WakeLock mDownloadXtraWakeLock;
393 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
394 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
397 private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
399 // Persist property for LPP_PROFILE
400 private final static String LPP_PROFILE = "persist.sys.gps.lpp";
404 private final PowerManager mPowerManager;
405 private final AlarmManager mAlarmManager;
406 private final PendingIntent mWakeupIntent;
407 private final PendingIntent mTimeoutIntent;
409 private final IAppOpsService mAppOpsService;
410 private final IBatteryStats mBatteryStats;
412 // only modified on handler thread
413 private WorkSource mClientSource = new WorkSource();
415 private GeofenceHardwareImpl mGeofenceHardwareImpl;
416 private int mYearOfHardware = 0;
418 // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
419 // stops output right at 600m/s, depriving this of the information of a device that reaches
420 // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
421 private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
422 private boolean mItarSpeedLimitExceeded = false;
425 private GnssMetrics mGnssMetrics;
427 private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
429 public void registerGnssStatusCallback(IGnssStatusListener callback) {
430 mListenerHelper.addListener(callback);
434 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
435 mListenerHelper.removeListener(callback);
439 public IGnssStatusProvider getGnssStatusProvider() {
440 return mGnssStatusProvider;
443 public IGpsGeofenceHardware getGpsGeofenceProxy() {
444 return mGpsGeofenceBinder;
447 public GnssMeasurementsProvider getGnssMeasurementsProvider() {
448 return mGnssMeasurementsProvider;
451 public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
452 return mGnssNavigationMessageProvider;
456 * Callback used to listen for data connectivity changes.
458 private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
459 new ConnectivityManager.NetworkCallback() {
461 public void onAvailable(Network network) {
462 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
465 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
466 xtraDownloadRequest();
468 // Always on, notify HAL so it can get data it needs
469 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
473 public void onLost(Network network) {
474 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
479 * Callback used to listen for availability of a requested SUPL connection.
480 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
481 * manage the registration/un-registration lifetimes separate.
483 private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
484 new ConnectivityManager.NetworkCallback() {
486 public void onAvailable(Network network) {
487 // Specific to a change to a SUPL enabled network becoming ready
488 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
492 public void onLost(Network network) {
493 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
497 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
498 @Override public void onReceive(Context context, Intent intent) {
499 String action = intent.getAction();
500 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
501 if (action == null) {
505 if (action.equals(ALARM_WAKEUP)) {
506 startNavigating(false);
507 } else if (action.equals(ALARM_TIMEOUT)) {
509 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
510 || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
511 || Intent.ACTION_SCREEN_OFF.equals(action)
512 || Intent.ACTION_SCREEN_ON.equals(action)) {
513 updateLowPowerMode();
514 } else if (action.equals(SIM_STATE_CHANGED)) {
515 subscriptionOrSimChanged(context);
520 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
521 new OnSubscriptionsChangedListener() {
523 public void onSubscriptionsChanged() {
524 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
528 private void subscriptionOrSimChanged(Context context) {
529 if (DEBUG) Log.d(TAG, "received SIM related action: ");
530 TelephonyManager phone = (TelephonyManager)
531 mContext.getSystemService(Context.TELEPHONY_SERVICE);
532 CarrierConfigManager configManager = (CarrierConfigManager)
533 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
534 String mccMnc = phone.getSimOperator();
535 boolean isKeepLppProfile = false;
536 if (!TextUtils.isEmpty(mccMnc)) {
537 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
538 synchronized (mLock) {
539 if (configManager != null) {
540 PersistableBundle b = configManager.getConfig();
541 isKeepLppProfile = b.getBoolean(CarrierConfigManager.KEY_PERSIST_LPP_MODE_BOOL);
543 if (isKeepLppProfile) {
544 // load current properties for the carrier
545 loadPropertiesFromResource(context, mProperties);
546 String lpp_profile = mProperties.getProperty("LPP_PROFILE");
547 // set the persist property LPP_PROFILE for the value
548 if (lpp_profile != null) {
549 SystemProperties.set(LPP_PROFILE, lpp_profile);
552 // reset the persist property
553 SystemProperties.set(LPP_PROFILE, "");
555 reloadGpsProperties(context, mProperties);
556 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
559 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
563 private void updateLowPowerMode() {
564 // Disable GPS if we are in device idle mode.
565 boolean disableGps = mPowerManager.isDeviceIdleMode();
566 final PowerSaveState result =
567 mPowerManager.getPowerSaveState(ServiceType.GPS);
568 switch (result.gpsMode) {
569 case BatterySaverPolicy.GPS_MODE_REALLY_DISABLED_WHEN_SCREEN_OFF:
570 case BatterySaverPolicy.GPS_MODE_DISABLED_WHEN_SCREEN_OFF:
571 // If we are in battery saver mode and the screen is off, disable GPS.
572 disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive();
575 if (disableGps != mDisableGps) {
576 mDisableGps = disableGps;
577 updateRequirements();
579 updateLocationModeForReallyDisabledWhenScreenOff(result.gpsMode);
583 boolean mLocationDisabledForPowerSaving;
585 private void updateLocationModeForReallyDisabledWhenScreenOff(int gpsMode) {
586 final boolean disableLocation = mDisableGps
587 && (gpsMode == BatterySaverPolicy.GPS_MODE_REALLY_DISABLED_WHEN_SCREEN_OFF);
589 // TODO Secondary user, intent sent in LocationSettingsBase
590 if (disableLocation != mLocationDisabledForPowerSaving) {
591 Log.w("XXX:GnssLP", "mLocationDisabledForPowerSaving=" + mLocationDisabledForPowerSaving + " on u" + UserHandle.myUserId());
592 mLocationDisabledForPowerSaving = disableLocation;
593 if (disableLocation) {
594 Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.LOCATION_MODE,
595 android.provider.Settings.Secure.LOCATION_MODE_OFF);
597 Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.LOCATION_MODE,
598 android.provider.Settings.Secure.LOCATION_MODE_PREVIOUS);
603 public static boolean isSupported() {
604 return native_is_supported();
607 interface SetCarrierProperty {
608 public boolean set(int value);
611 private void reloadGpsProperties(Context context, Properties properties) {
612 if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
613 loadPropertiesFromResource(context, properties);
615 String lpp_prof = SystemProperties.get(LPP_PROFILE);
616 if (!TextUtils.isEmpty(lpp_prof)) {
617 // override default value of this if lpp_prof is not empty
618 properties.setProperty("LPP_PROFILE", lpp_prof);
621 * Overlay carrier properties from a debug configuration file.
623 loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
624 // TODO: we should get rid of C2K specific setting.
625 setSuplHostPort(properties.getProperty("SUPL_HOST"),
626 properties.getProperty("SUPL_PORT"));
627 mC2KServerHost = properties.getProperty("C2K_HOST");
628 String portString = properties.getProperty("C2K_PORT");
629 if (mC2KServerHost != null && portString != null) {
631 mC2KServerPort = Integer.parseInt(portString);
632 } catch (NumberFormatException e) {
633 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
636 if (native_is_gnss_configuration_supported()) {
637 Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
639 put("SUPL_VER", (val) -> native_set_supl_version(val));
640 put("SUPL_MODE", (val) -> native_set_supl_mode(val));
641 put("SUPL_ES", (val) -> native_set_supl_es(val));
642 put("LPP_PROFILE", (val) -> native_set_lpp_profile(val));
643 put("A_GLONASS_POS_PROTOCOL_SELECT", (val) -> native_set_gnss_pos_protocol_select(val));
644 put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", (val) -> native_set_emergency_supl_pdn(val));
645 put("GPS_LOCK", (val) -> native_set_gps_lock(val));
649 for(Entry<String, SetCarrierProperty> entry : map.entrySet()) {
650 String propertyName = entry.getKey();
651 String propertyValueString = properties.getProperty(propertyName);
652 if (propertyValueString != null) {
654 int propertyValueInt = Integer.decode(propertyValueString);
655 boolean result = entry.getValue().set(propertyValueInt);
656 if (result == false) {
657 Log.e(TAG, "Unable to set " + propertyName);
659 } catch (NumberFormatException e) {
660 Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
665 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
669 // SUPL_ES configuration.
670 String suplESProperty = mProperties.getProperty("SUPL_ES");
671 if (suplESProperty != null) {
673 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
674 } catch (NumberFormatException e) {
675 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
680 private void loadPropertiesFromResource(Context context,
681 Properties properties) {
682 String[] configValues = context.getResources().getStringArray(
683 com.android.internal.R.array.config_gpsParameters);
684 for (String item : configValues) {
685 if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
686 // We need to support "KEY =", but not "=VALUE".
687 String[] split = item.split("=");
688 if (split.length == 2) {
689 properties.setProperty(split[0].trim().toUpperCase(), split[1]);
691 Log.w(TAG, "malformed contents: " + item);
696 private boolean loadPropertiesFromFile(String filename,
697 Properties properties) {
699 File file = new File(filename);
700 FileInputStream stream = null;
702 stream = new FileInputStream(file);
703 properties.load(stream);
705 IoUtils.closeQuietly(stream);
708 } catch (IOException e) {
709 if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename);
715 public GnssLocationProvider(Context context, ILocationManager ilocationManager,
718 mNtpTime = NtpTrustedTime.getInstance(context);
719 mILocationManager = ilocationManager;
721 mLocation.setExtras(mLocationExtras);
723 // Create a wake lock
724 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
725 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
726 mWakeLock.setReferenceCounted(true);
728 // Create a separate wake lock for xtra downloader as it may be released due to timeout.
729 mDownloadXtraWakeLock = mPowerManager.newWakeLock(
730 PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY);
731 mDownloadXtraWakeLock.setReferenceCounted(true);
733 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
734 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
735 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
737 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
739 // App ops service to keep track of who is accessing the GPS
740 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
741 Context.APP_OPS_SERVICE));
743 // Battery statistics service to be notified when GPS turns on or off
744 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
745 BatteryStats.SERVICE_NAME));
747 // Construct internal handler
748 mHandler = new ProviderHandler(looper);
750 // Load GPS configuration and register listeners in the background:
751 // some operations, such as opening files and registering broadcast receivers, can take a
752 // relative long time, so the ctor() is kept to create objects needed by this instance,
753 // while IO initialization and registration is delegated to our internal handler
754 // this approach is just fine because events are posted to our handler anyway
755 mProperties = new Properties();
756 sendMessage(INITIALIZE_HANDLER, 0, null);
758 // Create a GPS net-initiated handler.
759 mNIHandler = new GpsNetInitiatedHandler(context,
760 mNetInitiatedListener,
763 mListenerHelper = new GnssStatusListenerHelper(mHandler) {
765 protected boolean isAvailableInPlatform() {
766 return isSupported();
770 protected boolean isGpsEnabled() {
775 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) {
777 public boolean isAvailableInPlatform() {
778 return native_is_measurement_supported();
782 protected boolean registerWithService() {
783 return native_start_measurement_collection();
787 protected void unregisterFromService() {
788 native_stop_measurement_collection();
792 protected boolean isGpsEnabled() {
797 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
799 protected boolean isAvailableInPlatform() {
800 return native_is_navigation_message_supported();
804 protected boolean registerWithService() {
805 return native_start_navigation_message_collection();
809 protected void unregisterFromService() {
810 native_stop_navigation_message_collection();
814 protected boolean isGpsEnabled() {
818 mGnssMetrics = new GnssMetrics();
821 * A cycle of native_init() and native_cleanup() is needed so that callbacks are registered
822 * after bootup even when location is disabled. This will allow Emergency SUPL to work even
823 * when location is disabled before device restart.
825 boolean isInitialized = native_init();
827 Log.d(TAG, "Failed to initialize at bootup");
834 * Returns the name of this provider.
837 public String getName() {
838 return LocationManager.GPS_PROVIDER;
842 public ProviderProperties getProperties() {
846 private void handleUpdateNetworkState(Network network) {
847 // retrieve NetworkInfo for this UID
848 NetworkInfo info = mConnMgr.getNetworkInfo(network);
850 boolean networkAvailable = false;
851 boolean isConnected = false;
852 int type = ConnectivityManager.TYPE_NONE;
853 boolean isRoaming = false;
854 String apnName = null;
857 networkAvailable = info.isAvailable() && TelephonyManager.getDefault().getDataEnabled();
858 isConnected = info.isConnected();
859 type = info.getType();
860 isRoaming = info.isRoaming();
861 apnName = info.getExtraInfo();
865 String message = String.format(
866 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
867 agpsDataConnStateAsString(),
870 mConnMgr.getNetworkCapabilities(network));
874 if (native_is_agps_ril_supported()) {
875 String defaultApn = getSelectedApn();
876 if (defaultApn == null) {
877 defaultApn = "dummy-apn";
880 native_update_network_state(
888 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
891 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
893 if (apnName == null) {
894 // assign a dummy value in the case of C2K as otherwise we will have a runtime
895 // exception in the following call to native_agps_data_conn_open
896 apnName = "dummy-apn";
898 int apnIpType = getApnIpType(apnName);
901 String message = String.format(
902 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
907 native_agps_data_conn_open(apnName, apnIpType);
908 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
910 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
915 private void handleRequestSuplConnection(InetAddress address) {
917 String message = String.format(
918 "requestSuplConnection, state=%s, address=%s",
919 agpsDataConnStateAsString(),
924 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
927 mAGpsDataConnectionIpAddr = address;
928 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
930 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
931 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
932 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
933 NetworkRequest request = requestBuilder.build();
934 mConnMgr.requestNetwork(
936 mSuplConnectivityCallback);
939 private void handleReleaseSuplConnection(int agpsDataConnStatus) {
941 String message = String.format(
942 "releaseSuplConnection, state=%s, status=%s",
943 agpsDataConnStateAsString(),
944 agpsDataConnStatusAsString(agpsDataConnStatus));
948 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
951 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
953 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
954 switch (agpsDataConnStatus) {
955 case GPS_AGPS_DATA_CONN_FAILED:
956 native_agps_data_conn_failed();
958 case GPS_RELEASE_AGPS_DATA_CONN:
959 native_agps_data_conn_closed();
962 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
966 private void handleInjectNtpTime() {
967 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
968 // already downloading data
971 if (!isDataNetworkConnected()) {
972 // try again when network is up
973 mInjectNtpTimePending = STATE_PENDING_NETWORK;
976 mInjectNtpTimePending = STATE_DOWNLOADING;
978 // hold wake lock while task runs
980 Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
981 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
986 // force refresh NTP cache when outdated
987 boolean refreshSuccess = true;
988 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
989 refreshSuccess = mNtpTime.forceRefresh();
992 // only update when NTP time is fresh
993 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
994 long time = mNtpTime.getCachedNtpTime();
995 long timeReference = mNtpTime.getCachedNtpTimeReference();
996 long certainty = mNtpTime.getCacheCertainty();
999 long now = System.currentTimeMillis();
1000 Log.d(TAG, "NTP server returned: "
1001 + time + " (" + new Date(time)
1002 + ") reference: " + timeReference
1003 + " certainty: " + certainty
1004 + " system time offset: " + (time - now));
1007 native_inject_time(time, timeReference, (int) certainty);
1008 delay = NTP_INTERVAL;
1009 mNtpBackOff.reset();
1011 Log.e(TAG, "requestTime failed");
1012 delay = mNtpBackOff.nextBackoffMillis();
1015 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
1018 String message = String.format(
1019 "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
1020 mOnDemandTimeInjection,
1023 Log.d(TAG, message);
1025 if (mOnDemandTimeInjection || !refreshSuccess) {
1026 // send delayed message for next NTP injection
1027 // since this is delayed and not urgent we do not hold a wake lock here
1028 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
1031 // release wake lock held by task
1032 mWakeLock.release();
1033 Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
1038 private void handleDownloadXtraData() {
1039 if (!mSupportsXtra) {
1040 // native code reports xtra not supported, don't try
1041 Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
1044 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
1045 // already downloading data
1048 if (!isDataNetworkConnected()) {
1049 // try again when network is up
1050 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
1053 mDownloadXtraDataPending = STATE_DOWNLOADING;
1055 // hold wake lock while task runs
1056 mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
1057 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
1058 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1061 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
1062 byte[] data = xtraDownloader.downloadXtraData();
1064 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
1065 native_inject_xtra_data(data, data.length);
1066 mXtraBackOff.reset();
1069 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
1073 // since this is delayed and not urgent we do not hold a wake lock here
1074 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
1075 mXtraBackOff.nextBackoffMillis());
1078 // Release wake lock held by task, synchronize on mLock in case multiple
1079 // download tasks overrun.
1080 synchronized (mLock) {
1081 if (mDownloadXtraWakeLock.isHeld()) {
1082 // This wakelock may have time-out, if a timeout was specified.
1083 // Catch (and ignore) any timeout exceptions.
1085 mDownloadXtraWakeLock.release();
1086 if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
1087 } catch (Exception e) {
1088 Log.i(TAG, "Wakelock timeout & release race exception in "
1089 + "handleDownloadXtraData()", e);
1092 Log.e(TAG, "WakeLock expired before release in "
1093 + "handleDownloadXtraData()");
1100 private void handleUpdateLocation(Location location) {
1101 if (location.hasAccuracy()) {
1102 native_inject_location(location.getLatitude(), location.getLongitude(),
1103 location.getAccuracy());
1108 * Enables this provider. When enabled, calls to getStatus()
1109 * must be handled. Hardware may be started up
1110 * when the provider is enabled.
1113 public void enable() {
1114 synchronized (mLock) {
1115 if (mEnabled) return;
1119 sendMessage(ENABLE, 1, null);
1122 private void setSuplHostPort(String hostString, String portString) {
1123 if (hostString != null) {
1124 mSuplServerHost = hostString;
1126 if (portString != null) {
1128 mSuplServerPort = Integer.parseInt(portString);
1129 } catch (NumberFormatException e) {
1130 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1133 if (mSuplServerHost != null
1134 && mSuplServerPort > TCP_MIN_PORT
1135 && mSuplServerPort <= TCP_MAX_PORT) {
1136 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1141 * Checks what SUPL mode to use, according to the AGPS mode as well as the
1142 * allowed mode from properties.
1144 * @param properties GPS properties
1145 * @param agpsEnabled whether AGPS is enabled by settings value
1146 * @param singleShot whether "singleshot" is needed
1147 * @return SUPL mode (MSA vs MSB vs STANDALONE)
1149 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1151 String modeString = properties.getProperty("SUPL_MODE");
1153 if (!TextUtils.isEmpty(modeString)) {
1155 suplMode = Integer.parseInt(modeString);
1156 } catch (NumberFormatException e) {
1157 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1158 return GPS_POSITION_MODE_STANDALONE;
1161 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1162 // such mode when it is available
1163 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1164 return GPS_POSITION_MODE_MS_BASED;
1166 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1167 // do fallback only for single-shot requests, because it is too expensive to do for
1168 // periodic requests as well
1170 && hasCapability(GPS_CAPABILITY_MSA)
1171 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1172 return GPS_POSITION_MODE_MS_ASSISTED;
1175 return GPS_POSITION_MODE_STANDALONE;
1178 private void handleEnable() {
1179 if (DEBUG) Log.d(TAG, "handleEnable");
1181 boolean enabled = native_init();
1184 mSupportsXtra = native_supports_xtra();
1186 // TODO: remove the following native calls if we can make sure they are redundant.
1187 if (mSuplServerHost != null) {
1188 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1190 if (mC2KServerHost != null) {
1191 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1194 mGnssMeasurementsProvider.onGpsEnabledChanged();
1195 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1198 synchronized (mLock) {
1201 Log.w(TAG, "Failed to enable location provider");
1206 * Disables this provider. When disabled, calls to getStatus()
1207 * need not be handled. Hardware may be shut
1208 * down while the provider is disabled.
1211 public void disable() {
1212 synchronized (mLock) {
1213 if (!mEnabled) return;
1217 sendMessage(ENABLE, 0, null);
1220 private void handleDisable() {
1221 if (DEBUG) Log.d(TAG, "handleDisable");
1223 updateClientUids(new WorkSource());
1225 mAlarmManager.cancel(mWakeupIntent);
1226 mAlarmManager.cancel(mTimeoutIntent);
1229 // do this before releasing wakelock
1232 mGnssMeasurementsProvider.onGpsEnabledChanged();
1233 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1237 public boolean isEnabled() {
1238 synchronized (mLock) {
1244 public int getStatus(Bundle extras) {
1245 setLocationExtras(extras);
1249 private void updateStatus(int status, int svCount, int meanCn0, int maxCn0) {
1250 if (status != mStatus || svCount != mSvCount || meanCn0 != mMeanCn0 || maxCn0 != mMaxCn0 ) {
1255 setLocationExtras(mLocationExtras);
1256 mStatusUpdateTime = SystemClock.elapsedRealtime();
1260 private void setLocationExtras(Bundle extras) {
1261 if (extras != null) {
1262 extras.putInt("satellites", mSvCount);
1263 extras.putInt("meanCn0", mMeanCn0);
1264 extras.putInt("maxCn0", mMaxCn0);
1269 public long getStatusUpdateTime() {
1270 return mStatusUpdateTime;
1274 public void setRequest(ProviderRequest request, WorkSource source) {
1275 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1278 private void handleSetRequest(ProviderRequest request, WorkSource source) {
1279 mProviderRequest = request;
1280 mWorkSource = source;
1281 updateRequirements();
1284 // Called when the requirements for GPS may have changed
1285 private void updateRequirements() {
1286 if (mProviderRequest == null || mWorkSource == null) {
1290 boolean singleShot = false;
1292 // see if the request is for a single update
1293 if (mProviderRequest.locationRequests != null
1294 && mProviderRequest.locationRequests.size() > 0) {
1295 // if any request has zero or more than one updates
1296 // requested, then this is not single-shot mode
1299 for (LocationRequest lr : mProviderRequest.locationRequests) {
1300 if (lr.getNumUpdates() != 1) {
1306 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1307 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1308 // update client uids
1309 updateClientUids(mWorkSource);
1311 mFixInterval = (int) mProviderRequest.interval;
1313 // check for overflow
1314 if (mFixInterval != mProviderRequest.interval) {
1315 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1316 mFixInterval = Integer.MAX_VALUE;
1319 // apply request to GPS engine
1320 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1322 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1323 mFixInterval, 0, 0)) {
1324 Log.e(TAG, "set_position_mode failed in setMinTime()");
1326 } else if (!mStarted) {
1328 startNavigating(singleShot);
1331 updateClientUids(new WorkSource());
1334 mAlarmManager.cancel(mWakeupIntent);
1335 mAlarmManager.cancel(mTimeoutIntent);
1339 private void updateClientUids(WorkSource source) {
1340 // Update work source.
1341 WorkSource[] changes = mClientSource.setReturningDiffs(source);
1342 if (changes == null) {
1345 WorkSource newWork = changes[0];
1346 WorkSource goneWork = changes[1];
1348 // Update sources that were not previously tracked.
1349 if (newWork != null) {
1351 for (int i=0; i<newWork.size(); i++) {
1353 int uid = newWork.get(i);
1354 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
1355 AppOpsManager.OP_GPS, uid, newWork.getName(i));
1356 if (uid != lastuid) {
1358 mBatteryStats.noteStartGps(uid);
1360 } catch (RemoteException e) {
1361 Log.w(TAG, "RemoteException", e);
1366 // Update sources that are no longer tracked.
1367 if (goneWork != null) {
1369 for (int i=0; i<goneWork.size(); i++) {
1371 int uid = goneWork.get(i);
1372 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
1373 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
1374 if (uid != lastuid) {
1376 mBatteryStats.noteStopGps(uid);
1378 } catch (RemoteException e) {
1379 Log.w(TAG, "RemoteException", e);
1386 public boolean sendExtraCommand(String command, Bundle extras) {
1388 long identity = Binder.clearCallingIdentity();
1389 boolean result = false;
1391 if ("delete_aiding_data".equals(command)) {
1392 result = deleteAidingData(extras);
1393 } else if ("force_time_injection".equals(command)) {
1396 } else if ("force_xtra_injection".equals(command)) {
1397 if (mSupportsXtra) {
1398 xtraDownloadRequest();
1402 Log.w(TAG, "sendExtraCommand: unknown command " + command);
1405 Binder.restoreCallingIdentity(identity);
1409 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
1410 public boolean isHardwareGeofenceSupported() {
1411 return native_is_geofence_supported();
1414 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
1415 double longitude, double radius, int lastTransition, int monitorTransitions,
1416 int notificationResponsiveness, int unknownTimer) {
1417 return native_add_geofence(geofenceId, latitude, longitude, radius,
1418 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
1421 public boolean removeHardwareGeofence(int geofenceId) {
1422 return native_remove_geofence(geofenceId);
1425 public boolean pauseHardwareGeofence(int geofenceId) {
1426 return native_pause_geofence(geofenceId);
1429 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
1430 return native_resume_geofence(geofenceId, monitorTransition);
1434 private boolean deleteAidingData(Bundle extras) {
1437 if (extras == null) {
1438 flags = GPS_DELETE_ALL;
1441 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1442 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1443 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1444 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1445 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1446 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1447 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1448 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1449 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1450 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1451 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1452 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1453 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1457 native_delete_aiding_data(flags);
1464 private void startNavigating(boolean singleShot) {
1466 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1467 mTimeToFirstFix = 0;
1470 mSingleShot = singleShot;
1471 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1472 // Notify about suppressed output, if speed limit was previously exceeded.
1473 // Elsewhere, we check again with every speed output reported.
1474 if (mItarSpeedLimitExceeded) {
1475 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited " +
1476 "until slow enough speed reported.");
1479 boolean agpsEnabled =
1480 (Settings.Global.getInt(mContext.getContentResolver(),
1481 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1482 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1487 switch(mPositionMode) {
1488 case GPS_POSITION_MODE_STANDALONE:
1489 mode = "standalone";
1491 case GPS_POSITION_MODE_MS_ASSISTED:
1492 mode = "MS_ASSISTED";
1494 case GPS_POSITION_MODE_MS_BASED:
1501 Log.d(TAG, "setting position_mode to " + mode);
1504 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1505 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1508 Log.e(TAG, "set_position_mode failed in startNavigating()");
1511 if (!native_start()) {
1513 Log.e(TAG, "native_start failed in startNavigating()");
1517 // reset SV count to zero
1518 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
1519 mFixRequestTime = SystemClock.elapsedRealtime();
1520 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1521 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1522 // and our fix interval is not short
1523 if (mFixInterval >= NO_FIX_TIMEOUT) {
1524 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1525 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1531 private void stopNavigating() {
1532 if (DEBUG) Log.d(TAG, "stopNavigating");
1535 mSingleShot = false;
1537 mTimeToFirstFix = 0;
1540 // reset SV count to zero
1541 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
1545 private void hibernate() {
1546 // stop GPS until our next fix interval arrives
1548 mAlarmManager.cancel(mTimeoutIntent);
1549 mAlarmManager.cancel(mWakeupIntent);
1550 long now = SystemClock.elapsedRealtime();
1551 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1554 private boolean hasCapability(int capability) {
1555 return ((mEngineCapabilities & capability) != 0);
1560 * called from native code to update our position.
1562 private void reportLocation(boolean hasLatLong, Location location) {
1563 if (location.hasSpeed()) {
1564 mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
1567 if (mItarSpeedLimitExceeded) {
1568 Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
1569 " GPS/GNSS Navigation output blocked.");
1570 mGnssMetrics.logReceivedLocationStatus(false);
1571 return; // No output of location allowed
1574 if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString());
1576 synchronized (mLocation) {
1577 mLocation = location;
1578 // It would be nice to push the elapsed real-time timestamp
1579 // further down the stack, but this is still useful
1580 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1581 mLocation.setExtras(mLocationExtras);
1584 mILocationManager.reportLocation(mLocation, false);
1585 } catch (RemoteException e) {
1586 Log.e(TAG, "RemoteException calling reportLocation");
1590 mGnssMetrics.logReceivedLocationStatus(hasLatLong);
1592 if (location.hasAccuracy()) {
1593 mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy());
1595 if (mTimeToFirstFix > 0) {
1596 int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime);
1597 mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
1601 mLastFixTime = SystemClock.elapsedRealtime();
1602 // report time to first fix
1603 if (mTimeToFirstFix == 0 && hasLatLong) {
1604 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1605 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1606 mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
1608 // notify status listeners
1609 mListenerHelper.onFirstFix(mTimeToFirstFix);
1616 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1617 // we want to time out if we do not receive a fix
1618 // within the time out and we are requesting infrequent fixes
1619 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1620 mAlarmManager.cancel(mTimeoutIntent);
1623 // send an intent to notify that the GPS is receiving fixes.
1624 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1625 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1626 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1627 updateStatus(LocationProvider.AVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
1630 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1631 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1632 if (DEBUG) Log.d(TAG, "got fix, hibernating");
1638 * called from native code to update our status
1640 private void reportStatus(int status) {
1641 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1643 boolean wasNavigating = mNavigating;
1645 case GPS_STATUS_SESSION_BEGIN:
1649 case GPS_STATUS_SESSION_END:
1650 mNavigating = false;
1652 case GPS_STATUS_ENGINE_ON:
1655 case GPS_STATUS_ENGINE_OFF:
1657 mNavigating = false;
1661 if (wasNavigating != mNavigating) {
1662 mListenerHelper.onStatusChanged(mNavigating);
1664 // send an intent to notify that the GPS has been enabled or disabled
1665 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1666 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1667 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1672 * called from native code to update SV info
1674 private void reportSvStatus() {
1675 int svCount = native_read_sv_status(mSvidWithFlags,
1680 mListenerHelper.onSvStatusChanged(
1688 // Log CN0 as part of GNSS metrics
1689 mGnssMetrics.logCn0(mCn0s, svCount);
1692 Log.v(TAG, "SV count: " + svCount);
1694 // Calculate number of satellites used in fix.
1695 int usedInFixCount = 0;
1698 for (int i = 0; i < svCount; i++) {
1699 if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1701 if (mCn0s[i] > maxCn0) {
1702 maxCn0 = (int)mCn0s[i];
1704 meanCn0 += mCn0s[i];
1707 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1708 " cn0: " + mCn0s[i] +
1709 " elev: " + mSvElevations[i] +
1710 " azimuth: " + mSvAzimuths[i] +
1711 " carrier frequency: " + mSvCarrierFreqs[i] +
1712 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1714 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1716 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1718 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0
1722 if (usedInFixCount > 0) {
1723 meanCn0 /= usedInFixCount;
1725 // return number of sats used in fix instead of total reported
1726 updateStatus(mStatus, usedInFixCount, meanCn0, maxCn0);
1728 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1729 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1730 // send an intent to notify that the GPS is no longer receiving fixes.
1731 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1732 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1733 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1734 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
1739 * called from native code to update AGPS status
1741 private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1743 case GPS_REQUEST_AGPS_DATA_CONN:
1744 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1745 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1746 InetAddress connectionIpAddress = null;
1747 if (ipaddr != null) {
1749 connectionIpAddress = InetAddress.getByAddress(ipaddr);
1750 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1751 } catch (UnknownHostException e) {
1752 Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1755 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1757 case GPS_RELEASE_AGPS_DATA_CONN:
1758 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1759 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1761 case GPS_AGPS_DATA_CONNECTED:
1762 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1764 case GPS_AGPS_DATA_CONN_DONE:
1765 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1767 case GPS_AGPS_DATA_CONN_FAILED:
1768 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1771 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1775 private void releaseSuplConnection(int connStatus) {
1776 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1780 * called from native code to report NMEA data received
1782 private void reportNmea(long timestamp) {
1783 if (!mItarSpeedLimitExceeded) {
1784 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1785 String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1786 mListenerHelper.onNmeaReceived(timestamp, nmea);
1791 * called from native code - GNSS measurements callback
1793 private void reportMeasurementData(GnssMeasurementsEvent event) {
1794 if (!mItarSpeedLimitExceeded) {
1795 // send to handler to allow native to return quickly
1796 mHandler.post(new Runnable() {
1799 mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1806 * called from native code - GNSS navigation message callback
1808 private void reportNavigationMessage(GnssNavigationMessage event) {
1809 if (!mItarSpeedLimitExceeded) {
1810 // send to handler to allow native to return quickly
1811 mHandler.post(new Runnable() {
1814 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1821 * called from native code to inform us what the GPS engine capabilities are
1823 private void setEngineCapabilities(int capabilities) {
1824 mEngineCapabilities = capabilities;
1826 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1827 mOnDemandTimeInjection = true;
1831 mGnssMeasurementsProvider.onCapabilitiesUpdated(
1832 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
1833 mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1834 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
1838 * Called from native code to inform us the hardware information.
1840 private void setGnssYearOfHardware(int yearOfHardware) {
1841 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1842 mYearOfHardware = yearOfHardware;
1845 public interface GnssSystemInfoProvider {
1847 * Returns the year of GPS hardware.
1849 int getGnssYearOfHardware();
1855 public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1856 return new GnssSystemInfoProvider() {
1858 public int getGnssYearOfHardware() {
1859 return mYearOfHardware;
1864 public interface GnssBatchingProvider {
1866 * Returns the GNSS batching size
1870 * Starts the hardware batching operation
1872 boolean start(long periodNanos, boolean wakeOnFifoFull);
1874 * Forces a flush of existing locations from the hardware batching
1878 * Stops the batching operation
1886 public GnssBatchingProvider getGnssBatchingProvider() {
1887 return new GnssBatchingProvider() {
1889 public int getSize() {
1890 return native_get_batch_size();
1893 public boolean start(long periodNanos, boolean wakeOnFifoFull) {
1894 if (periodNanos <= 0) {
1895 Log.e(TAG, "Invalid periodNanos " + periodNanos +
1896 "in batching request, not started");
1899 return native_start_batch(periodNanos, wakeOnFifoFull);
1902 public void flush() {
1903 native_flush_batch();
1906 public boolean stop() {
1907 return native_stop_batch();
1912 public interface GnssMetricsProvider {
1914 * Returns GNSS metrics as proto string
1916 String getGnssMetricsAsProtoString();
1922 public GnssMetricsProvider getGnssMetricsProvider() {
1923 return new GnssMetricsProvider() {
1925 public String getGnssMetricsAsProtoString() {
1926 return mGnssMetrics.dumpGnssMetricsAsProtoString();
1932 * Initialize Batching if enabled
1934 private void enableBatching() {
1935 if (!native_init_batching()) {
1936 Log.e(TAG, "Failed to initialize GNSS batching");
1943 private void disableBatching() {
1944 native_stop_batch();
1945 native_cleanup_batching();
1949 * called from native code - GNSS location batch callback
1951 private void reportLocationBatch(Location[] locationArray) {
1952 List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
1953 if(DEBUG) { Log.d(TAG, "Location batch of size " + locationArray.length + "reported"); }
1955 mILocationManager.reportLocationBatch(locations);
1956 } catch (RemoteException e) {
1957 Log.e(TAG, "RemoteException calling reportLocationBatch");
1962 * called from native code to request XTRA data
1964 private void xtraDownloadRequest() {
1965 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1966 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1970 * Converts the GPS HAL status to the internal Geofence Hardware status.
1972 private int getGeofenceStatus(int status) {
1974 case GPS_GEOFENCE_OPERATION_SUCCESS:
1975 return GeofenceHardware.GEOFENCE_SUCCESS;
1976 case GPS_GEOFENCE_ERROR_GENERIC:
1977 return GeofenceHardware.GEOFENCE_FAILURE;
1978 case GPS_GEOFENCE_ERROR_ID_EXISTS:
1979 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1980 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1981 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1982 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1983 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1984 case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1985 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1992 * Called from native to report GPS Geofence transition
1993 * All geofence callbacks are called on the same thread
1995 private void reportGeofenceTransition(int geofenceId, Location location, int transition,
1996 long transitionTimestamp) {
1997 if (mGeofenceHardwareImpl == null) {
1998 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2001 mGeofenceHardwareImpl.reportGeofenceTransition(
2005 transitionTimestamp,
2006 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
2007 FusedBatchOptions.SourceTechnologies.GNSS);
2011 * called from native code to report GPS status change.
2013 private void reportGeofenceStatus(int status, Location location) {
2014 if (mGeofenceHardwareImpl == null) {
2015 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2017 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
2018 if(status == GPS_GEOFENCE_AVAILABLE) {
2019 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
2021 mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
2022 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
2025 FusedBatchOptions.SourceTechnologies.GNSS);
2029 * called from native code - Geofence Add callback
2031 private void reportGeofenceAddStatus(int geofenceId, int status) {
2032 if (mGeofenceHardwareImpl == null) {
2033 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2035 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
2039 * called from native code - Geofence Remove callback
2041 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
2042 if (mGeofenceHardwareImpl == null) {
2043 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2045 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
2049 * called from native code - Geofence Pause callback
2051 private void reportGeofencePauseStatus(int geofenceId, int status) {
2052 if (mGeofenceHardwareImpl == null) {
2053 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2055 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
2059 * called from native code - Geofence Resume callback
2061 private void reportGeofenceResumeStatus(int geofenceId, int status) {
2062 if (mGeofenceHardwareImpl == null) {
2063 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2065 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
2068 //=============================================================
2069 // NI Client support
2070 //=============================================================
2071 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
2072 // Sends a response for an NI request to HAL.
2074 public boolean sendNiResponse(int notificationId, int userResponse)
2076 // TODO Add Permission check
2078 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
2079 ", response: " + userResponse);
2080 native_send_ni_response(notificationId, userResponse);
2085 public INetInitiatedListener getNetInitiatedListener() {
2086 return mNetInitiatedListener;
2089 // Called by JNI function to report an NI request.
2090 public void reportNiNotification(
2095 int defaultResponse,
2098 int requestorIdEncoding,
2102 Log.i(TAG, "reportNiNotification: entered");
2103 Log.i(TAG, "notificationId: " + notificationId +
2104 ", niType: " + niType +
2105 ", notifyFlags: " + notifyFlags +
2106 ", timeout: " + timeout +
2107 ", defaultResponse: " + defaultResponse);
2109 Log.i(TAG, "requestorId: " + requestorId +
2111 ", requestorIdEncoding: " + requestorIdEncoding +
2112 ", textEncoding: " + textEncoding);
2114 GpsNiNotification notification = new GpsNiNotification();
2116 notification.notificationId = notificationId;
2117 notification.niType = niType;
2118 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
2119 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
2120 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
2121 notification.timeout = timeout;
2122 notification.defaultResponse = defaultResponse;
2123 notification.requestorId = requestorId;
2124 notification.text = text;
2125 notification.requestorIdEncoding = requestorIdEncoding;
2126 notification.textEncoding = textEncoding;
2128 mNIHandler.handleNiNotification(notification);
2132 * Called from native code to request set id info.
2133 * We should be careful about receiving null string from the TelephonyManager,
2134 * because sending null String to JNI function would cause a crash.
2137 private void requestSetID(int flags) {
2138 TelephonyManager phone = (TelephonyManager)
2139 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2140 int type = AGPS_SETID_TYPE_NONE;
2143 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
2144 String data_temp = phone.getSubscriberId();
2145 if (data_temp == null) {
2146 // This means the framework does not have the SIM card ready.
2148 // This means the framework has the SIM card.
2150 type = AGPS_SETID_TYPE_IMSI;
2153 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
2154 String data_temp = phone.getLine1Number();
2155 if (data_temp == null) {
2156 // This means the framework does not have the SIM card ready.
2158 // This means the framework has the SIM card.
2160 type = AGPS_SETID_TYPE_MSISDN;
2163 native_agps_set_id(type, data);
2167 * Called from native code to request utc time info
2169 private void requestUtcTime() {
2170 if (DEBUG) Log.d(TAG, "utcTimeRequest");
2171 sendMessage(INJECT_NTP_TIME, 0, null);
2175 * Called from native code to request reference location info
2178 private void requestRefLocation() {
2179 TelephonyManager phone = (TelephonyManager)
2180 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2181 final int phoneType = phone.getPhoneType();
2182 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2183 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2184 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2185 && (phone.getNetworkOperator().length() > 3)) {
2187 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
2188 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2189 int networkType = phone.getNetworkType();
2190 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2191 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2192 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2193 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2194 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2195 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2197 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2199 native_agps_set_ref_location_cellid(type, mcc, mnc,
2200 gsm_cell.getLac(), gsm_cell.getCid());
2202 Log.e(TAG,"Error getting cell location info.");
2204 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2205 Log.e(TAG, "CDMA not supported.");
2209 private void sendMessage(int message, int arg, Object obj) {
2210 // hold a wake lock until this message is delivered
2211 // note that this assumes the message will not be removed from the queue before
2212 // it is handled (otherwise the wake lock would be leaked).
2213 mWakeLock.acquire();
2214 if (Log.isLoggable(TAG, Log.INFO)) {
2215 Log.i(TAG, "WakeLock acquired by sendMessage(" + messageIdAsString(message) + ", " + arg
2216 + ", " + obj + ")");
2218 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2221 private final class ProviderHandler extends Handler {
2222 public ProviderHandler(Looper looper) {
2223 super(looper, null, true /*async*/);
2227 public void handleMessage(Message msg) {
2228 int message = msg.what;
2231 if (msg.arg1 == 1) {
2238 GpsRequest gpsRequest = (GpsRequest) msg.obj;
2239 handleSetRequest(gpsRequest.request, gpsRequest.source);
2241 case UPDATE_NETWORK_STATE:
2242 handleUpdateNetworkState((Network) msg.obj);
2244 case REQUEST_SUPL_CONNECTION:
2245 handleRequestSuplConnection((InetAddress) msg.obj);
2247 case RELEASE_SUPL_CONNECTION:
2248 handleReleaseSuplConnection(msg.arg1);
2250 case INJECT_NTP_TIME:
2251 handleInjectNtpTime();
2253 case DOWNLOAD_XTRA_DATA:
2254 handleDownloadXtraData();
2256 case INJECT_NTP_TIME_FINISHED:
2257 mInjectNtpTimePending = STATE_IDLE;
2259 case DOWNLOAD_XTRA_DATA_FINISHED:
2260 mDownloadXtraDataPending = STATE_IDLE;
2262 case UPDATE_LOCATION:
2263 handleUpdateLocation((Location) msg.obj);
2265 case SUBSCRIPTION_OR_SIM_CHANGED:
2266 subscriptionOrSimChanged(mContext);
2268 case INITIALIZE_HANDLER:
2272 if (msg.arg2 == 1) {
2273 // wakelock was taken for this message, release it
2274 mWakeLock.release();
2275 if (Log.isLoggable(TAG, Log.INFO)) {
2276 Log.i(TAG, "WakeLock released by handleMessage(" + messageIdAsString(message)
2277 + ", " + msg.arg1 + ", " + msg.obj + ")");
2283 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2284 * It is in charge of loading properties and registering for events that will be posted to
2287 private void handleInitialize() {
2288 // load default GPS configuration
2289 // (this configuration might change in the future based on SIM changes)
2290 reloadGpsProperties(mContext, mProperties);
2292 // TODO: When this object "finishes" we should unregister by invoking
2293 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
2294 // This is not strictly necessary because it will be unregistered if the
2295 // notification fails but it is good form.
2297 // Register for SubscriptionInfo list changes which is guaranteed
2298 // to invoke onSubscriptionsChanged the first time.
2299 SubscriptionManager.from(mContext)
2300 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2302 // listen for events
2303 IntentFilter intentFilter;
2304 if (native_is_agps_ril_supported()) {
2305 intentFilter = new IntentFilter();
2306 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2307 intentFilter.addDataScheme("sms");
2308 intentFilter.addDataAuthority("localhost", "7275");
2309 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2311 intentFilter = new IntentFilter();
2312 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2314 intentFilter.addDataType("application/vnd.omaloc-supl-init");
2315 } catch (IntentFilter.MalformedMimeTypeException e) {
2316 Log.w(TAG, "Malformed SUPL init mime type");
2318 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2320 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2321 + " HAL is not supported");
2324 intentFilter = new IntentFilter();
2325 intentFilter.addAction(ALARM_WAKEUP);
2326 intentFilter.addAction(ALARM_TIMEOUT);
2327 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2328 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2329 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2330 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2331 intentFilter.addAction(SIM_STATE_CHANGED);
2332 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2334 // register for connectivity change events, this is equivalent to the deprecated way of
2335 // registering for CONNECTIVITY_ACTION broadcasts
2336 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2337 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
2338 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
2339 // On watches, Bluetooth is the most important network type.
2341 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
2343 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH);
2345 NetworkRequest networkRequest = networkRequestBuilder.build();
2346 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2348 // listen for PASSIVE_PROVIDER updates
2349 LocationManager locManager =
2350 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2352 float minDistance = 0;
2353 boolean oneShot = false;
2354 LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2355 LocationManager.PASSIVE_PROVIDER,
2359 // Don't keep track of this request since it's done on behalf of other clients
2360 // (which are kept track of separately).
2361 request.setHideFromAppOps(true);
2362 locManager.requestLocationUpdates(
2364 new NetworkLocationListener(),
2369 private final class NetworkLocationListener implements LocationListener {
2371 public void onLocationChanged(Location location) {
2372 // this callback happens on mHandler looper
2373 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2374 handleUpdateLocation(location);
2378 public void onStatusChanged(String provider, int status, Bundle extras) { }
2380 public void onProviderEnabled(String provider) { }
2382 public void onProviderDisabled(String provider) { }
2385 private String getSelectedApn() {
2386 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2387 Cursor cursor = null;
2389 cursor = mContext.getContentResolver().query(
2391 new String[] { "apn" },
2392 null /* selection */,
2393 null /* selectionArgs */,
2394 Carriers.DEFAULT_SORT_ORDER);
2395 if (cursor != null && cursor.moveToFirst()) {
2396 return cursor.getString(0);
2398 Log.e(TAG, "No APN found to select.");
2400 } catch (Exception e) {
2401 Log.e(TAG, "Error encountered on selecting the APN.", e);
2403 if (cursor != null) {
2411 private int getApnIpType(String apn) {
2412 ensureInHandlerThread();
2417 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2418 Cursor cursor = null;
2420 cursor = mContext.getContentResolver().query(
2421 Carriers.CONTENT_URI,
2422 new String[] { Carriers.PROTOCOL },
2425 Carriers.DEFAULT_SORT_ORDER);
2427 if (null != cursor && cursor.moveToFirst()) {
2428 return translateToApnIpType(cursor.getString(0), apn);
2430 Log.e(TAG, "No entry found in query for APN: " + apn);
2432 } catch (Exception e) {
2433 Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2435 if (cursor != null) {
2443 private int translateToApnIpType(String ipProtocol, String apn) {
2444 if ("IP".equals(ipProtocol)) {
2447 if ("IPV6".equals(ipProtocol)) {
2450 if ("IPV4V6".equals(ipProtocol)) {
2454 // we hit the default case so the ipProtocol is not recognized
2455 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2456 Log.e(TAG, message);
2460 private void setRouting() {
2461 if (mAGpsDataConnectionIpAddr == null) {
2465 // TODO: replace the use of this deprecated API
2466 boolean result = mConnMgr.requestRouteToHostAddress(
2467 ConnectivityManager.TYPE_MOBILE_SUPL,
2468 mAGpsDataConnectionIpAddr);
2471 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2473 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2478 * @return {@code true} if there is a data network available for outgoing connections,
2479 * {@code false} otherwise.
2481 private boolean isDataNetworkConnected() {
2482 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2483 return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2487 * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2489 private void ensureInHandlerThread() {
2490 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2493 throw new RuntimeException("This method must run on the Handler thread.");
2497 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2499 private String agpsDataConnStateAsString() {
2500 switch(mAGpsDataConnectionState) {
2501 case AGPS_DATA_CONNECTION_CLOSED:
2503 case AGPS_DATA_CONNECTION_OPEN:
2505 case AGPS_DATA_CONNECTION_OPENING:
2513 * @return A string representing the given GPS_AGPS_DATA status.
2515 private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2516 switch (agpsDataConnStatus) {
2517 case GPS_AGPS_DATA_CONNECTED:
2519 case GPS_AGPS_DATA_CONN_DONE:
2521 case GPS_AGPS_DATA_CONN_FAILED:
2523 case GPS_RELEASE_AGPS_DATA_CONN:
2525 case GPS_REQUEST_AGPS_DATA_CONN:
2533 * @return A string representing the given message ID.
2535 private String messageIdAsString(int message) {
2540 return "SET_REQUEST";
2541 case UPDATE_NETWORK_STATE:
2542 return "UPDATE_NETWORK_STATE";
2543 case REQUEST_SUPL_CONNECTION:
2544 return "REQUEST_SUPL_CONNECTION";
2545 case RELEASE_SUPL_CONNECTION:
2546 return "RELEASE_SUPL_CONNECTION";
2547 case INJECT_NTP_TIME:
2548 return "INJECT_NTP_TIME";
2549 case DOWNLOAD_XTRA_DATA:
2550 return "DOWNLOAD_XTRA_DATA";
2551 case INJECT_NTP_TIME_FINISHED:
2552 return "INJECT_NTP_TIME_FINISHED";
2553 case DOWNLOAD_XTRA_DATA_FINISHED:
2554 return "DOWNLOAD_XTRA_DATA_FINISHED";
2555 case UPDATE_LOCATION:
2556 return "UPDATE_LOCATION";
2557 case SUBSCRIPTION_OR_SIM_CHANGED:
2558 return "SUBSCRIPTION_OR_SIM_CHANGED";
2559 case INITIALIZE_HANDLER:
2560 return "INITIALIZE_HANDLER";
2569 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2570 StringBuilder s = new StringBuilder();
2571 s.append(" mStarted=").append(mStarted).append('\n');
2572 s.append(" mFixInterval=").append(mFixInterval).append('\n');
2573 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2574 s.append(" mDisableLocation (battery saver mode)=").append(mLocationDisabledForPowerSaving)
2576 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2578 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2579 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2580 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2581 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2582 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2583 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2584 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2585 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2587 s.append(mGnssMetrics.dumpGnssMetricsAsText());
2588 s.append(" native internal state: ").append(native_get_internal_state());
2594 * A simple implementation of exponential backoff.
2596 private static final class BackOff {
2597 private static final int MULTIPLIER = 2;
2598 private final long mInitIntervalMillis;
2599 private final long mMaxIntervalMillis;
2600 private long mCurrentIntervalMillis;
2602 public BackOff(long initIntervalMillis, long maxIntervalMillis) {
2603 mInitIntervalMillis = initIntervalMillis;
2604 mMaxIntervalMillis = maxIntervalMillis;
2606 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2609 public long nextBackoffMillis() {
2610 if (mCurrentIntervalMillis > mMaxIntervalMillis) {
2611 return mMaxIntervalMillis;
2614 mCurrentIntervalMillis *= MULTIPLIER;
2615 return mCurrentIntervalMillis;
2618 public void reset() {
2619 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2623 // for GPS SV statistics
2624 private static final int MAX_SVS = 64;
2626 // preallocated arrays, to avoid memory allocation in reportStatus()
2627 private int mSvidWithFlags[] = new int[MAX_SVS];
2628 private float mCn0s[] = new float[MAX_SVS];
2629 private float mSvElevations[] = new float[MAX_SVS];
2630 private float mSvAzimuths[] = new float[MAX_SVS];
2631 private float mSvCarrierFreqs[] = new float[MAX_SVS];
2632 private int mSvCount;
2633 private int mMeanCn0;
2634 private int mMaxCn0;
2635 // preallocated to avoid memory allocation in reportNmea()
2636 private byte[] mNmeaBuffer = new byte[120];
2638 static { class_init_native(); }
2639 private static native void class_init_native();
2640 private static native boolean native_is_supported();
2641 private static native boolean native_is_agps_ril_supported();
2642 private static native boolean native_is_gnss_configuration_supported();
2644 private native boolean native_init();
2645 private native void native_cleanup();
2646 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2647 int preferred_accuracy, int preferred_time);
2648 private native boolean native_start();
2649 private native boolean native_stop();
2650 private native void native_delete_aiding_data(int flags);
2651 // returns number of SVs
2652 // mask[0] is ephemeris mask and mask[1] is almanac mask
2653 private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
2654 float[] azimuths, float[] carrierFrequencies);
2655 private native int native_read_nmea(byte[] buffer, int bufferSize);
2656 private native void native_inject_location(double latitude, double longitude, float accuracy);
2659 private native void native_inject_time(long time, long timeReference, int uncertainty);
2660 private native boolean native_supports_xtra();
2661 private native void native_inject_xtra_data(byte[] data, int length);
2664 private native String native_get_internal_state();
2667 private native void native_agps_data_conn_open(String apn, int apnIpType);
2668 private native void native_agps_data_conn_closed();
2669 private native void native_agps_data_conn_failed();
2670 private native void native_agps_ni_message(byte [] msg, int length);
2671 private native void native_set_agps_server(int type, String hostname, int port);
2673 // Network-initiated (NI) Support
2674 private native void native_send_ni_response(int notificationId, int userResponse);
2677 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2679 private native void native_agps_set_id(int type, String setid);
2681 private native void native_update_network_state(boolean connected, int type,
2682 boolean roaming, boolean available, String extraInfo, String defaultAPN);
2684 // Hardware Geofence support.
2685 private static native boolean native_is_geofence_supported();
2686 private static native boolean native_add_geofence(int geofenceId, double latitude,
2687 double longitude, double radius, int lastTransition,int monitorTransitions,
2688 int notificationResponsivenes, int unknownTimer);
2689 private static native boolean native_remove_geofence(int geofenceId);
2690 private static native boolean native_resume_geofence(int geofenceId, int transitions);
2691 private static native boolean native_pause_geofence(int geofenceId);
2693 // Gps Hal measurements support.
2694 private static native boolean native_is_measurement_supported();
2695 private native boolean native_start_measurement_collection();
2696 private native boolean native_stop_measurement_collection();
2698 // Gps Navigation message support.
2699 private static native boolean native_is_navigation_message_supported();
2700 private native boolean native_start_navigation_message_collection();
2701 private native boolean native_stop_navigation_message_collection();
2703 // GNSS Configuration
2704 private static native boolean native_set_supl_version(int version);
2705 private static native boolean native_set_supl_mode(int mode);
2706 private static native boolean native_set_supl_es(int es);
2707 private static native boolean native_set_lpp_profile(int lppProfile);
2708 private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
2709 private static native boolean native_set_gps_lock(int gpsLock);
2710 private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
2713 private static native int native_get_batch_size();
2714 private static native boolean native_start_batch(long periodNanos, boolean wakeOnFifoFull);
2715 private static native void native_flush_batch();
2716 private static native boolean native_stop_batch();
2717 private static native boolean native_init_batching();
2718 private static native void native_cleanup_batching();