1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.location; 18 19 import android.app.AlarmManager; 20 import android.app.AppOpsManager; 21 import android.app.PendingIntent; 22 import android.content.BroadcastReceiver; 23 import android.content.ContentResolver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 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.GnssMeasurementsEvent; 33 import android.location.GnssNavigationMessage; 34 import android.location.GnssStatus; 35 import android.location.IGnssStatusListener; 36 import android.location.IGnssStatusProvider; 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.BatteryStats; 53 import android.os.Binder; 54 import android.os.Bundle; 55 import android.os.Handler; 56 import android.os.Looper; 57 import android.os.Message; 58 import android.os.PersistableBundle; 59 import android.os.PowerManager; 60 import android.os.PowerManager.ServiceType; 61 import android.os.PowerSaveState; 62 import android.os.RemoteException; 63 import android.os.ServiceManager; 64 import android.os.SystemClock; 65 import android.os.SystemProperties; 66 import android.os.UserHandle; 67 import android.os.WorkSource; 68 import android.os.WorkSource.WorkChain; 69 import android.provider.Settings; 70 import android.provider.Telephony.Carriers; 71 import android.provider.Telephony.Sms.Intents; 72 import android.telephony.CarrierConfigManager; 73 import android.telephony.SubscriptionManager; 74 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 75 import android.telephony.TelephonyManager; 76 import android.telephony.gsm.GsmCellLocation; 77 import android.text.TextUtils; 78 import android.util.Log; 79 80 import com.android.internal.app.IBatteryStats; 81 import com.android.internal.location.GpsNetInitiatedHandler; 82 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; 83 import com.android.internal.location.ProviderProperties; 84 import com.android.internal.location.ProviderRequest; 85 import com.android.internal.location.gnssmetrics.GnssMetrics; 86 import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback; 87 import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback; 88 89 import libcore.io.IoUtils; 90 91 import java.io.File; 92 import java.io.FileDescriptor; 93 import java.io.FileInputStream; 94 import java.io.IOException; 95 import java.io.PrintWriter; 96 import java.net.InetAddress; 97 import java.net.UnknownHostException; 98 import java.util.ArrayList; 99 import java.util.Arrays; 100 import java.util.HashMap; 101 import java.util.List; 102 import java.util.Map; 103 import java.util.Map.Entry; 104 import java.util.Properties; 105 106 /** 107 * A GNSS implementation of LocationProvider used by LocationManager. 108 * 109 * {@hide} 110 */ 111 public class GnssLocationProvider implements LocationProviderInterface, InjectNtpTimeCallback, 112 GnssSatelliteBlacklistCallback { 113 114 private static final String TAG = "GnssLocationProvider"; 115 116 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 117 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 118 119 private static final ProviderProperties PROPERTIES = new ProviderProperties( 120 true, true, false, false, true, true, true, 121 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE); 122 123 // these need to match GnssPositionMode enum in IGnss.hal 124 private static final int GPS_POSITION_MODE_STANDALONE = 0; 125 private static final int GPS_POSITION_MODE_MS_BASED = 1; 126 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2; 127 128 // these need to match GnssPositionRecurrence enum in IGnss.hal 129 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0; 130 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1; 131 132 // these need to match GnssStatusValue enum in IGnssCallback.hal 133 private static final int GPS_STATUS_NONE = 0; 134 private static final int GPS_STATUS_SESSION_BEGIN = 1; 135 private static final int GPS_STATUS_SESSION_END = 2; 136 private static final int GPS_STATUS_ENGINE_ON = 3; 137 private static final int GPS_STATUS_ENGINE_OFF = 4; 138 139 // these need to match AGnssStatusValue enum in IAGnssCallback.hal 140 /** AGPS status event values. */ 141 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1; 142 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2; 143 private static final int GPS_AGPS_DATA_CONNECTED = 3; 144 private static final int GPS_AGPS_DATA_CONN_DONE = 4; 145 private static final int GPS_AGPS_DATA_CONN_FAILED = 5; 146 147 // these need to match GnssLocationFlags enum in types.hal 148 private static final int LOCATION_INVALID = 0; 149 private static final int LOCATION_HAS_LAT_LONG = 1; 150 private static final int LOCATION_HAS_ALTITUDE = 2; 151 private static final int LOCATION_HAS_SPEED = 4; 152 private static final int LOCATION_HAS_BEARING = 8; 153 private static final int LOCATION_HAS_HORIZONTAL_ACCURACY = 16; 154 private static final int LOCATION_HAS_VERTICAL_ACCURACY = 32; 155 private static final int LOCATION_HAS_SPEED_ACCURACY = 64; 156 private static final int LOCATION_HAS_BEARING_ACCURACY = 128; 157 158 159 // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal 160 private static final int GPS_DELETE_EPHEMERIS = 0x0001; 161 private static final int GPS_DELETE_ALMANAC = 0x0002; 162 private static final int GPS_DELETE_POSITION = 0x0004; 163 private static final int GPS_DELETE_TIME = 0x0008; 164 private static final int GPS_DELETE_IONO = 0x0010; 165 private static final int GPS_DELETE_UTC = 0x0020; 166 private static final int GPS_DELETE_HEALTH = 0x0040; 167 private static final int GPS_DELETE_SVDIR = 0x0080; 168 private static final int GPS_DELETE_SVSTEER = 0x0100; 169 private static final int GPS_DELETE_SADATA = 0x0200; 170 private static final int GPS_DELETE_RTI = 0x0400; 171 private static final int GPS_DELETE_CELLDB_INFO = 0x8000; 172 private static final int GPS_DELETE_ALL = 0xFFFF; 173 174 // The GPS_CAPABILITY_* flags must match Capabilities enum in IGnssCallback.hal 175 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001; 176 private static final int GPS_CAPABILITY_MSB = 0x0000002; 177 private static final int GPS_CAPABILITY_MSA = 0x0000004; 178 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008; 179 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010; 180 private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020; 181 private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040; 182 private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080; 183 184 // The AGPS SUPL mode 185 private static final int AGPS_SUPL_MODE_MSA = 0x02; 186 private static final int AGPS_SUPL_MODE_MSB = 0x01; 187 188 // these need to match AGnssType enum in IAGnssCallback.hal 189 private static final int AGPS_TYPE_SUPL = 1; 190 private static final int AGPS_TYPE_C2K = 2; 191 192 // these must match the ApnIpType enum in IAGnss.hal 193 private static final int APN_INVALID = 0; 194 private static final int APN_IPV4 = 1; 195 private static final int APN_IPV6 = 2; 196 private static final int APN_IPV4V6 = 3; 197 198 // for mAGpsDataConnectionState 199 private static final int AGPS_DATA_CONNECTION_CLOSED = 0; 200 private static final int AGPS_DATA_CONNECTION_OPENING = 1; 201 private static final int AGPS_DATA_CONNECTION_OPEN = 2; 202 203 // Handler messages 204 private static final int CHECK_LOCATION = 1; 205 private static final int ENABLE = 2; 206 private static final int SET_REQUEST = 3; 207 private static final int UPDATE_NETWORK_STATE = 4; 208 private static final int INJECT_NTP_TIME = 5; 209 private static final int DOWNLOAD_XTRA_DATA = 6; 210 private static final int UPDATE_LOCATION = 7; // Handle external location from network listener 211 private static final int ADD_LISTENER = 8; 212 private static final int REMOVE_LISTENER = 9; 213 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11; 214 private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12; 215 private static final int INITIALIZE_HANDLER = 13; 216 private static final int REQUEST_SUPL_CONNECTION = 14; 217 private static final int RELEASE_SUPL_CONNECTION = 15; 218 private static final int REQUEST_LOCATION = 16; 219 private static final int REPORT_LOCATION = 17; // HAL reports location 220 private static final int REPORT_SV_STATUS = 18; // HAL reports SV status 221 222 // Request setid 223 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1; 224 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2; 225 226 //TODO(b/33112647): Create gps_debug.conf with commented career parameters. 227 private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf"; 228 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; 232 233 // set id info 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; 237 238 private static final int GPS_GEOFENCE_UNAVAILABLE = 1 << 0L; 239 private static final int GPS_GEOFENCE_AVAILABLE = 1 << 1L; 240 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; 248 249 // TCP/IP constants. 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; 253 254 // 1 second, or 1 Hz frequency. 255 private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000; 256 // Default update duration in milliseconds for REQUEST_LOCATION. 257 private static final long LOCATION_UPDATE_DURATION_MILLIS = 0; 258 259 /** simpler wrapper for ProviderRequest + Worksource */ 260 private static class GpsRequest { 261 public ProviderRequest request; 262 public WorkSource source; 263 GpsRequest(ProviderRequest request, WorkSource source)264 public GpsRequest(ProviderRequest request, WorkSource source) { 265 this.request = request; 266 this.source = source; 267 } 268 } 269 270 // Threadsafe class to hold stats reported in the Extras Bundle 271 private static class LocationExtras { 272 private int mSvCount; 273 private int mMeanCn0; 274 private int mMaxCn0; 275 private final Bundle mBundle; 276 LocationExtras()277 public LocationExtras() { 278 mBundle = new Bundle(); 279 } 280 set(int svCount, int meanCn0, int maxCn0)281 public void set(int svCount, int meanCn0, int maxCn0) { 282 synchronized(this) { 283 mSvCount = svCount; 284 mMeanCn0 = meanCn0; 285 mMaxCn0 = maxCn0; 286 } 287 setBundle(mBundle); 288 } 289 reset()290 public void reset() { 291 set(0,0,0); 292 } 293 294 // Also used by outside methods to add to other bundles setBundle(Bundle extras)295 public void setBundle(Bundle extras) { 296 if (extras != null) { 297 synchronized (this) { 298 extras.putInt("satellites", mSvCount); 299 extras.putInt("meanCn0", mMeanCn0); 300 extras.putInt("maxCn0", mMaxCn0); 301 } 302 } 303 } 304 getBundle()305 public Bundle getBundle() { 306 synchronized (this) { 307 return new Bundle(mBundle); 308 } 309 } 310 } 311 312 private final Object mLock = new Object(); 313 314 // current status 315 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE; 316 317 // time for last status update 318 private long mStatusUpdateTime = SystemClock.elapsedRealtime(); 319 320 // turn off GPS fix icon if we haven't received a fix in 10 seconds 321 private static final long RECENT_FIX_TIMEOUT = 10 * 1000; 322 323 // stop trying if we do not receive a fix within 60 seconds 324 private static final int NO_FIX_TIMEOUT = 60 * 1000; 325 326 // if the fix interval is below this we leave GPS on, 327 // if above then we cycle the GPS driver. 328 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane. 329 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000; 330 331 // how long to wait if we have a network error in NTP or XTRA downloading 332 // the initial value of the exponential backoff 333 // current setting - 5 minutes 334 private static final long RETRY_INTERVAL = 5 * 60 * 1000; 335 // how long to wait if we have a network error in NTP or XTRA downloading 336 // the max value of the exponential backoff 337 // current setting - 4 hours 338 private static final long MAX_RETRY_INTERVAL = 4 * 60 * 60 * 1000; 339 340 // Timeout when holding wakelocks for downloading XTRA data. 341 private static final long DOWNLOAD_XTRA_DATA_TIMEOUT_MS = 60 * 1000; 342 343 private final ExponentialBackOff mXtraBackOff = new ExponentialBackOff(RETRY_INTERVAL, 344 MAX_RETRY_INTERVAL); 345 346 // true if we are enabled, protected by this 347 private boolean mEnabled; 348 349 // states for injecting ntp and downloading xtra data 350 private static final int STATE_PENDING_NETWORK = 0; 351 private static final int STATE_DOWNLOADING = 1; 352 private static final int STATE_IDLE = 2; 353 354 // flags to trigger NTP or XTRA data download when network becomes available 355 // initialized to true so we do NTP and XTRA when the network comes up after booting 356 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK; 357 358 // true if GPS is navigating 359 private boolean mNavigating; 360 361 // true if GPS engine is on 362 private boolean mEngineOn; 363 364 // requested frequency of fixes, in milliseconds 365 private int mFixInterval = 1000; 366 367 // true if low power mode for the GNSS chipset is part of the latest request. 368 private boolean mLowPowerMode = false; 369 370 // true if we started navigation 371 private boolean mStarted; 372 373 // true if single shot request is in progress 374 private boolean mSingleShot; 375 376 // capabilities of the GPS engine 377 private int mEngineCapabilities; 378 379 // true if XTRA is supported 380 private boolean mSupportsXtra; 381 382 // for calculating time to first fix 383 private long mFixRequestTime = 0; 384 // time to first fix for most recent session 385 private int mTimeToFirstFix = 0; 386 // time we received our last fix 387 private long mLastFixTime; 388 389 private int mPositionMode; 390 391 // Current request from underlying location clients. 392 private ProviderRequest mProviderRequest = null; 393 // The WorkSource associated with the most recent client request (i.e, most recent call to 394 // setRequest). 395 private WorkSource mWorkSource = null; 396 // True if gps should be disabled (used to support battery saver mode in settings). 397 private boolean mDisableGps = false; 398 399 /** 400 * Properties loaded from PROPERTIES_FILE. 401 * It must be accessed only inside {@link #mHandler}. 402 */ 403 private Properties mProperties; 404 405 private String mSuplServerHost; 406 private int mSuplServerPort = TCP_MIN_PORT; 407 private String mC2KServerHost; 408 private int mC2KServerPort; 409 private boolean mSuplEsEnabled = false; 410 411 private final Context mContext; 412 private final ILocationManager mILocationManager; 413 private final LocationExtras mLocationExtras = new LocationExtras(); 414 private final GnssStatusListenerHelper mListenerHelper; 415 private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper; 416 private final GnssMeasurementsProvider mGnssMeasurementsProvider; 417 private final GnssNavigationMessageProvider mGnssNavigationMessageProvider; 418 private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener(); 419 private final LocationChangeListener mFusedLocationListener = new FusedLocationListener(); 420 private final NtpTimeHelper mNtpTimeHelper; 421 private final GnssBatchingProvider mGnssBatchingProvider; 422 private final GnssGeofenceProvider mGnssGeofenceProvider; 423 424 // Handler for processing events 425 private Handler mHandler; 426 427 /** It must be accessed only inside {@link #mHandler}. */ 428 private int mAGpsDataConnectionState; 429 /** It must be accessed only inside {@link #mHandler}. */ 430 private InetAddress mAGpsDataConnectionIpAddr; 431 432 private final ConnectivityManager mConnMgr; 433 private final GpsNetInitiatedHandler mNIHandler; 434 435 // Wakelocks 436 private final static String WAKELOCK_KEY = "GnssLocationProvider"; 437 private final PowerManager.WakeLock mWakeLock; 438 private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderXtraDownload"; 439 private final PowerManager.WakeLock mDownloadXtraWakeLock; 440 441 // Alarms 442 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP"; 443 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT"; 444 445 // SIM/Carrier info. 446 private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED"; 447 448 // Persist property for LPP_PROFILE 449 private final static String LPP_PROFILE = "persist.sys.gps.lpp"; 450 451 452 private final PowerManager mPowerManager; 453 private final AlarmManager mAlarmManager; 454 private final PendingIntent mWakeupIntent; 455 private final PendingIntent mTimeoutIntent; 456 457 private final AppOpsManager mAppOps; 458 private final IBatteryStats mBatteryStats; 459 460 // Current list of underlying location clients. 461 // only modified on handler thread 462 private WorkSource mClientSource = new WorkSource(); 463 464 private GeofenceHardwareImpl mGeofenceHardwareImpl; 465 466 // Volatile for simple inter-thread sync on these values. 467 private volatile int mHardwareYear = 0; 468 private volatile String mHardwareModelName; 469 470 // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL 471 // stops output right at 600m/s, depriving this of the information of a device that reaches 472 // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases. 473 private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F; 474 475 private volatile boolean mItarSpeedLimitExceeded = false; 476 477 // GNSS Metrics 478 private GnssMetrics mGnssMetrics; 479 480 private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() { 481 @Override 482 public void registerGnssStatusCallback(IGnssStatusListener callback) { 483 mListenerHelper.addListener(callback); 484 } 485 486 @Override 487 public void unregisterGnssStatusCallback(IGnssStatusListener callback) { 488 mListenerHelper.removeListener(callback); 489 } 490 }; 491 getGnssStatusProvider()492 public IGnssStatusProvider getGnssStatusProvider() { 493 return mGnssStatusProvider; 494 } 495 getGpsGeofenceProxy()496 public IGpsGeofenceHardware getGpsGeofenceProxy() { 497 return mGnssGeofenceProvider; 498 } 499 getGnssMeasurementsProvider()500 public GnssMeasurementsProvider getGnssMeasurementsProvider() { 501 return mGnssMeasurementsProvider; 502 } 503 getGnssNavigationMessageProvider()504 public GnssNavigationMessageProvider getGnssNavigationMessageProvider() { 505 return mGnssNavigationMessageProvider; 506 } 507 508 /** 509 * Callback used to listen for data connectivity changes. 510 */ 511 private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback = 512 new ConnectivityManager.NetworkCallback() { 513 @Override 514 public void onAvailable(Network network) { 515 mNtpTimeHelper.onNetworkAvailable(); 516 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) { 517 if (mSupportsXtra) { 518 // Download only if supported, (prevents an unneccesary on-boot 519 // download) 520 xtraDownloadRequest(); 521 } 522 } 523 // Always on, notify HAL so it can get data it needs 524 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network); 525 } 526 527 @Override 528 public void onLost(Network network) { 529 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network); 530 } 531 }; 532 533 /** 534 * Callback used to listen for availability of a requested SUPL connection. 535 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to 536 * manage the registration/un-registration lifetimes separate. 537 */ 538 private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback = 539 new ConnectivityManager.NetworkCallback() { 540 @Override 541 public void onAvailable(Network network) { 542 // Specific to a change to a SUPL enabled network becoming ready 543 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network); 544 } 545 546 @Override 547 public void onLost(Network network) { 548 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN); 549 } 550 }; 551 552 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 553 @Override 554 public void onReceive(Context context, Intent intent) { 555 String action = intent.getAction(); 556 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action); 557 if (action == null) { 558 return; 559 } 560 561 if (action.equals(ALARM_WAKEUP)) { 562 startNavigating(false); 563 } else if (action.equals(ALARM_TIMEOUT)) { 564 hibernate(); 565 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action) 566 || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action) 567 || Intent.ACTION_SCREEN_OFF.equals(action) 568 || Intent.ACTION_SCREEN_ON.equals(action)) { 569 updateLowPowerMode(); 570 } else if (action.equals(SIM_STATE_CHANGED)) { 571 subscriptionOrSimChanged(context); 572 } 573 } 574 }; 575 576 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = 577 new OnSubscriptionsChangedListener() { 578 @Override 579 public void onSubscriptionsChanged() { 580 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null); 581 } 582 }; 583 584 /** 585 * Implements {@link GnssSatelliteBlacklistCallback#onUpdateSatelliteBlacklist}. 586 */ 587 @Override onUpdateSatelliteBlacklist(int[] constellations, int[] svids)588 public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) { 589 mHandler.post(()->{ 590 native_set_satellite_blacklist(constellations, svids); 591 }); 592 } 593 subscriptionOrSimChanged(Context context)594 private void subscriptionOrSimChanged(Context context) { 595 if (DEBUG) Log.d(TAG, "received SIM related action: "); 596 TelephonyManager phone = (TelephonyManager) 597 mContext.getSystemService(Context.TELEPHONY_SERVICE); 598 CarrierConfigManager configManager = (CarrierConfigManager) 599 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 600 String mccMnc = phone.getSimOperator(); 601 boolean isKeepLppProfile = false; 602 if (!TextUtils.isEmpty(mccMnc)) { 603 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc); 604 synchronized (mLock) { 605 if (configManager != null) { 606 PersistableBundle b = configManager.getConfig(); 607 if (b != null) { 608 isKeepLppProfile = 609 b.getBoolean(CarrierConfigManager.KEY_PERSIST_LPP_MODE_BOOL); 610 } 611 } 612 if (isKeepLppProfile) { 613 // load current properties for the carrier 614 loadPropertiesFromResource(context, mProperties); 615 String lpp_profile = mProperties.getProperty("LPP_PROFILE"); 616 // set the persist property LPP_PROFILE for the value 617 if (lpp_profile != null) { 618 SystemProperties.set(LPP_PROFILE, lpp_profile); 619 } 620 } else { 621 // reset the persist property 622 SystemProperties.set(LPP_PROFILE, ""); 623 } 624 reloadGpsProperties(context, mProperties); 625 mNIHandler.setSuplEsEnabled(mSuplEsEnabled); 626 } 627 } else { 628 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available"); 629 } 630 } 631 updateLowPowerMode()632 private void updateLowPowerMode() { 633 // Disable GPS if we are in device idle mode. 634 boolean disableGps = mPowerManager.isDeviceIdleMode(); 635 final PowerSaveState result = 636 mPowerManager.getPowerSaveState(ServiceType.GPS); 637 switch (result.gpsMode) { 638 case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF: 639 // If we are in battery saver mode and the screen is off, disable GPS. 640 disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive(); 641 break; 642 } 643 if (disableGps != mDisableGps) { 644 mDisableGps = disableGps; 645 updateRequirements(); 646 } 647 } 648 isSupported()649 public static boolean isSupported() { 650 return native_is_supported(); 651 } 652 653 interface SetCarrierProperty { set(int value)654 public boolean set(int value); 655 } 656 reloadGpsProperties(Context context, Properties properties)657 private void reloadGpsProperties(Context context, Properties properties) { 658 if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size()); 659 loadPropertiesFromResource(context, properties); 660 661 String lpp_prof = SystemProperties.get(LPP_PROFILE); 662 if (!TextUtils.isEmpty(lpp_prof)) { 663 // override default value of this if lpp_prof is not empty 664 properties.setProperty("LPP_PROFILE", lpp_prof); 665 } 666 /* 667 * Overlay carrier properties from a debug configuration file. 668 */ 669 loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties); 670 // TODO: we should get rid of C2K specific setting. 671 setSuplHostPort(properties.getProperty("SUPL_HOST"), 672 properties.getProperty("SUPL_PORT")); 673 mC2KServerHost = properties.getProperty("C2K_HOST"); 674 String portString = properties.getProperty("C2K_PORT"); 675 if (mC2KServerHost != null && portString != null) { 676 try { 677 mC2KServerPort = Integer.parseInt(portString); 678 } catch (NumberFormatException e) { 679 Log.e(TAG, "unable to parse C2K_PORT: " + portString); 680 } 681 } 682 if (native_is_gnss_configuration_supported()) { 683 Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() { 684 { 685 put("SUPL_VER", (val) -> native_set_supl_version(val)); 686 put("SUPL_MODE", (val) -> native_set_supl_mode(val)); 687 put("SUPL_ES", (val) -> native_set_supl_es(val)); 688 put("LPP_PROFILE", (val) -> native_set_lpp_profile(val)); 689 put("A_GLONASS_POS_PROTOCOL_SELECT", 690 (val) -> native_set_gnss_pos_protocol_select(val)); 691 put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL", 692 (val) -> native_set_emergency_supl_pdn(val)); 693 put("GPS_LOCK", (val) -> native_set_gps_lock(val)); 694 } 695 }; 696 697 for (Entry<String, SetCarrierProperty> entry : map.entrySet()) { 698 String propertyName = entry.getKey(); 699 String propertyValueString = properties.getProperty(propertyName); 700 if (propertyValueString != null) { 701 try { 702 int propertyValueInt = Integer.decode(propertyValueString); 703 boolean result = entry.getValue().set(propertyValueInt); 704 if (result == false) { 705 Log.e(TAG, "Unable to set " + propertyName); 706 } 707 } catch (NumberFormatException e) { 708 Log.e(TAG, "unable to parse propertyName: " + propertyValueString); 709 } 710 } 711 } 712 } else if (DEBUG) { 713 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not" 714 + " supported"); 715 } 716 717 // SUPL_ES configuration. 718 String suplESProperty = mProperties.getProperty("SUPL_ES"); 719 if (suplESProperty != null) { 720 try { 721 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1); 722 } catch (NumberFormatException e) { 723 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty); 724 } 725 } 726 727 String emergencyExtensionSecondsString 728 = properties.getProperty("ES_EXTENSION_SEC", "0"); 729 try { 730 int emergencyExtensionSeconds = 731 Integer.parseInt(emergencyExtensionSecondsString); 732 mNIHandler.setEmergencyExtensionSeconds(emergencyExtensionSeconds); 733 } catch (NumberFormatException e) { 734 Log.e(TAG, "unable to parse ES_EXTENSION_SEC: " 735 + emergencyExtensionSecondsString); 736 } 737 } 738 loadPropertiesFromResource(Context context, Properties properties)739 private void loadPropertiesFromResource(Context context, 740 Properties properties) { 741 String[] configValues = context.getResources().getStringArray( 742 com.android.internal.R.array.config_gpsParameters); 743 for (String item : configValues) { 744 if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item); 745 // We need to support "KEY =", but not "=VALUE". 746 int index = item.indexOf("="); 747 if (index > 0 && index + 1 < item.length()) { 748 String key = item.substring(0, index); 749 String value = item.substring(index + 1); 750 properties.setProperty(key.trim().toUpperCase(), value); 751 } else { 752 Log.w(TAG, "malformed contents: " + item); 753 } 754 } 755 } 756 loadPropertiesFromFile(String filename, Properties properties)757 private boolean loadPropertiesFromFile(String filename, 758 Properties properties) { 759 try { 760 File file = new File(filename); 761 FileInputStream stream = null; 762 try { 763 stream = new FileInputStream(file); 764 properties.load(stream); 765 } finally { 766 IoUtils.closeQuietly(stream); 767 } 768 769 } catch (IOException e) { 770 if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename); 771 return false; 772 } 773 return true; 774 } 775 GnssLocationProvider(Context context, ILocationManager ilocationManager, Looper looper)776 public GnssLocationProvider(Context context, ILocationManager ilocationManager, 777 Looper looper) { 778 mContext = context; 779 mILocationManager = ilocationManager; 780 781 // Create a wake lock 782 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 783 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 784 mWakeLock.setReferenceCounted(true); 785 786 // Create a separate wake lock for xtra downloader as it may be released due to timeout. 787 mDownloadXtraWakeLock = mPowerManager.newWakeLock( 788 PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY); 789 mDownloadXtraWakeLock.setReferenceCounted(true); 790 791 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 792 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); 793 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); 794 795 mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 796 797 // App ops service to keep track of who is accessing the GPS 798 mAppOps = mContext.getSystemService(AppOpsManager.class); 799 800 // Battery statistics service to be notified when GPS turns on or off 801 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 802 BatteryStats.SERVICE_NAME)); 803 804 // Construct internal handler 805 mHandler = new ProviderHandler(looper); 806 807 // Load GPS configuration and register listeners in the background: 808 // some operations, such as opening files and registering broadcast receivers, can take a 809 // relative long time, so the ctor() is kept to create objects needed by this instance, 810 // while IO initialization and registration is delegated to our internal handler 811 // this approach is just fine because events are posted to our handler anyway 812 mProperties = new Properties(); 813 // Create a GPS net-initiated handler (also needed by handleInitialize) 814 mNIHandler = new GpsNetInitiatedHandler(context, 815 mNetInitiatedListener, 816 mSuplEsEnabled); 817 sendMessage(INITIALIZE_HANDLER, 0, null); 818 819 mListenerHelper = new GnssStatusListenerHelper(mHandler) { 820 @Override 821 protected boolean isAvailableInPlatform() { 822 return isSupported(); 823 } 824 825 @Override 826 protected boolean isGpsEnabled() { 827 return isEnabled(); 828 } 829 }; 830 831 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mContext, mHandler) { 832 @Override 833 protected boolean isGpsEnabled() { 834 return isEnabled(); 835 } 836 }; 837 838 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) { 839 @Override 840 protected boolean isGpsEnabled() { 841 return isEnabled(); 842 } 843 }; 844 mGnssMetrics = new GnssMetrics(mBatteryStats); 845 846 mNtpTimeHelper = new NtpTimeHelper(mContext, looper, this); 847 mGnssSatelliteBlacklistHelper = new GnssSatelliteBlacklistHelper(mContext, 848 looper, this); 849 mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist); 850 mGnssBatchingProvider = new GnssBatchingProvider(); 851 mGnssGeofenceProvider = new GnssGeofenceProvider(looper); 852 } 853 854 /** 855 * Returns the name of this provider. 856 */ 857 @Override getName()858 public String getName() { 859 return LocationManager.GPS_PROVIDER; 860 } 861 862 @Override getProperties()863 public ProviderProperties getProperties() { 864 return PROPERTIES; 865 } 866 867 868 /** 869 * Implements {@link InjectNtpTimeCallback#injectTime} 870 */ 871 @Override injectTime(long time, long timeReference, int uncertainty)872 public void injectTime(long time, long timeReference, int uncertainty) { 873 native_inject_time(time, timeReference, uncertainty); 874 } 875 handleUpdateNetworkState(Network network)876 private void handleUpdateNetworkState(Network network) { 877 // retrieve NetworkInfo for this UID 878 NetworkInfo info = mConnMgr.getNetworkInfo(network); 879 880 boolean networkAvailable = false; 881 boolean isConnected = false; 882 int type = ConnectivityManager.TYPE_NONE; 883 boolean isRoaming = false; 884 String apnName = null; 885 886 if (info != null) { 887 networkAvailable = info.isAvailable() && TelephonyManager.getDefault().getDataEnabled(); 888 isConnected = info.isConnected(); 889 type = info.getType(); 890 isRoaming = info.isRoaming(); 891 apnName = info.getExtraInfo(); 892 } 893 894 if (DEBUG) { 895 String message = String.format( 896 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S", 897 agpsDataConnStateAsString(), 898 isConnected, 899 info, 900 mConnMgr.getNetworkCapabilities(network)); 901 Log.d(TAG, message); 902 } 903 904 if (native_is_agps_ril_supported()) { 905 String defaultApn = getSelectedApn(); 906 if (defaultApn == null) { 907 defaultApn = "dummy-apn"; 908 } 909 910 native_update_network_state( 911 isConnected, 912 type, 913 isRoaming, 914 networkAvailable, 915 apnName, 916 defaultApn); 917 } else if (DEBUG) { 918 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported"); 919 } 920 921 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 922 if (isConnected) { 923 if (apnName == null) { 924 // assign a dummy value in the case of C2K as otherwise we will have a runtime 925 // exception in the following call to native_agps_data_conn_open 926 apnName = "dummy-apn"; 927 } 928 int apnIpType = getApnIpType(apnName); 929 setRouting(); 930 if (DEBUG) { 931 String message = String.format( 932 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", 933 apnName, 934 apnIpType); 935 Log.d(TAG, message); 936 } 937 native_agps_data_conn_open(apnName, apnIpType); 938 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 939 } else { 940 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); 941 } 942 } 943 } 944 handleRequestSuplConnection(InetAddress address)945 private void handleRequestSuplConnection(InetAddress address) { 946 if (DEBUG) { 947 String message = String.format( 948 "requestSuplConnection, state=%s, address=%s", 949 agpsDataConnStateAsString(), 950 address); 951 Log.d(TAG, message); 952 } 953 954 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 955 return; 956 } 957 mAGpsDataConnectionIpAddr = address; 958 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 959 960 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder(); 961 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); 962 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); 963 NetworkRequest request = requestBuilder.build(); 964 mConnMgr.requestNetwork( 965 request, 966 mSuplConnectivityCallback); 967 } 968 handleReleaseSuplConnection(int agpsDataConnStatus)969 private void handleReleaseSuplConnection(int agpsDataConnStatus) { 970 if (DEBUG) { 971 String message = String.format( 972 "releaseSuplConnection, state=%s, status=%s", 973 agpsDataConnStateAsString(), 974 agpsDataConnStatusAsString(agpsDataConnStatus)); 975 Log.d(TAG, message); 976 } 977 978 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) { 979 return; 980 } 981 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 982 983 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback); 984 switch (agpsDataConnStatus) { 985 case GPS_AGPS_DATA_CONN_FAILED: 986 native_agps_data_conn_failed(); 987 break; 988 case GPS_RELEASE_AGPS_DATA_CONN: 989 native_agps_data_conn_closed(); 990 break; 991 default: 992 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus); 993 } 994 } 995 handleRequestLocation(boolean independentFromGnss)996 private void handleRequestLocation(boolean independentFromGnss) { 997 if (isRequestLocationRateLimited()) { 998 if (DEBUG) { 999 Log.d(TAG, "RequestLocation is denied due to too frequent requests."); 1000 } 1001 return; 1002 } 1003 ContentResolver resolver = mContext.getContentResolver(); 1004 long durationMillis = Settings.Global.getLong( 1005 resolver, 1006 Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS, 1007 LOCATION_UPDATE_DURATION_MILLIS); 1008 if (durationMillis == 0) { 1009 Log.i(TAG, "GNSS HAL location request is disabled by Settings."); 1010 return; 1011 } 1012 1013 LocationManager locationManager = (LocationManager) mContext.getSystemService( 1014 Context.LOCATION_SERVICE); 1015 String provider; 1016 LocationChangeListener locationListener; 1017 1018 if (independentFromGnss) { 1019 // For fast GNSS TTFF 1020 provider = LocationManager.NETWORK_PROVIDER; 1021 locationListener = mNetworkLocationListener; 1022 } else { 1023 // For Device-Based Hybrid (E911) 1024 provider = LocationManager.FUSED_PROVIDER; 1025 locationListener = mFusedLocationListener; 1026 } 1027 1028 Log.i(TAG, 1029 String.format( 1030 "GNSS HAL Requesting location updates from %s provider for %d millis.", 1031 provider, durationMillis)); 1032 try { 1033 locationManager.requestLocationUpdates(provider, 1034 LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0, 1035 locationListener, mHandler.getLooper()); 1036 locationListener.numLocationUpdateRequest++; 1037 mHandler.postDelayed(() -> { 1038 if (--locationListener.numLocationUpdateRequest == 0) { 1039 Log.i(TAG, 1040 String.format("Removing location updates from %s provider.", provider)); 1041 locationManager.removeUpdates(locationListener); 1042 } 1043 }, durationMillis); 1044 } catch (IllegalArgumentException e) { 1045 Log.w(TAG, "Unable to request location.", e); 1046 } 1047 } 1048 injectBestLocation(Location location)1049 private void injectBestLocation(Location location) { 1050 int gnssLocationFlags = LOCATION_HAS_LAT_LONG | 1051 (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) | 1052 (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) | 1053 (location.hasBearing() ? LOCATION_HAS_BEARING : 0) | 1054 (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0) | 1055 (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0) | 1056 (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0) | 1057 (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0); 1058 1059 double latitudeDegrees = location.getLatitude(); 1060 double longitudeDegrees = location.getLongitude(); 1061 double altitudeMeters = location.getAltitude(); 1062 float speedMetersPerSec = location.getSpeed(); 1063 float bearingDegrees = location.getBearing(); 1064 float horizontalAccuracyMeters = location.getAccuracy(); 1065 float verticalAccuracyMeters = location.getVerticalAccuracyMeters(); 1066 float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond(); 1067 float bearingAccuracyDegrees = location.getBearingAccuracyDegrees(); 1068 long timestamp = location.getTime(); 1069 native_inject_best_location(gnssLocationFlags, latitudeDegrees, longitudeDegrees, 1070 altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters, 1071 verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees, 1072 timestamp); 1073 } 1074 1075 /** Returns true if the location request is too frequent. */ isRequestLocationRateLimited()1076 private boolean isRequestLocationRateLimited() { 1077 // TODO(b/73198123): implement exponential backoff. 1078 return false; 1079 } 1080 handleDownloadXtraData()1081 private void handleDownloadXtraData() { 1082 if (!mSupportsXtra) { 1083 // native code reports xtra not supported, don't try 1084 Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported"); 1085 return; 1086 } 1087 if (mDownloadXtraDataPending == STATE_DOWNLOADING) { 1088 // already downloading data 1089 return; 1090 } 1091 if (!isDataNetworkConnected()) { 1092 // try again when network is up 1093 mDownloadXtraDataPending = STATE_PENDING_NETWORK; 1094 return; 1095 } 1096 mDownloadXtraDataPending = STATE_DOWNLOADING; 1097 1098 // hold wake lock while task runs 1099 mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS); 1100 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()"); 1101 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 1102 @Override 1103 public void run() { 1104 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties); 1105 byte[] data = xtraDownloader.downloadXtraData(); 1106 if (data != null) { 1107 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data"); 1108 native_inject_xtra_data(data, data.length); 1109 mXtraBackOff.reset(); 1110 } 1111 1112 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); 1113 1114 if (data == null) { 1115 // try again later 1116 // since this is delayed and not urgent we do not hold a wake lock here 1117 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, 1118 mXtraBackOff.nextBackoffMillis()); 1119 } 1120 1121 // Release wake lock held by task, synchronize on mLock in case multiple 1122 // download tasks overrun. 1123 synchronized (mLock) { 1124 if (mDownloadXtraWakeLock.isHeld()) { 1125 // This wakelock may have time-out, if a timeout was specified. 1126 // Catch (and ignore) any timeout exceptions. 1127 try { 1128 mDownloadXtraWakeLock.release(); 1129 if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()"); 1130 } catch (Exception e) { 1131 Log.i(TAG, "Wakelock timeout & release race exception in " 1132 + "handleDownloadXtraData()", e); 1133 } 1134 } else { 1135 Log.e(TAG, "WakeLock expired before release in " 1136 + "handleDownloadXtraData()"); 1137 } 1138 } 1139 } 1140 }); 1141 } 1142 handleUpdateLocation(Location location)1143 private void handleUpdateLocation(Location location) { 1144 if (location.hasAccuracy()) { 1145 native_inject_location(location.getLatitude(), location.getLongitude(), 1146 location.getAccuracy()); 1147 } 1148 } 1149 1150 /** 1151 * Enables this provider. When enabled, calls to getStatus() 1152 * must be handled. Hardware may be started up 1153 * when the provider is enabled. 1154 */ 1155 @Override enable()1156 public void enable() { 1157 synchronized (mLock) { 1158 if (mEnabled) return; 1159 mEnabled = true; 1160 } 1161 1162 sendMessage(ENABLE, 1, null); 1163 } 1164 setSuplHostPort(String hostString, String portString)1165 private void setSuplHostPort(String hostString, String portString) { 1166 if (hostString != null) { 1167 mSuplServerHost = hostString; 1168 } 1169 if (portString != null) { 1170 try { 1171 mSuplServerPort = Integer.parseInt(portString); 1172 } catch (NumberFormatException e) { 1173 Log.e(TAG, "unable to parse SUPL_PORT: " + portString); 1174 } 1175 } 1176 if (mSuplServerHost != null 1177 && mSuplServerPort > TCP_MIN_PORT 1178 && mSuplServerPort <= TCP_MAX_PORT) { 1179 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 1180 } 1181 } 1182 1183 /** 1184 * Checks what SUPL mode to use, according to the AGPS mode as well as the 1185 * allowed mode from properties. 1186 * 1187 * @param properties GPS properties 1188 * @param agpsEnabled whether AGPS is enabled by settings value 1189 * @param singleShot whether "singleshot" is needed 1190 * @return SUPL mode (MSA vs MSB vs STANDALONE) 1191 */ getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot)1192 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) { 1193 if (agpsEnabled) { 1194 String modeString = properties.getProperty("SUPL_MODE"); 1195 int suplMode = 0; 1196 if (!TextUtils.isEmpty(modeString)) { 1197 try { 1198 suplMode = Integer.parseInt(modeString); 1199 } catch (NumberFormatException e) { 1200 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString); 1201 return GPS_POSITION_MODE_STANDALONE; 1202 } 1203 } 1204 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor 1205 // such mode when it is available 1206 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { 1207 return GPS_POSITION_MODE_MS_BASED; 1208 } 1209 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available, 1210 // do fallback only for single-shot requests, because it is too expensive to do for 1211 // periodic requests as well 1212 if (singleShot 1213 && hasCapability(GPS_CAPABILITY_MSA) 1214 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) { 1215 return GPS_POSITION_MODE_MS_ASSISTED; 1216 } 1217 } 1218 return GPS_POSITION_MODE_STANDALONE; 1219 } 1220 handleEnable()1221 private void handleEnable() { 1222 if (DEBUG) Log.d(TAG, "handleEnable"); 1223 1224 boolean enabled = native_init(); 1225 1226 if (enabled) { 1227 mSupportsXtra = native_supports_xtra(); 1228 1229 // TODO: remove the following native calls if we can make sure they are redundant. 1230 if (mSuplServerHost != null) { 1231 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 1232 } 1233 if (mC2KServerHost != null) { 1234 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); 1235 } 1236 1237 mGnssMeasurementsProvider.onGpsEnabledChanged(); 1238 mGnssNavigationMessageProvider.onGpsEnabledChanged(); 1239 mGnssBatchingProvider.enable(); 1240 } else { 1241 synchronized (mLock) { 1242 mEnabled = false; 1243 } 1244 Log.w(TAG, "Failed to enable location provider"); 1245 } 1246 } 1247 1248 /** 1249 * Disables this provider. When disabled, calls to getStatus() 1250 * need not be handled. Hardware may be shut 1251 * down while the provider is disabled. 1252 */ 1253 @Override disable()1254 public void disable() { 1255 synchronized (mLock) { 1256 if (!mEnabled) return; 1257 mEnabled = false; 1258 } 1259 1260 sendMessage(ENABLE, 0, null); 1261 } 1262 handleDisable()1263 private void handleDisable() { 1264 if (DEBUG) Log.d(TAG, "handleDisable"); 1265 1266 updateClientUids(new WorkSource()); 1267 stopNavigating(); 1268 mAlarmManager.cancel(mWakeupIntent); 1269 mAlarmManager.cancel(mTimeoutIntent); 1270 1271 mGnssBatchingProvider.disable(); 1272 // do this before releasing wakelock 1273 native_cleanup(); 1274 1275 mGnssMeasurementsProvider.onGpsEnabledChanged(); 1276 mGnssNavigationMessageProvider.onGpsEnabledChanged(); 1277 } 1278 1279 @Override isEnabled()1280 public boolean isEnabled() { 1281 synchronized (mLock) { 1282 return mEnabled; 1283 } 1284 } 1285 1286 @Override getStatus(Bundle extras)1287 public int getStatus(Bundle extras) { 1288 mLocationExtras.setBundle(extras); 1289 return mStatus; 1290 } 1291 updateStatus(int status)1292 private void updateStatus(int status) { 1293 if (status != mStatus) { 1294 mStatus = status; 1295 mStatusUpdateTime = SystemClock.elapsedRealtime(); 1296 } 1297 } 1298 1299 @Override getStatusUpdateTime()1300 public long getStatusUpdateTime() { 1301 return mStatusUpdateTime; 1302 } 1303 1304 @Override setRequest(ProviderRequest request, WorkSource source)1305 public void setRequest(ProviderRequest request, WorkSource source) { 1306 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source)); 1307 } 1308 handleSetRequest(ProviderRequest request, WorkSource source)1309 private void handleSetRequest(ProviderRequest request, WorkSource source) { 1310 mProviderRequest = request; 1311 mWorkSource = source; 1312 updateRequirements(); 1313 } 1314 1315 // Called when the requirements for GPS may have changed updateRequirements()1316 private void updateRequirements() { 1317 if (mProviderRequest == null || mWorkSource == null) { 1318 return; 1319 } 1320 1321 boolean singleShot = false; 1322 1323 // see if the request is for a single update 1324 if (mProviderRequest.locationRequests != null 1325 && mProviderRequest.locationRequests.size() > 0) { 1326 // if any request has zero or more than one updates 1327 // requested, then this is not single-shot mode 1328 singleShot = true; 1329 1330 for (LocationRequest lr : mProviderRequest.locationRequests) { 1331 if (lr.getNumUpdates() != 1) { 1332 singleShot = false; 1333 } 1334 } 1335 } 1336 1337 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest); 1338 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) { 1339 // update client uids 1340 updateClientUids(mWorkSource); 1341 1342 mFixInterval = (int) mProviderRequest.interval; 1343 mLowPowerMode = (boolean) mProviderRequest.lowPowerMode; 1344 // check for overflow 1345 if (mFixInterval != mProviderRequest.interval) { 1346 Log.w(TAG, "interval overflow: " + mProviderRequest.interval); 1347 mFixInterval = Integer.MAX_VALUE; 1348 } 1349 1350 // apply request to GPS engine 1351 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1352 // change period and/or lowPowerMode 1353 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1354 mFixInterval, 0, 0, mLowPowerMode)) { 1355 Log.e(TAG, "set_position_mode failed in updateRequirements"); 1356 } 1357 } else if (!mStarted) { 1358 // start GPS 1359 startNavigating(singleShot); 1360 } else { 1361 // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING 1362 mAlarmManager.cancel(mTimeoutIntent); 1363 if (mFixInterval >= NO_FIX_TIMEOUT) { 1364 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1365 // and our fix interval is not short 1366 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1367 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); } 1368 } 1369 } else { 1370 updateClientUids(new WorkSource()); 1371 1372 stopNavigating(); 1373 mAlarmManager.cancel(mWakeupIntent); 1374 mAlarmManager.cancel(mTimeoutIntent); 1375 } 1376 } 1377 updateClientUids(WorkSource source)1378 private void updateClientUids(WorkSource source) { 1379 if (source.equals(mClientSource)) { 1380 return; 1381 } 1382 1383 // (1) Inform BatteryStats that the list of IDs we're tracking changed. 1384 try { 1385 mBatteryStats.noteGpsChanged(mClientSource, source); 1386 } catch (RemoteException e) { 1387 Log.w(TAG, "RemoteException", e); 1388 } 1389 1390 // (2) Inform AppOps service about the list of changes to UIDs. 1391 1392 List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source); 1393 if (diffs != null) { 1394 List<WorkChain> newChains = diffs[0]; 1395 List<WorkChain> goneChains = diffs[1]; 1396 1397 if (newChains != null) { 1398 for (int i = 0; i < newChains.size(); ++i) { 1399 final WorkChain newChain = newChains.get(i); 1400 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(), 1401 newChain.getAttributionTag()); 1402 } 1403 } 1404 1405 if (goneChains != null) { 1406 for (int i = 0; i < goneChains.size(); i++) { 1407 final WorkChain goneChain = goneChains.get(i); 1408 mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(), 1409 goneChain.getAttributionTag()); 1410 } 1411 } 1412 1413 mClientSource.transferWorkChains(source); 1414 } 1415 1416 // Update the flat UIDs and names list and inform app-ops of all changes. 1417 WorkSource[] changes = mClientSource.setReturningDiffs(source); 1418 if (changes != null) { 1419 WorkSource newWork = changes[0]; 1420 WorkSource goneWork = changes[1]; 1421 1422 // Update sources that were not previously tracked. 1423 if (newWork != null) { 1424 for (int i = 0; i < newWork.size(); i++) { 1425 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, 1426 newWork.get(i), newWork.getName(i)); 1427 } 1428 } 1429 1430 // Update sources that are no longer tracked. 1431 if (goneWork != null) { 1432 for (int i = 0; i < goneWork.size(); i++) { 1433 mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i)); 1434 } 1435 } 1436 } 1437 } 1438 1439 @Override sendExtraCommand(String command, Bundle extras)1440 public boolean sendExtraCommand(String command, Bundle extras) { 1441 1442 long identity = Binder.clearCallingIdentity(); 1443 try { 1444 boolean result = false; 1445 1446 if ("delete_aiding_data".equals(command)) { 1447 result = deleteAidingData(extras); 1448 } else if ("force_time_injection".equals(command)) { 1449 requestUtcTime(); 1450 result = true; 1451 } else if ("force_xtra_injection".equals(command)) { 1452 if (mSupportsXtra) { 1453 xtraDownloadRequest(); 1454 result = true; 1455 } 1456 } else { 1457 Log.w(TAG, "sendExtraCommand: unknown command " + command); 1458 } 1459 return result; 1460 } finally { 1461 Binder.restoreCallingIdentity(identity); 1462 } 1463 } 1464 deleteAidingData(Bundle extras)1465 private boolean deleteAidingData(Bundle extras) { 1466 int flags; 1467 1468 if (extras == null) { 1469 flags = GPS_DELETE_ALL; 1470 } else { 1471 flags = 0; 1472 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; 1473 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; 1474 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; 1475 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; 1476 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; 1477 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; 1478 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; 1479 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; 1480 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; 1481 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; 1482 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; 1483 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; 1484 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; 1485 } 1486 1487 if (flags != 0) { 1488 native_delete_aiding_data(flags); 1489 return true; 1490 } 1491 1492 return false; 1493 } 1494 startNavigating(boolean singleShot)1495 private void startNavigating(boolean singleShot) { 1496 if (!mStarted) { 1497 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot); 1498 mTimeToFirstFix = 0; 1499 mLastFixTime = 0; 1500 mStarted = true; 1501 mSingleShot = singleShot; 1502 mPositionMode = GPS_POSITION_MODE_STANDALONE; 1503 // Notify about suppressed output, if speed limit was previously exceeded. 1504 // Elsewhere, we check again with every speed output reported. 1505 if (mItarSpeedLimitExceeded) { 1506 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited " + 1507 "until slow enough speed reported."); 1508 } 1509 1510 boolean agpsEnabled = 1511 (Settings.Global.getInt(mContext.getContentResolver(), 1512 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0); 1513 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot); 1514 1515 if (DEBUG) { 1516 String mode; 1517 1518 switch (mPositionMode) { 1519 case GPS_POSITION_MODE_STANDALONE: 1520 mode = "standalone"; 1521 break; 1522 case GPS_POSITION_MODE_MS_ASSISTED: 1523 mode = "MS_ASSISTED"; 1524 break; 1525 case GPS_POSITION_MODE_MS_BASED: 1526 mode = "MS_BASED"; 1527 break; 1528 default: 1529 mode = "unknown"; 1530 break; 1531 } 1532 Log.d(TAG, "setting position_mode to " + mode); 1533 } 1534 1535 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); 1536 mLowPowerMode = (boolean) mProviderRequest.lowPowerMode; 1537 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1538 interval, 0, 0, mLowPowerMode)) { 1539 mStarted = false; 1540 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1541 return; 1542 } 1543 if (!native_start()) { 1544 mStarted = false; 1545 Log.e(TAG, "native_start failed in startNavigating()"); 1546 return; 1547 } 1548 1549 // reset SV count to zero 1550 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE); 1551 mLocationExtras.reset(); 1552 mFixRequestTime = SystemClock.elapsedRealtime(); 1553 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1554 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1555 // and our fix interval is not short 1556 if (mFixInterval >= NO_FIX_TIMEOUT) { 1557 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1558 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); 1559 } 1560 } 1561 } 1562 } 1563 stopNavigating()1564 private void stopNavigating() { 1565 if (DEBUG) Log.d(TAG, "stopNavigating"); 1566 if (mStarted) { 1567 mStarted = false; 1568 mSingleShot = false; 1569 native_stop(); 1570 mLastFixTime = 0; 1571 1572 // reset SV count to zero 1573 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE); 1574 mLocationExtras.reset(); 1575 } 1576 } 1577 hibernate()1578 private void hibernate() { 1579 // stop GPS until our next fix interval arrives 1580 stopNavigating(); 1581 mAlarmManager.cancel(mTimeoutIntent); 1582 mAlarmManager.cancel(mWakeupIntent); 1583 long now = SystemClock.elapsedRealtime(); 1584 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent); 1585 } 1586 hasCapability(int capability)1587 private boolean hasCapability(int capability) { 1588 return ((mEngineCapabilities & capability) != 0); 1589 } 1590 1591 1592 /** 1593 * called from native code to update our position. 1594 */ reportLocation(boolean hasLatLong, Location location)1595 private void reportLocation(boolean hasLatLong, Location location) { 1596 sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location); 1597 } 1598 handleReportLocation(boolean hasLatLong, Location location)1599 private void handleReportLocation(boolean hasLatLong, Location location) { 1600 if (location.hasSpeed()) { 1601 mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND; 1602 } 1603 1604 if (mItarSpeedLimitExceeded) { 1605 Log.i(TAG, "Hal reported a speed in excess of ITAR limit." + 1606 " GPS/GNSS Navigation output blocked."); 1607 if (mStarted) { 1608 mGnssMetrics.logReceivedLocationStatus(false); 1609 } 1610 return; // No output of location allowed 1611 } 1612 1613 if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString()); 1614 1615 // It would be nice to push the elapsed real-time timestamp 1616 // further down the stack, but this is still useful 1617 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1618 location.setExtras(mLocationExtras.getBundle()); 1619 1620 try { 1621 mILocationManager.reportLocation(location, false); 1622 } catch (RemoteException e) { 1623 Log.e(TAG, "RemoteException calling reportLocation"); 1624 } 1625 1626 if (mStarted) { 1627 mGnssMetrics.logReceivedLocationStatus(hasLatLong); 1628 if (hasLatLong) { 1629 if (location.hasAccuracy()) { 1630 mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy()); 1631 } 1632 if (mTimeToFirstFix > 0) { 1633 int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime); 1634 mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes); 1635 } 1636 } 1637 } 1638 1639 mLastFixTime = SystemClock.elapsedRealtime(); 1640 // report time to first fix 1641 if (mTimeToFirstFix == 0 && hasLatLong) { 1642 mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime); 1643 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1644 if (mStarted) { 1645 mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix); 1646 } 1647 1648 // notify status listeners 1649 mListenerHelper.onFirstFix(mTimeToFirstFix); 1650 } 1651 1652 if (mSingleShot) { 1653 stopNavigating(); 1654 } 1655 1656 if (mStarted && mStatus != LocationProvider.AVAILABLE) { 1657 // For devices that use framework scheduling, a timer may be set to ensure we don't 1658 // spend too much power searching for a location, when the requested update rate is slow. 1659 // As we just recievied a location, we'll cancel that timer. 1660 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { 1661 mAlarmManager.cancel(mTimeoutIntent); 1662 } 1663 1664 // send an intent to notify that the GPS is receiving fixes. 1665 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1666 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); 1667 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1668 updateStatus(LocationProvider.AVAILABLE); 1669 } 1670 1671 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && 1672 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1673 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1674 hibernate(); 1675 } 1676 } 1677 1678 /** 1679 * called from native code to update our status 1680 */ reportStatus(int status)1681 private void reportStatus(int status) { 1682 if (DEBUG) Log.v(TAG, "reportStatus status: " + status); 1683 1684 boolean wasNavigating = mNavigating; 1685 switch (status) { 1686 case GPS_STATUS_SESSION_BEGIN: 1687 mNavigating = true; 1688 mEngineOn = true; 1689 break; 1690 case GPS_STATUS_SESSION_END: 1691 mNavigating = false; 1692 break; 1693 case GPS_STATUS_ENGINE_ON: 1694 mEngineOn = true; 1695 break; 1696 case GPS_STATUS_ENGINE_OFF: 1697 mEngineOn = false; 1698 mNavigating = false; 1699 break; 1700 } 1701 1702 if (wasNavigating != mNavigating) { 1703 mListenerHelper.onStatusChanged(mNavigating); 1704 1705 // send an intent to notify that the GPS has been enabled or disabled 1706 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION); 1707 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating); 1708 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1709 } 1710 } 1711 1712 // Helper class to carry data to handler for reportSvStatus 1713 private static class SvStatusInfo { 1714 public int mSvCount; 1715 public int[] mSvidWithFlags; 1716 public float[] mCn0s; 1717 public float[] mSvElevations; 1718 public float[] mSvAzimuths; 1719 public float[] mSvCarrierFreqs; 1720 } 1721 1722 /** 1723 * called from native code to update SV info 1724 */ reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs)1725 private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s, 1726 float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) { 1727 SvStatusInfo svStatusInfo = new SvStatusInfo(); 1728 svStatusInfo.mSvCount = svCount; 1729 svStatusInfo.mSvidWithFlags = svidWithFlags; 1730 svStatusInfo.mCn0s = cn0s; 1731 svStatusInfo.mSvElevations = svElevations; 1732 svStatusInfo.mSvAzimuths = svAzimuths; 1733 svStatusInfo.mSvCarrierFreqs = svCarrierFreqs; 1734 1735 sendMessage(REPORT_SV_STATUS, 0, svStatusInfo); 1736 } 1737 handleReportSvStatus(SvStatusInfo info)1738 private void handleReportSvStatus(SvStatusInfo info) { 1739 mListenerHelper.onSvStatusChanged( 1740 info.mSvCount, 1741 info.mSvidWithFlags, 1742 info.mCn0s, 1743 info.mSvElevations, 1744 info.mSvAzimuths, 1745 info.mSvCarrierFreqs); 1746 1747 // Log CN0 as part of GNSS metrics 1748 mGnssMetrics.logCn0(info.mCn0s, info.mSvCount); 1749 1750 if (VERBOSE) { 1751 Log.v(TAG, "SV count: " + info.mSvCount); 1752 } 1753 // Calculate number of satellites used in fix. 1754 int usedInFixCount = 0; 1755 int maxCn0 = 0; 1756 int meanCn0 = 0; 1757 for (int i = 0; i < info.mSvCount; i++) { 1758 if ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) { 1759 ++usedInFixCount; 1760 if (info.mCn0s[i] > maxCn0) { 1761 maxCn0 = (int) info.mCn0s[i]; 1762 } 1763 meanCn0 += info.mCn0s[i]; 1764 } 1765 if (VERBOSE) { 1766 Log.v(TAG, "svid: " + (info.mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) + 1767 " cn0: " + info.mCn0s[i] + 1768 " elev: " + info.mSvElevations[i] + 1769 " azimuth: " + info.mSvAzimuths[i] + 1770 " carrier frequency: " + info.mSvCarrierFreqs[i] + 1771 ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0 1772 ? " " : " E") + 1773 ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0 1774 ? " " : " A") + 1775 ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0 1776 ? "" : "U") + 1777 ((info.mSvidWithFlags[i] & 1778 GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0 1779 ? "" : "F")); 1780 } 1781 } 1782 if (usedInFixCount > 0) { 1783 meanCn0 /= usedInFixCount; 1784 } 1785 // return number of sats used in fix instead of total reported 1786 mLocationExtras.set(usedInFixCount, meanCn0, maxCn0); 1787 1788 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && 1789 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) { 1790 // send an intent to notify that the GPS is no longer receiving fixes. 1791 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1792 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false); 1793 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1794 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE); 1795 } 1796 } 1797 1798 /** 1799 * called from native code to update AGPS status 1800 */ reportAGpsStatus(int type, int status, byte[] ipaddr)1801 private void reportAGpsStatus(int type, int status, byte[] ipaddr) { 1802 switch (status) { 1803 case GPS_REQUEST_AGPS_DATA_CONN: 1804 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); 1805 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr)); 1806 InetAddress connectionIpAddress = null; 1807 if (ipaddr != null) { 1808 try { 1809 connectionIpAddress = InetAddress.getByAddress(ipaddr); 1810 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress); 1811 } catch (UnknownHostException e) { 1812 Log.e(TAG, "Bad IP Address: " + ipaddr, e); 1813 } 1814 } 1815 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress); 1816 break; 1817 case GPS_RELEASE_AGPS_DATA_CONN: 1818 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); 1819 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN); 1820 break; 1821 case GPS_AGPS_DATA_CONNECTED: 1822 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1823 break; 1824 case GPS_AGPS_DATA_CONN_DONE: 1825 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1826 break; 1827 case GPS_AGPS_DATA_CONN_FAILED: 1828 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1829 break; 1830 default: 1831 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status); 1832 } 1833 } 1834 releaseSuplConnection(int connStatus)1835 private void releaseSuplConnection(int connStatus) { 1836 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/); 1837 } 1838 1839 /** 1840 * called from native code to report NMEA data received 1841 */ reportNmea(long timestamp)1842 private void reportNmea(long timestamp) { 1843 if (!mItarSpeedLimitExceeded) { 1844 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); 1845 String nmea = new String(mNmeaBuffer, 0 /* offset */, length); 1846 mListenerHelper.onNmeaReceived(timestamp, nmea); 1847 } 1848 } 1849 1850 /** 1851 * called from native code - GNSS measurements callback 1852 */ reportMeasurementData(GnssMeasurementsEvent event)1853 private void reportMeasurementData(GnssMeasurementsEvent event) { 1854 if (!mItarSpeedLimitExceeded) { 1855 // send to handler to allow native to return quickly 1856 mHandler.post(new Runnable() { 1857 @Override 1858 public void run() { 1859 mGnssMeasurementsProvider.onMeasurementsAvailable(event); 1860 } 1861 }); 1862 } 1863 } 1864 1865 /** 1866 * called from native code - GNSS navigation message callback 1867 */ reportNavigationMessage(GnssNavigationMessage event)1868 private void reportNavigationMessage(GnssNavigationMessage event) { 1869 if (!mItarSpeedLimitExceeded) { 1870 // send to handler to allow native to return quickly 1871 mHandler.post(new Runnable() { 1872 @Override 1873 public void run() { 1874 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event); 1875 } 1876 }); 1877 } 1878 } 1879 1880 /** 1881 * called from native code to inform us what the GPS engine capabilities are 1882 */ setEngineCapabilities(final int capabilities)1883 private void setEngineCapabilities(final int capabilities) { 1884 // send to handler thread for fast native return, and in-order handling 1885 mHandler.post(new Runnable() { 1886 @Override 1887 public void run() { 1888 mEngineCapabilities = capabilities; 1889 1890 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { 1891 mNtpTimeHelper.enablePeriodicTimeInjection(); 1892 requestUtcTime(); 1893 } 1894 1895 mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability( 1896 GPS_CAPABILITY_MEASUREMENTS)); 1897 mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability( 1898 GPS_CAPABILITY_NAV_MESSAGES)); 1899 restartRequests(); 1900 } 1901 }); 1902 } 1903 restartRequests()1904 private void restartRequests() { 1905 Log.i(TAG, "restartRequests"); 1906 1907 restartLocationRequest(); 1908 mGnssMeasurementsProvider.resumeIfStarted(); 1909 mGnssNavigationMessageProvider.resumeIfStarted(); 1910 mGnssBatchingProvider.resumeIfStarted(); 1911 mGnssGeofenceProvider.resumeIfStarted(); 1912 } 1913 restartLocationRequest()1914 private void restartLocationRequest() { 1915 if (DEBUG) Log.d(TAG, "restartLocationRequest"); 1916 mStarted = false; 1917 updateRequirements(); 1918 } 1919 1920 /** 1921 * Called from native code to inform us the hardware year. 1922 */ setGnssYearOfHardware(final int yearOfHardware)1923 private void setGnssYearOfHardware(final int yearOfHardware) { 1924 // mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync 1925 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware); 1926 mHardwareYear = yearOfHardware; 1927 } 1928 1929 /** 1930 * Called from native code to inform us the hardware model name. 1931 */ setGnssHardwareModelName(final String modelName)1932 private void setGnssHardwareModelName(final String modelName) { 1933 // mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync 1934 if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName); 1935 mHardwareModelName = modelName; 1936 } 1937 1938 /** 1939 * Called from native code to inform us GNSS HAL service died. 1940 */ reportGnssServiceDied()1941 private void reportGnssServiceDied() { 1942 if (DEBUG) Log.d(TAG, "reportGnssServiceDied"); 1943 mHandler.post(() -> { 1944 class_init_native(); 1945 native_init_once(); 1946 if (isEnabled()) { 1947 // re-calls native_init() and other setup. 1948 handleEnable(); 1949 // resend configuration into the restarted HAL service. 1950 reloadGpsProperties(mContext, mProperties); 1951 } 1952 }); 1953 } 1954 1955 public interface GnssSystemInfoProvider { 1956 /** 1957 * Returns the year of underlying GPS hardware. 1958 */ getGnssYearOfHardware()1959 int getGnssYearOfHardware(); 1960 /** 1961 * Returns the model name of underlying GPS hardware. 1962 */ getGnssHardwareModelName()1963 String getGnssHardwareModelName(); 1964 } 1965 1966 /** 1967 * @hide 1968 */ getGnssSystemInfoProvider()1969 public GnssSystemInfoProvider getGnssSystemInfoProvider() { 1970 return new GnssSystemInfoProvider() { 1971 @Override 1972 public int getGnssYearOfHardware() { 1973 return mHardwareYear; 1974 } 1975 @Override 1976 public String getGnssHardwareModelName() { 1977 return mHardwareModelName; 1978 } 1979 }; 1980 } 1981 1982 /** 1983 * @hide 1984 */ 1985 public GnssBatchingProvider getGnssBatchingProvider() { 1986 return mGnssBatchingProvider; 1987 } 1988 1989 public interface GnssMetricsProvider { 1990 /** 1991 * Returns GNSS metrics as proto string 1992 */ 1993 String getGnssMetricsAsProtoString(); 1994 } 1995 1996 /** 1997 * @hide 1998 */ 1999 public GnssMetricsProvider getGnssMetricsProvider() { 2000 return new GnssMetricsProvider() { 2001 @Override 2002 public String getGnssMetricsAsProtoString() { 2003 return mGnssMetrics.dumpGnssMetricsAsProtoString(); 2004 } 2005 }; 2006 } 2007 2008 /** 2009 * called from native code - GNSS location batch callback 2010 */ 2011 private void reportLocationBatch(Location[] locationArray) { 2012 List<Location> locations = new ArrayList<>(Arrays.asList(locationArray)); 2013 if (DEBUG) { 2014 Log.d(TAG, "Location batch of size " + locationArray.length + " reported"); 2015 } 2016 try { 2017 mILocationManager.reportLocationBatch(locations); 2018 } catch (RemoteException e) { 2019 Log.e(TAG, "RemoteException calling reportLocationBatch"); 2020 } 2021 } 2022 2023 /** 2024 * called from native code to request XTRA data 2025 */ 2026 private void xtraDownloadRequest() { 2027 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 2028 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 2029 } 2030 2031 /** 2032 * Converts the GPS HAL status to the internal Geofence Hardware status. 2033 */ 2034 private int getGeofenceStatus(int status) { 2035 switch (status) { 2036 case GPS_GEOFENCE_OPERATION_SUCCESS: 2037 return GeofenceHardware.GEOFENCE_SUCCESS; 2038 case GPS_GEOFENCE_ERROR_GENERIC: 2039 return GeofenceHardware.GEOFENCE_FAILURE; 2040 case GPS_GEOFENCE_ERROR_ID_EXISTS: 2041 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 2042 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: 2043 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 2044 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: 2045 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 2046 case GPS_GEOFENCE_ERROR_ID_UNKNOWN: 2047 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 2048 default: 2049 return -1; 2050 } 2051 } 2052 2053 /** 2054 * Called from native to report GPS Geofence transition 2055 * All geofence callbacks are called on the same thread 2056 */ 2057 private void reportGeofenceTransition(int geofenceId, Location location, int transition, 2058 long transitionTimestamp) { 2059 if (mGeofenceHardwareImpl == null) { 2060 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2061 } 2062 2063 mGeofenceHardwareImpl.reportGeofenceTransition( 2064 geofenceId, 2065 location, 2066 transition, 2067 transitionTimestamp, 2068 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 2069 FusedBatchOptions.SourceTechnologies.GNSS); 2070 } 2071 2072 /** 2073 * called from native code to report GPS status change. 2074 */ 2075 private void reportGeofenceStatus(int status, Location location) { 2076 if (mGeofenceHardwareImpl == null) { 2077 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2078 } 2079 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 2080 if (status == GPS_GEOFENCE_AVAILABLE) { 2081 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 2082 } 2083 mGeofenceHardwareImpl.reportGeofenceMonitorStatus( 2084 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 2085 monitorStatus, 2086 location, 2087 FusedBatchOptions.SourceTechnologies.GNSS); 2088 } 2089 2090 /** 2091 * called from native code - Geofence Add callback 2092 */ 2093 private void reportGeofenceAddStatus(int geofenceId, int status) { 2094 if (mGeofenceHardwareImpl == null) { 2095 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2096 } 2097 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); 2098 } 2099 2100 /** 2101 * called from native code - Geofence Remove callback 2102 */ 2103 private void reportGeofenceRemoveStatus(int geofenceId, int status) { 2104 if (mGeofenceHardwareImpl == null) { 2105 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2106 } 2107 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); 2108 } 2109 2110 /** 2111 * called from native code - Geofence Pause callback 2112 */ 2113 private void reportGeofencePauseStatus(int geofenceId, int status) { 2114 if (mGeofenceHardwareImpl == null) { 2115 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2116 } 2117 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); 2118 } 2119 2120 /** 2121 * called from native code - Geofence Resume callback 2122 */ 2123 private void reportGeofenceResumeStatus(int geofenceId, int status) { 2124 if (mGeofenceHardwareImpl == null) { 2125 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2126 } 2127 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); 2128 } 2129 2130 //============================================================= 2131 // NI Client support 2132 //============================================================= 2133 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 2134 // Sends a response for an NI request to HAL. 2135 @Override 2136 public boolean sendNiResponse(int notificationId, int userResponse) { 2137 // TODO Add Permission check 2138 2139 if (DEBUG) { 2140 Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 2141 ", response: " + userResponse); 2142 } 2143 native_send_ni_response(notificationId, userResponse); 2144 return true; 2145 } 2146 }; 2147 2148 public INetInitiatedListener getNetInitiatedListener() { 2149 return mNetInitiatedListener; 2150 } 2151 2152 // Called by JNI function to report an NI request. 2153 public void reportNiNotification( 2154 int notificationId, 2155 int niType, 2156 int notifyFlags, 2157 int timeout, 2158 int defaultResponse, 2159 String requestorId, 2160 String text, 2161 int requestorIdEncoding, 2162 int textEncoding 2163 ) { 2164 Log.i(TAG, "reportNiNotification: entered"); 2165 Log.i(TAG, "notificationId: " + notificationId + 2166 ", niType: " + niType + 2167 ", notifyFlags: " + notifyFlags + 2168 ", timeout: " + timeout + 2169 ", defaultResponse: " + defaultResponse); 2170 2171 Log.i(TAG, "requestorId: " + requestorId + 2172 ", text: " + text + 2173 ", requestorIdEncoding: " + requestorIdEncoding + 2174 ", textEncoding: " + textEncoding); 2175 2176 GpsNiNotification notification = new GpsNiNotification(); 2177 2178 notification.notificationId = notificationId; 2179 notification.niType = niType; 2180 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 2181 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 2182 notification.privacyOverride = 2183 (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 2184 notification.timeout = timeout; 2185 notification.defaultResponse = defaultResponse; 2186 notification.requestorId = requestorId; 2187 notification.text = text; 2188 notification.requestorIdEncoding = requestorIdEncoding; 2189 notification.textEncoding = textEncoding; 2190 2191 mNIHandler.handleNiNotification(notification); 2192 } 2193 2194 /** 2195 * Called from native code to request set id info. 2196 * We should be careful about receiving null string from the TelephonyManager, 2197 * because sending null String to JNI function would cause a crash. 2198 */ 2199 2200 private void requestSetID(int flags) { 2201 TelephonyManager phone = (TelephonyManager) 2202 mContext.getSystemService(Context.TELEPHONY_SERVICE); 2203 int type = AGPS_SETID_TYPE_NONE; 2204 String data = ""; 2205 2206 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { 2207 String data_temp = phone.getSubscriberId(); 2208 if (data_temp == null) { 2209 // This means the framework does not have the SIM card ready. 2210 } else { 2211 // This means the framework has the SIM card. 2212 data = data_temp; 2213 type = AGPS_SETID_TYPE_IMSI; 2214 } 2215 } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { 2216 String data_temp = phone.getLine1Number(); 2217 if (data_temp == null) { 2218 // This means the framework does not have the SIM card ready. 2219 } else { 2220 // This means the framework has the SIM card. 2221 data = data_temp; 2222 type = AGPS_SETID_TYPE_MSISDN; 2223 } 2224 } 2225 native_agps_set_id(type, data); 2226 } 2227 2228 /** 2229 * Called from native code to request location info. 2230 */ 2231 private void requestLocation(boolean independentFromGnss) { 2232 if (DEBUG) { 2233 Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss); 2234 } 2235 sendMessage(REQUEST_LOCATION, 0, independentFromGnss); 2236 } 2237 2238 /** 2239 * Called from native code to request utc time info 2240 */ 2241 private void requestUtcTime() { 2242 if (DEBUG) Log.d(TAG, "utcTimeRequest"); 2243 sendMessage(INJECT_NTP_TIME, 0, null); 2244 } 2245 2246 /** 2247 * Called from native code to request reference location info 2248 */ 2249 private void requestRefLocation() { 2250 TelephonyManager phone = (TelephonyManager) 2251 mContext.getSystemService(Context.TELEPHONY_SERVICE); 2252 final int phoneType = phone.getPhoneType(); 2253 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 2254 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); 2255 if ((gsm_cell != null) && (phone.getNetworkOperator() != null) 2256 && (phone.getNetworkOperator().length() > 3)) { 2257 int type; 2258 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0, 3)); 2259 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); 2260 int networkType = phone.getNetworkType(); 2261 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS 2262 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA 2263 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA 2264 || networkType == TelephonyManager.NETWORK_TYPE_HSPA 2265 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) { 2266 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 2267 } else { 2268 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 2269 } 2270 native_agps_set_ref_location_cellid(type, mcc, mnc, 2271 gsm_cell.getLac(), gsm_cell.getCid()); 2272 } else { 2273 Log.e(TAG, "Error getting cell location info."); 2274 } 2275 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 2276 Log.e(TAG, "CDMA not supported."); 2277 } 2278 } 2279 2280 private void sendMessage(int message, int arg, Object obj) { 2281 // hold a wake lock until this message is delivered 2282 // note that this assumes the message will not be removed from the queue before 2283 // it is handled (otherwise the wake lock would be leaked). 2284 mWakeLock.acquire(); 2285 if (Log.isLoggable(TAG, Log.INFO)) { 2286 Log.i(TAG, "WakeLock acquired by sendMessage(" + messageIdAsString(message) + ", " + arg 2287 + ", " + obj + ")"); 2288 } 2289 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget(); 2290 } 2291 2292 private final class ProviderHandler extends Handler { 2293 public ProviderHandler(Looper looper) { 2294 super(looper, null, true /*async*/); 2295 } 2296 2297 @Override 2298 public void handleMessage(Message msg) { 2299 int message = msg.what; 2300 switch (message) { 2301 case ENABLE: 2302 if (msg.arg1 == 1) { 2303 handleEnable(); 2304 } else { 2305 handleDisable(); 2306 } 2307 break; 2308 case SET_REQUEST: 2309 GpsRequest gpsRequest = (GpsRequest) msg.obj; 2310 handleSetRequest(gpsRequest.request, gpsRequest.source); 2311 break; 2312 case UPDATE_NETWORK_STATE: 2313 handleUpdateNetworkState((Network) msg.obj); 2314 break; 2315 case REQUEST_SUPL_CONNECTION: 2316 handleRequestSuplConnection((InetAddress) msg.obj); 2317 break; 2318 case RELEASE_SUPL_CONNECTION: 2319 handleReleaseSuplConnection(msg.arg1); 2320 break; 2321 case INJECT_NTP_TIME: 2322 mNtpTimeHelper.retrieveAndInjectNtpTime(); 2323 break; 2324 case REQUEST_LOCATION: 2325 handleRequestLocation((boolean) msg.obj); 2326 break; 2327 case DOWNLOAD_XTRA_DATA: 2328 handleDownloadXtraData(); 2329 break; 2330 case DOWNLOAD_XTRA_DATA_FINISHED: 2331 mDownloadXtraDataPending = STATE_IDLE; 2332 break; 2333 case UPDATE_LOCATION: 2334 handleUpdateLocation((Location) msg.obj); 2335 break; 2336 case SUBSCRIPTION_OR_SIM_CHANGED: 2337 subscriptionOrSimChanged(mContext); 2338 break; 2339 case INITIALIZE_HANDLER: 2340 handleInitialize(); 2341 break; 2342 case REPORT_LOCATION: 2343 handleReportLocation(msg.arg1 == 1, (Location) msg.obj); 2344 break; 2345 case REPORT_SV_STATUS: 2346 handleReportSvStatus((SvStatusInfo) msg.obj); 2347 break; 2348 } 2349 if (msg.arg2 == 1) { 2350 // wakelock was taken for this message, release it 2351 mWakeLock.release(); 2352 if (Log.isLoggable(TAG, Log.INFO)) { 2353 Log.i(TAG, "WakeLock released by handleMessage(" + messageIdAsString(message) 2354 + ", " + msg.arg1 + ", " + msg.obj + ")"); 2355 } 2356 } 2357 } 2358 2359 /** 2360 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}. 2361 * It is in charge of loading properties and registering for events that will be posted to 2362 * this handler. 2363 */ 2364 private void handleInitialize() { 2365 native_init_once(); 2366 2367 /* 2368 * A cycle of native_init() and native_cleanup() is needed so that callbacks are 2369 * registered after bootup even when location is disabled. 2370 * This will allow Emergency SUPL to work even when location is disabled before device 2371 * restart. 2372 */ 2373 boolean isInitialized = native_init(); 2374 if (!isInitialized) { 2375 Log.w(TAG, "Native initialization failed at bootup"); 2376 } else { 2377 native_cleanup(); 2378 } 2379 2380 // load default GPS configuration 2381 // (this configuration might change in the future based on SIM changes) 2382 reloadGpsProperties(mContext, mProperties); 2383 2384 // TODO: When this object "finishes" we should unregister by invoking 2385 // SubscriptionManager.getInstance(mContext).unregister 2386 // (mOnSubscriptionsChangedListener); 2387 // This is not strictly necessary because it will be unregistered if the 2388 // notification fails but it is good form. 2389 2390 // Register for SubscriptionInfo list changes which is guaranteed 2391 // to invoke onSubscriptionsChanged the first time. 2392 SubscriptionManager.from(mContext) 2393 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 2394 2395 // listen for events 2396 IntentFilter intentFilter; 2397 if (native_is_agps_ril_supported()) { 2398 intentFilter = new IntentFilter(); 2399 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); 2400 intentFilter.addDataScheme("sms"); 2401 intentFilter.addDataAuthority("localhost", "7275"); 2402 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2403 2404 intentFilter = new IntentFilter(); 2405 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); 2406 try { 2407 intentFilter.addDataType("application/vnd.omaloc-supl-init"); 2408 } catch (IntentFilter.MalformedMimeTypeException e) { 2409 Log.w(TAG, "Malformed SUPL init mime type"); 2410 } 2411 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2412 } else if (DEBUG) { 2413 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS" 2414 + " HAL is not supported"); 2415 } 2416 2417 intentFilter = new IntentFilter(); 2418 intentFilter.addAction(ALARM_WAKEUP); 2419 intentFilter.addAction(ALARM_TIMEOUT); 2420 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 2421 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 2422 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 2423 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 2424 intentFilter.addAction(SIM_STATE_CHANGED); 2425 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2426 2427 // register for connectivity change events, this is equivalent to the deprecated way of 2428 // registering for CONNECTIVITY_ACTION broadcasts 2429 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); 2430 networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 2431 networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); 2432 networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); 2433 NetworkRequest networkRequest = networkRequestBuilder.build(); 2434 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback); 2435 2436 // listen for PASSIVE_PROVIDER updates 2437 LocationManager locManager = 2438 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 2439 long minTime = 0; 2440 float minDistance = 0; 2441 boolean oneShot = false; 2442 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 2443 LocationManager.PASSIVE_PROVIDER, 2444 minTime, 2445 minDistance, 2446 oneShot); 2447 // Don't keep track of this request since it's done on behalf of other clients 2448 // (which are kept track of separately). 2449 request.setHideFromAppOps(true); 2450 locManager.requestLocationUpdates( 2451 request, 2452 new NetworkLocationListener(), 2453 getLooper()); 2454 } 2455 } 2456 2457 private abstract class LocationChangeListener implements LocationListener { 2458 int numLocationUpdateRequest; 2459 2460 @Override 2461 public void onStatusChanged(String provider, int status, Bundle extras) { 2462 } 2463 2464 @Override 2465 public void onProviderEnabled(String provider) { 2466 } 2467 2468 @Override 2469 public void onProviderDisabled(String provider) { 2470 } 2471 } 2472 2473 private final class NetworkLocationListener extends LocationChangeListener { 2474 @Override 2475 public void onLocationChanged(Location location) { 2476 // this callback happens on mHandler looper 2477 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 2478 handleUpdateLocation(location); 2479 } 2480 } 2481 } 2482 2483 private final class FusedLocationListener extends LocationChangeListener { 2484 @Override 2485 public void onLocationChanged(Location location) { 2486 if (LocationManager.FUSED_PROVIDER.equals(location.getProvider())) { 2487 injectBestLocation(location); 2488 } 2489 } 2490 } 2491 2492 private String getSelectedApn() { 2493 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 2494 Cursor cursor = null; 2495 try { 2496 cursor = mContext.getContentResolver().query( 2497 uri, 2498 new String[]{"apn"}, 2499 null /* selection */, 2500 null /* selectionArgs */, 2501 Carriers.DEFAULT_SORT_ORDER); 2502 if (cursor != null && cursor.moveToFirst()) { 2503 return cursor.getString(0); 2504 } else { 2505 Log.e(TAG, "No APN found to select."); 2506 } 2507 } catch (Exception e) { 2508 Log.e(TAG, "Error encountered on selecting the APN.", e); 2509 } finally { 2510 if (cursor != null) { 2511 cursor.close(); 2512 } 2513 } 2514 2515 return null; 2516 } 2517 2518 private int getApnIpType(String apn) { 2519 ensureInHandlerThread(); 2520 if (apn == null) { 2521 return APN_INVALID; 2522 } 2523 2524 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); 2525 Cursor cursor = null; 2526 try { 2527 cursor = mContext.getContentResolver().query( 2528 Carriers.CONTENT_URI, 2529 new String[]{Carriers.PROTOCOL}, 2530 selection, 2531 null, 2532 Carriers.DEFAULT_SORT_ORDER); 2533 2534 if (null != cursor && cursor.moveToFirst()) { 2535 return translateToApnIpType(cursor.getString(0), apn); 2536 } else { 2537 Log.e(TAG, "No entry found in query for APN: " + apn); 2538 } 2539 } catch (Exception e) { 2540 Log.e(TAG, "Error encountered on APN query for: " + apn, e); 2541 } finally { 2542 if (cursor != null) { 2543 cursor.close(); 2544 } 2545 } 2546 2547 return APN_INVALID; 2548 } 2549 2550 private int translateToApnIpType(String ipProtocol, String apn) { 2551 if ("IP".equals(ipProtocol)) { 2552 return APN_IPV4; 2553 } 2554 if ("IPV6".equals(ipProtocol)) { 2555 return APN_IPV6; 2556 } 2557 if ("IPV4V6".equals(ipProtocol)) { 2558 return APN_IPV4V6; 2559 } 2560 2561 // we hit the default case so the ipProtocol is not recognized 2562 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn); 2563 Log.e(TAG, message); 2564 return APN_INVALID; 2565 } 2566 2567 private void setRouting() { 2568 if (mAGpsDataConnectionIpAddr == null) { 2569 return; 2570 } 2571 2572 // TODO: replace the use of this deprecated API 2573 boolean result = mConnMgr.requestRouteToHostAddress( 2574 ConnectivityManager.TYPE_MOBILE_SUPL, 2575 mAGpsDataConnectionIpAddr); 2576 2577 if (!result) { 2578 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); 2579 } else if (DEBUG) { 2580 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); 2581 } 2582 } 2583 2584 /** 2585 * @return {@code true} if there is a data network available for outgoing connections, 2586 * {@code false} otherwise. 2587 */ 2588 private boolean isDataNetworkConnected() { 2589 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo(); 2590 return activeNetworkInfo != null && activeNetworkInfo.isConnected(); 2591 } 2592 2593 /** 2594 * Ensures the calling function is running in the thread associated with {@link #mHandler}. 2595 */ 2596 private void ensureInHandlerThread() { 2597 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) { 2598 return; 2599 } 2600 throw new RuntimeException("This method must run on the Handler thread."); 2601 } 2602 2603 /** 2604 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}. 2605 */ 2606 private String agpsDataConnStateAsString() { 2607 switch (mAGpsDataConnectionState) { 2608 case AGPS_DATA_CONNECTION_CLOSED: 2609 return "CLOSED"; 2610 case AGPS_DATA_CONNECTION_OPEN: 2611 return "OPEN"; 2612 case AGPS_DATA_CONNECTION_OPENING: 2613 return "OPENING"; 2614 default: 2615 return "<Unknown>"; 2616 } 2617 } 2618 2619 /** 2620 * @return A string representing the given GPS_AGPS_DATA status. 2621 */ 2622 private String agpsDataConnStatusAsString(int agpsDataConnStatus) { 2623 switch (agpsDataConnStatus) { 2624 case GPS_AGPS_DATA_CONNECTED: 2625 return "CONNECTED"; 2626 case GPS_AGPS_DATA_CONN_DONE: 2627 return "DONE"; 2628 case GPS_AGPS_DATA_CONN_FAILED: 2629 return "FAILED"; 2630 case GPS_RELEASE_AGPS_DATA_CONN: 2631 return "RELEASE"; 2632 case GPS_REQUEST_AGPS_DATA_CONN: 2633 return "REQUEST"; 2634 default: 2635 return "<Unknown>"; 2636 } 2637 } 2638 2639 /** 2640 * @return A string representing the given message ID. 2641 */ 2642 private String messageIdAsString(int message) { 2643 switch (message) { 2644 case ENABLE: 2645 return "ENABLE"; 2646 case SET_REQUEST: 2647 return "SET_REQUEST"; 2648 case UPDATE_NETWORK_STATE: 2649 return "UPDATE_NETWORK_STATE"; 2650 case REQUEST_SUPL_CONNECTION: 2651 return "REQUEST_SUPL_CONNECTION"; 2652 case RELEASE_SUPL_CONNECTION: 2653 return "RELEASE_SUPL_CONNECTION"; 2654 case INJECT_NTP_TIME: 2655 return "INJECT_NTP_TIME"; 2656 case REQUEST_LOCATION: 2657 return "REQUEST_LOCATION"; 2658 case DOWNLOAD_XTRA_DATA: 2659 return "DOWNLOAD_XTRA_DATA"; 2660 case DOWNLOAD_XTRA_DATA_FINISHED: 2661 return "DOWNLOAD_XTRA_DATA_FINISHED"; 2662 case UPDATE_LOCATION: 2663 return "UPDATE_LOCATION"; 2664 case SUBSCRIPTION_OR_SIM_CHANGED: 2665 return "SUBSCRIPTION_OR_SIM_CHANGED"; 2666 case INITIALIZE_HANDLER: 2667 return "INITIALIZE_HANDLER"; 2668 case REPORT_LOCATION: 2669 return "REPORT_LOCATION"; 2670 case REPORT_SV_STATUS: 2671 return "REPORT_SV_STATUS"; 2672 default: 2673 return "<Unknown>"; 2674 } 2675 } 2676 2677 2678 @Override 2679 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2680 StringBuilder s = new StringBuilder(); 2681 s.append(" mStarted=").append(mStarted).append('\n'); 2682 s.append(" mFixInterval=").append(mFixInterval).append('\n'); 2683 s.append(" mLowPowerMode=").append(mLowPowerMode).append('\n'); 2684 s.append(" mGnssMeasurementsProvider.isRegistered()=") 2685 .append(mGnssMeasurementsProvider.isRegistered()).append('\n'); 2686 s.append(" mGnssNavigationMessageProvider.isRegistered()=") 2687 .append(mGnssNavigationMessageProvider.isRegistered()).append('\n'); 2688 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n'); 2689 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)); 2690 s.append(" ( "); 2691 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING "); 2692 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB "); 2693 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA "); 2694 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT "); 2695 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME "); 2696 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING "); 2697 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS "); 2698 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES "); 2699 s.append(")\n"); 2700 s.append(mGnssMetrics.dumpGnssMetricsAsText()); 2701 s.append(" native internal state: ").append(native_get_internal_state()); 2702 s.append("\n"); 2703 pw.append(s); 2704 } 2705 2706 // preallocated to avoid memory allocation in reportNmea() 2707 private byte[] mNmeaBuffer = new byte[120]; 2708 2709 static { 2710 class_init_native(); 2711 } 2712 2713 private static native void class_init_native(); 2714 2715 private static native boolean native_is_supported(); 2716 2717 private static native boolean native_is_agps_ril_supported(); 2718 2719 private static native boolean native_is_gnss_configuration_supported(); 2720 2721 private static native void native_init_once(); 2722 2723 private native boolean native_init(); 2724 2725 private native void native_cleanup(); 2726 2727 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 2728 int preferred_accuracy, int preferred_time, boolean lowPowerMode); 2729 2730 private native boolean native_start(); 2731 2732 private native boolean native_stop(); 2733 2734 private native void native_delete_aiding_data(int flags); 2735 2736 private native int native_read_nmea(byte[] buffer, int bufferSize); 2737 2738 private native void native_inject_best_location( 2739 int gnssLocationFlags, 2740 double latitudeDegrees, 2741 double longitudeDegrees, 2742 double altitudeMeters, 2743 float speedMetersPerSec, 2744 float bearingDegrees, 2745 float horizontalAccuracyMeters, 2746 float verticalAccuracyMeters, 2747 float speedAccuracyMetersPerSecond, 2748 float bearingAccuracyDegrees, 2749 long timestamp); 2750 2751 private native void native_inject_location(double latitude, double longitude, float accuracy); 2752 2753 // XTRA Support 2754 private native void native_inject_time(long time, long timeReference, int uncertainty); 2755 2756 private native boolean native_supports_xtra(); 2757 2758 private native void native_inject_xtra_data(byte[] data, int length); 2759 2760 // DEBUG Support 2761 private native String native_get_internal_state(); 2762 2763 // AGPS Support 2764 private native void native_agps_data_conn_open(String apn, int apnIpType); 2765 2766 private native void native_agps_data_conn_closed(); 2767 2768 private native void native_agps_data_conn_failed(); 2769 2770 private native void native_agps_ni_message(byte[] msg, int length); 2771 2772 private native void native_set_agps_server(int type, String hostname, int port); 2773 2774 // Network-initiated (NI) Support 2775 private native void native_send_ni_response(int notificationId, int userResponse); 2776 2777 // AGPS ril suport 2778 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 2779 int lac, int cid); 2780 2781 private native void native_agps_set_id(int type, String setid); 2782 2783 private native void native_update_network_state(boolean connected, int type, 2784 boolean roaming, boolean available, String extraInfo, String defaultAPN); 2785 2786 // GNSS Configuration 2787 private static native boolean native_set_supl_version(int version); 2788 2789 private static native boolean native_set_supl_mode(int mode); 2790 2791 private static native boolean native_set_supl_es(int es); 2792 2793 private static native boolean native_set_lpp_profile(int lppProfile); 2794 2795 private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect); 2796 2797 private static native boolean native_set_gps_lock(int gpsLock); 2798 2799 private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn); 2800 2801 private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds); 2802 } 2803 2804