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 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 277 public LocationExtras() { 278 mBundle = new Bundle(); 279 } 280 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 290 public void reset() { 291 set(0,0,0); 292 } 293 294 // Also used by outside methods to add to other bundles 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 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 492 public IGnssStatusProvider getGnssStatusProvider() { 493 return mGnssStatusProvider; 494 } 495 496 public IGpsGeofenceHardware getGpsGeofenceProxy() { 497 return mGnssGeofenceProvider; 498 } 499 500 public GnssMeasurementsProvider getGnssMeasurementsProvider() { 501 return mGnssMeasurementsProvider; 502 } 503 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 588 public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) { 589 mHandler.post(()->{ 590 native_set_satellite_blacklist(constellations, svids); 591 }); 592 } 593 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 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 649 public static boolean isSupported() { 650 return native_is_supported(); 651 } 652 653 interface SetCarrierProperty { 654 public boolean set(int value); 655 } 656 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 728 private void loadPropertiesFromResource(Context context, 729 Properties properties) { 730 String[] configValues = context.getResources().getStringArray( 731 com.android.internal.R.array.config_gpsParameters); 732 for (String item : configValues) { 733 if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item); 734 // We need to support "KEY =", but not "=VALUE". 735 int index = item.indexOf("="); 736 if (index > 0 && index + 1 < item.length()) { 737 String key = item.substring(0, index); 738 String value = item.substring(index + 1); 739 properties.setProperty(key.trim().toUpperCase(), value); 740 } else { 741 Log.w(TAG, "malformed contents: " + item); 742 } 743 } 744 } 745 746 private boolean loadPropertiesFromFile(String filename, 747 Properties properties) { 748 try { 749 File file = new File(filename); 750 FileInputStream stream = null; 751 try { 752 stream = new FileInputStream(file); 753 properties.load(stream); 754 } finally { 755 IoUtils.closeQuietly(stream); 756 } 757 758 } catch (IOException e) { 759 if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename); 760 return false; 761 } 762 return true; 763 } 764 765 public GnssLocationProvider(Context context, ILocationManager ilocationManager, 766 Looper looper) { 767 mContext = context; 768 mILocationManager = ilocationManager; 769 770 // Create a wake lock 771 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 772 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 773 mWakeLock.setReferenceCounted(true); 774 775 // Create a separate wake lock for xtra downloader as it may be released due to timeout. 776 mDownloadXtraWakeLock = mPowerManager.newWakeLock( 777 PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY); 778 mDownloadXtraWakeLock.setReferenceCounted(true); 779 780 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 781 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); 782 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); 783 784 mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 785 786 // App ops service to keep track of who is accessing the GPS 787 mAppOps = mContext.getSystemService(AppOpsManager.class); 788 789 // Battery statistics service to be notified when GPS turns on or off 790 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 791 BatteryStats.SERVICE_NAME)); 792 793 // Construct internal handler 794 mHandler = new ProviderHandler(looper); 795 796 // Load GPS configuration and register listeners in the background: 797 // some operations, such as opening files and registering broadcast receivers, can take a 798 // relative long time, so the ctor() is kept to create objects needed by this instance, 799 // while IO initialization and registration is delegated to our internal handler 800 // this approach is just fine because events are posted to our handler anyway 801 mProperties = new Properties(); 802 sendMessage(INITIALIZE_HANDLER, 0, null); 803 804 // Create a GPS net-initiated handler. 805 mNIHandler = new GpsNetInitiatedHandler(context, 806 mNetInitiatedListener, 807 mSuplEsEnabled); 808 809 mListenerHelper = new GnssStatusListenerHelper(mHandler) { 810 @Override 811 protected boolean isAvailableInPlatform() { 812 return isSupported(); 813 } 814 815 @Override 816 protected boolean isGpsEnabled() { 817 return isEnabled(); 818 } 819 }; 820 821 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mContext, mHandler) { 822 @Override 823 protected boolean isGpsEnabled() { 824 return isEnabled(); 825 } 826 }; 827 828 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) { 829 @Override 830 protected boolean isGpsEnabled() { 831 return isEnabled(); 832 } 833 }; 834 mGnssMetrics = new GnssMetrics(mBatteryStats); 835 836 mNtpTimeHelper = new NtpTimeHelper(mContext, looper, this); 837 mGnssSatelliteBlacklistHelper = new GnssSatelliteBlacklistHelper(mContext, 838 looper, this); 839 mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist); 840 mGnssBatchingProvider = new GnssBatchingProvider(); 841 mGnssGeofenceProvider = new GnssGeofenceProvider(looper); 842 } 843 844 /** 845 * Returns the name of this provider. 846 */ 847 @Override 848 public String getName() { 849 return LocationManager.GPS_PROVIDER; 850 } 851 852 @Override 853 public ProviderProperties getProperties() { 854 return PROPERTIES; 855 } 856 857 858 /** 859 * Implements {@link InjectNtpTimeCallback#injectTime} 860 */ 861 @Override 862 public void injectTime(long time, long timeReference, int uncertainty) { 863 native_inject_time(time, timeReference, uncertainty); 864 } 865 866 private void handleUpdateNetworkState(Network network) { 867 // retrieve NetworkInfo for this UID 868 NetworkInfo info = mConnMgr.getNetworkInfo(network); 869 870 boolean networkAvailable = false; 871 boolean isConnected = false; 872 int type = ConnectivityManager.TYPE_NONE; 873 boolean isRoaming = false; 874 String apnName = null; 875 876 if (info != null) { 877 networkAvailable = info.isAvailable() && TelephonyManager.getDefault().getDataEnabled(); 878 isConnected = info.isConnected(); 879 type = info.getType(); 880 isRoaming = info.isRoaming(); 881 apnName = info.getExtraInfo(); 882 } 883 884 if (DEBUG) { 885 String message = String.format( 886 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S", 887 agpsDataConnStateAsString(), 888 isConnected, 889 info, 890 mConnMgr.getNetworkCapabilities(network)); 891 Log.d(TAG, message); 892 } 893 894 if (native_is_agps_ril_supported()) { 895 String defaultApn = getSelectedApn(); 896 if (defaultApn == null) { 897 defaultApn = "dummy-apn"; 898 } 899 900 native_update_network_state( 901 isConnected, 902 type, 903 isRoaming, 904 networkAvailable, 905 apnName, 906 defaultApn); 907 } else if (DEBUG) { 908 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported"); 909 } 910 911 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 912 if (isConnected) { 913 if (apnName == null) { 914 // assign a dummy value in the case of C2K as otherwise we will have a runtime 915 // exception in the following call to native_agps_data_conn_open 916 apnName = "dummy-apn"; 917 } 918 int apnIpType = getApnIpType(apnName); 919 setRouting(); 920 if (DEBUG) { 921 String message = String.format( 922 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", 923 apnName, 924 apnIpType); 925 Log.d(TAG, message); 926 } 927 native_agps_data_conn_open(apnName, apnIpType); 928 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 929 } else { 930 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); 931 } 932 } 933 } 934 935 private void handleRequestSuplConnection(InetAddress address) { 936 if (DEBUG) { 937 String message = String.format( 938 "requestSuplConnection, state=%s, address=%s", 939 agpsDataConnStateAsString(), 940 address); 941 Log.d(TAG, message); 942 } 943 944 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 945 return; 946 } 947 mAGpsDataConnectionIpAddr = address; 948 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 949 950 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder(); 951 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); 952 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); 953 NetworkRequest request = requestBuilder.build(); 954 mConnMgr.requestNetwork( 955 request, 956 mSuplConnectivityCallback); 957 } 958 959 private void handleReleaseSuplConnection(int agpsDataConnStatus) { 960 if (DEBUG) { 961 String message = String.format( 962 "releaseSuplConnection, state=%s, status=%s", 963 agpsDataConnStateAsString(), 964 agpsDataConnStatusAsString(agpsDataConnStatus)); 965 Log.d(TAG, message); 966 } 967 968 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) { 969 return; 970 } 971 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 972 973 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback); 974 switch (agpsDataConnStatus) { 975 case GPS_AGPS_DATA_CONN_FAILED: 976 native_agps_data_conn_failed(); 977 break; 978 case GPS_RELEASE_AGPS_DATA_CONN: 979 native_agps_data_conn_closed(); 980 break; 981 default: 982 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus); 983 } 984 } 985 986 private void handleRequestLocation(boolean independentFromGnss) { 987 if (isRequestLocationRateLimited()) { 988 if (DEBUG) { 989 Log.d(TAG, "RequestLocation is denied due to too frequent requests."); 990 } 991 return; 992 } 993 ContentResolver resolver = mContext.getContentResolver(); 994 long durationMillis = Settings.Global.getLong( 995 resolver, 996 Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS, 997 LOCATION_UPDATE_DURATION_MILLIS); 998 if (durationMillis == 0) { 999 Log.i(TAG, "GNSS HAL location request is disabled by Settings."); 1000 return; 1001 } 1002 1003 LocationManager locationManager = (LocationManager) mContext.getSystemService( 1004 Context.LOCATION_SERVICE); 1005 String provider; 1006 LocationChangeListener locationListener; 1007 1008 if (independentFromGnss) { 1009 // For fast GNSS TTFF 1010 provider = LocationManager.NETWORK_PROVIDER; 1011 locationListener = mNetworkLocationListener; 1012 } else { 1013 // For Device-Based Hybrid (E911) 1014 provider = LocationManager.FUSED_PROVIDER; 1015 locationListener = mFusedLocationListener; 1016 } 1017 1018 Log.i(TAG, 1019 String.format( 1020 "GNSS HAL Requesting location updates from %s provider for %d millis.", 1021 provider, durationMillis)); 1022 try { 1023 locationManager.requestLocationUpdates(provider, 1024 LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0, 1025 locationListener, mHandler.getLooper()); 1026 locationListener.numLocationUpdateRequest++; 1027 mHandler.postDelayed(() -> { 1028 if (--locationListener.numLocationUpdateRequest == 0) { 1029 Log.i(TAG, 1030 String.format("Removing location updates from %s provider.", provider)); 1031 locationManager.removeUpdates(locationListener); 1032 } 1033 }, durationMillis); 1034 } catch (IllegalArgumentException e) { 1035 Log.w(TAG, "Unable to request location.", e); 1036 } 1037 } 1038 1039 private void injectBestLocation(Location location) { 1040 int gnssLocationFlags = LOCATION_HAS_LAT_LONG | 1041 (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) | 1042 (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) | 1043 (location.hasBearing() ? LOCATION_HAS_BEARING : 0) | 1044 (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0) | 1045 (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0) | 1046 (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0) | 1047 (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0); 1048 1049 double latitudeDegrees = location.getLatitude(); 1050 double longitudeDegrees = location.getLongitude(); 1051 double altitudeMeters = location.getAltitude(); 1052 float speedMetersPerSec = location.getSpeed(); 1053 float bearingDegrees = location.getBearing(); 1054 float horizontalAccuracyMeters = location.getAccuracy(); 1055 float verticalAccuracyMeters = location.getVerticalAccuracyMeters(); 1056 float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond(); 1057 float bearingAccuracyDegrees = location.getBearingAccuracyDegrees(); 1058 long timestamp = location.getTime(); 1059 native_inject_best_location(gnssLocationFlags, latitudeDegrees, longitudeDegrees, 1060 altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters, 1061 verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees, 1062 timestamp); 1063 } 1064 1065 /** Returns true if the location request is too frequent. */ 1066 private boolean isRequestLocationRateLimited() { 1067 // TODO(b/73198123): implement exponential backoff. 1068 return false; 1069 } 1070 1071 private void handleDownloadXtraData() { 1072 if (!mSupportsXtra) { 1073 // native code reports xtra not supported, don't try 1074 Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported"); 1075 return; 1076 } 1077 if (mDownloadXtraDataPending == STATE_DOWNLOADING) { 1078 // already downloading data 1079 return; 1080 } 1081 if (!isDataNetworkConnected()) { 1082 // try again when network is up 1083 mDownloadXtraDataPending = STATE_PENDING_NETWORK; 1084 return; 1085 } 1086 mDownloadXtraDataPending = STATE_DOWNLOADING; 1087 1088 // hold wake lock while task runs 1089 mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS); 1090 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()"); 1091 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { 1092 @Override 1093 public void run() { 1094 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties); 1095 byte[] data = xtraDownloader.downloadXtraData(); 1096 if (data != null) { 1097 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data"); 1098 native_inject_xtra_data(data, data.length); 1099 mXtraBackOff.reset(); 1100 } 1101 1102 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null); 1103 1104 if (data == null) { 1105 // try again later 1106 // since this is delayed and not urgent we do not hold a wake lock here 1107 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA, 1108 mXtraBackOff.nextBackoffMillis()); 1109 } 1110 1111 // Release wake lock held by task, synchronize on mLock in case multiple 1112 // download tasks overrun. 1113 synchronized (mLock) { 1114 if (mDownloadXtraWakeLock.isHeld()) { 1115 // This wakelock may have time-out, if a timeout was specified. 1116 // Catch (and ignore) any timeout exceptions. 1117 try { 1118 mDownloadXtraWakeLock.release(); 1119 if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()"); 1120 } catch (Exception e) { 1121 Log.i(TAG, "Wakelock timeout & release race exception in " 1122 + "handleDownloadXtraData()", e); 1123 } 1124 } else { 1125 Log.e(TAG, "WakeLock expired before release in " 1126 + "handleDownloadXtraData()"); 1127 } 1128 } 1129 } 1130 }); 1131 } 1132 1133 private void handleUpdateLocation(Location location) { 1134 if (location.hasAccuracy()) { 1135 native_inject_location(location.getLatitude(), location.getLongitude(), 1136 location.getAccuracy()); 1137 } 1138 } 1139 1140 /** 1141 * Enables this provider. When enabled, calls to getStatus() 1142 * must be handled. Hardware may be started up 1143 * when the provider is enabled. 1144 */ 1145 @Override 1146 public void enable() { 1147 synchronized (mLock) { 1148 if (mEnabled) return; 1149 mEnabled = true; 1150 } 1151 1152 sendMessage(ENABLE, 1, null); 1153 } 1154 1155 private void setSuplHostPort(String hostString, String portString) { 1156 if (hostString != null) { 1157 mSuplServerHost = hostString; 1158 } 1159 if (portString != null) { 1160 try { 1161 mSuplServerPort = Integer.parseInt(portString); 1162 } catch (NumberFormatException e) { 1163 Log.e(TAG, "unable to parse SUPL_PORT: " + portString); 1164 } 1165 } 1166 if (mSuplServerHost != null 1167 && mSuplServerPort > TCP_MIN_PORT 1168 && mSuplServerPort <= TCP_MAX_PORT) { 1169 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 1170 } 1171 } 1172 1173 /** 1174 * Checks what SUPL mode to use, according to the AGPS mode as well as the 1175 * allowed mode from properties. 1176 * 1177 * @param properties GPS properties 1178 * @param agpsEnabled whether AGPS is enabled by settings value 1179 * @param singleShot whether "singleshot" is needed 1180 * @return SUPL mode (MSA vs MSB vs STANDALONE) 1181 */ 1182 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) { 1183 if (agpsEnabled) { 1184 String modeString = properties.getProperty("SUPL_MODE"); 1185 int suplMode = 0; 1186 if (!TextUtils.isEmpty(modeString)) { 1187 try { 1188 suplMode = Integer.parseInt(modeString); 1189 } catch (NumberFormatException e) { 1190 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString); 1191 return GPS_POSITION_MODE_STANDALONE; 1192 } 1193 } 1194 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor 1195 // such mode when it is available 1196 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { 1197 return GPS_POSITION_MODE_MS_BASED; 1198 } 1199 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available, 1200 // do fallback only for single-shot requests, because it is too expensive to do for 1201 // periodic requests as well 1202 if (singleShot 1203 && hasCapability(GPS_CAPABILITY_MSA) 1204 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) { 1205 return GPS_POSITION_MODE_MS_ASSISTED; 1206 } 1207 } 1208 return GPS_POSITION_MODE_STANDALONE; 1209 } 1210 1211 private void handleEnable() { 1212 if (DEBUG) Log.d(TAG, "handleEnable"); 1213 1214 boolean enabled = native_init(); 1215 1216 if (enabled) { 1217 mSupportsXtra = native_supports_xtra(); 1218 1219 // TODO: remove the following native calls if we can make sure they are redundant. 1220 if (mSuplServerHost != null) { 1221 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort); 1222 } 1223 if (mC2KServerHost != null) { 1224 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort); 1225 } 1226 1227 mGnssMeasurementsProvider.onGpsEnabledChanged(); 1228 mGnssNavigationMessageProvider.onGpsEnabledChanged(); 1229 mGnssBatchingProvider.enable(); 1230 } else { 1231 synchronized (mLock) { 1232 mEnabled = false; 1233 } 1234 Log.w(TAG, "Failed to enable location provider"); 1235 } 1236 } 1237 1238 /** 1239 * Disables this provider. When disabled, calls to getStatus() 1240 * need not be handled. Hardware may be shut 1241 * down while the provider is disabled. 1242 */ 1243 @Override 1244 public void disable() { 1245 synchronized (mLock) { 1246 if (!mEnabled) return; 1247 mEnabled = false; 1248 } 1249 1250 sendMessage(ENABLE, 0, null); 1251 } 1252 1253 private void handleDisable() { 1254 if (DEBUG) Log.d(TAG, "handleDisable"); 1255 1256 updateClientUids(new WorkSource()); 1257 stopNavigating(); 1258 mAlarmManager.cancel(mWakeupIntent); 1259 mAlarmManager.cancel(mTimeoutIntent); 1260 1261 mGnssBatchingProvider.disable(); 1262 // do this before releasing wakelock 1263 native_cleanup(); 1264 1265 mGnssMeasurementsProvider.onGpsEnabledChanged(); 1266 mGnssNavigationMessageProvider.onGpsEnabledChanged(); 1267 } 1268 1269 @Override 1270 public boolean isEnabled() { 1271 synchronized (mLock) { 1272 return mEnabled; 1273 } 1274 } 1275 1276 @Override 1277 public int getStatus(Bundle extras) { 1278 mLocationExtras.setBundle(extras); 1279 return mStatus; 1280 } 1281 1282 private void updateStatus(int status) { 1283 if (status != mStatus) { 1284 mStatus = status; 1285 mStatusUpdateTime = SystemClock.elapsedRealtime(); 1286 } 1287 } 1288 1289 @Override 1290 public long getStatusUpdateTime() { 1291 return mStatusUpdateTime; 1292 } 1293 1294 @Override 1295 public void setRequest(ProviderRequest request, WorkSource source) { 1296 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source)); 1297 } 1298 1299 private void handleSetRequest(ProviderRequest request, WorkSource source) { 1300 mProviderRequest = request; 1301 mWorkSource = source; 1302 updateRequirements(); 1303 } 1304 1305 // Called when the requirements for GPS may have changed 1306 private void updateRequirements() { 1307 if (mProviderRequest == null || mWorkSource == null) { 1308 return; 1309 } 1310 1311 boolean singleShot = false; 1312 1313 // see if the request is for a single update 1314 if (mProviderRequest.locationRequests != null 1315 && mProviderRequest.locationRequests.size() > 0) { 1316 // if any request has zero or more than one updates 1317 // requested, then this is not single-shot mode 1318 singleShot = true; 1319 1320 for (LocationRequest lr : mProviderRequest.locationRequests) { 1321 if (lr.getNumUpdates() != 1) { 1322 singleShot = false; 1323 } 1324 } 1325 } 1326 1327 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest); 1328 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) { 1329 // update client uids 1330 updateClientUids(mWorkSource); 1331 1332 mFixInterval = (int) mProviderRequest.interval; 1333 mLowPowerMode = (boolean) mProviderRequest.lowPowerMode; 1334 // check for overflow 1335 if (mFixInterval != mProviderRequest.interval) { 1336 Log.w(TAG, "interval overflow: " + mProviderRequest.interval); 1337 mFixInterval = Integer.MAX_VALUE; 1338 } 1339 1340 // apply request to GPS engine 1341 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1342 // change period and/or lowPowerMode 1343 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1344 mFixInterval, 0, 0, mLowPowerMode)) { 1345 Log.e(TAG, "set_position_mode failed in updateRequirements"); 1346 } 1347 } else if (!mStarted) { 1348 // start GPS 1349 startNavigating(singleShot); 1350 } else { 1351 // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING 1352 mAlarmManager.cancel(mTimeoutIntent); 1353 if (mFixInterval >= NO_FIX_TIMEOUT) { 1354 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1355 // and our fix interval is not short 1356 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1357 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); } 1358 } 1359 } else { 1360 updateClientUids(new WorkSource()); 1361 1362 stopNavigating(); 1363 mAlarmManager.cancel(mWakeupIntent); 1364 mAlarmManager.cancel(mTimeoutIntent); 1365 } 1366 } 1367 1368 private void updateClientUids(WorkSource source) { 1369 if (source.equals(mClientSource)) { 1370 return; 1371 } 1372 1373 // (1) Inform BatteryStats that the list of IDs we're tracking changed. 1374 try { 1375 mBatteryStats.noteGpsChanged(mClientSource, source); 1376 } catch (RemoteException e) { 1377 Log.w(TAG, "RemoteException", e); 1378 } 1379 1380 // (2) Inform AppOps service about the list of changes to UIDs. 1381 1382 List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source); 1383 if (diffs != null) { 1384 List<WorkChain> newChains = diffs[0]; 1385 List<WorkChain> goneChains = diffs[1]; 1386 1387 if (newChains != null) { 1388 for (int i = 0; i < newChains.size(); ++i) { 1389 final WorkChain newChain = newChains.get(i); 1390 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(), 1391 newChain.getAttributionTag()); 1392 } 1393 } 1394 1395 if (goneChains != null) { 1396 for (int i = 0; i < goneChains.size(); i++) { 1397 final WorkChain goneChain = goneChains.get(i); 1398 mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(), 1399 goneChain.getAttributionTag()); 1400 } 1401 } 1402 1403 mClientSource.transferWorkChains(source); 1404 } 1405 1406 // Update the flat UIDs and names list and inform app-ops of all changes. 1407 WorkSource[] changes = mClientSource.setReturningDiffs(source); 1408 if (changes != null) { 1409 WorkSource newWork = changes[0]; 1410 WorkSource goneWork = changes[1]; 1411 1412 // Update sources that were not previously tracked. 1413 if (newWork != null) { 1414 for (int i = 0; i < newWork.size(); i++) { 1415 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, 1416 newWork.get(i), newWork.getName(i)); 1417 } 1418 } 1419 1420 // Update sources that are no longer tracked. 1421 if (goneWork != null) { 1422 for (int i = 0; i < goneWork.size(); i++) { 1423 mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i)); 1424 } 1425 } 1426 } 1427 } 1428 1429 @Override 1430 public boolean sendExtraCommand(String command, Bundle extras) { 1431 1432 long identity = Binder.clearCallingIdentity(); 1433 try { 1434 boolean result = false; 1435 1436 if ("delete_aiding_data".equals(command)) { 1437 result = deleteAidingData(extras); 1438 } else if ("force_time_injection".equals(command)) { 1439 requestUtcTime(); 1440 result = true; 1441 } else if ("force_xtra_injection".equals(command)) { 1442 if (mSupportsXtra) { 1443 xtraDownloadRequest(); 1444 result = true; 1445 } 1446 } else { 1447 Log.w(TAG, "sendExtraCommand: unknown command " + command); 1448 } 1449 return result; 1450 } finally { 1451 Binder.restoreCallingIdentity(identity); 1452 } 1453 } 1454 1455 private boolean deleteAidingData(Bundle extras) { 1456 int flags; 1457 1458 if (extras == null) { 1459 flags = GPS_DELETE_ALL; 1460 } else { 1461 flags = 0; 1462 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS; 1463 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC; 1464 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION; 1465 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME; 1466 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO; 1467 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC; 1468 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH; 1469 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR; 1470 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER; 1471 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA; 1472 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI; 1473 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO; 1474 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL; 1475 } 1476 1477 if (flags != 0) { 1478 native_delete_aiding_data(flags); 1479 return true; 1480 } 1481 1482 return false; 1483 } 1484 1485 private void startNavigating(boolean singleShot) { 1486 if (!mStarted) { 1487 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot); 1488 mTimeToFirstFix = 0; 1489 mLastFixTime = 0; 1490 mStarted = true; 1491 mSingleShot = singleShot; 1492 mPositionMode = GPS_POSITION_MODE_STANDALONE; 1493 // Notify about suppressed output, if speed limit was previously exceeded. 1494 // Elsewhere, we check again with every speed output reported. 1495 if (mItarSpeedLimitExceeded) { 1496 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited " + 1497 "until slow enough speed reported."); 1498 } 1499 1500 boolean agpsEnabled = 1501 (Settings.Global.getInt(mContext.getContentResolver(), 1502 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0); 1503 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot); 1504 1505 if (DEBUG) { 1506 String mode; 1507 1508 switch (mPositionMode) { 1509 case GPS_POSITION_MODE_STANDALONE: 1510 mode = "standalone"; 1511 break; 1512 case GPS_POSITION_MODE_MS_ASSISTED: 1513 mode = "MS_ASSISTED"; 1514 break; 1515 case GPS_POSITION_MODE_MS_BASED: 1516 mode = "MS_BASED"; 1517 break; 1518 default: 1519 mode = "unknown"; 1520 break; 1521 } 1522 Log.d(TAG, "setting position_mode to " + mode); 1523 } 1524 1525 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000); 1526 mLowPowerMode = (boolean) mProviderRequest.lowPowerMode; 1527 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC, 1528 interval, 0, 0, mLowPowerMode)) { 1529 mStarted = false; 1530 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1531 return; 1532 } 1533 if (!native_start()) { 1534 mStarted = false; 1535 Log.e(TAG, "native_start failed in startNavigating()"); 1536 return; 1537 } 1538 1539 // reset SV count to zero 1540 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE); 1541 mLocationExtras.reset(); 1542 mFixRequestTime = SystemClock.elapsedRealtime(); 1543 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) { 1544 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1545 // and our fix interval is not short 1546 if (mFixInterval >= NO_FIX_TIMEOUT) { 1547 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1548 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); 1549 } 1550 } 1551 } 1552 } 1553 1554 private void stopNavigating() { 1555 if (DEBUG) Log.d(TAG, "stopNavigating"); 1556 if (mStarted) { 1557 mStarted = false; 1558 mSingleShot = false; 1559 native_stop(); 1560 mLastFixTime = 0; 1561 1562 // reset SV count to zero 1563 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE); 1564 mLocationExtras.reset(); 1565 } 1566 } 1567 1568 private void hibernate() { 1569 // stop GPS until our next fix interval arrives 1570 stopNavigating(); 1571 mAlarmManager.cancel(mTimeoutIntent); 1572 mAlarmManager.cancel(mWakeupIntent); 1573 long now = SystemClock.elapsedRealtime(); 1574 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent); 1575 } 1576 1577 private boolean hasCapability(int capability) { 1578 return ((mEngineCapabilities & capability) != 0); 1579 } 1580 1581 1582 /** 1583 * called from native code to update our position. 1584 */ 1585 private void reportLocation(boolean hasLatLong, Location location) { 1586 sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location); 1587 } 1588 1589 private void handleReportLocation(boolean hasLatLong, Location location) { 1590 if (location.hasSpeed()) { 1591 mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND; 1592 } 1593 1594 if (mItarSpeedLimitExceeded) { 1595 Log.i(TAG, "Hal reported a speed in excess of ITAR limit." + 1596 " GPS/GNSS Navigation output blocked."); 1597 if (mStarted) { 1598 mGnssMetrics.logReceivedLocationStatus(false); 1599 } 1600 return; // No output of location allowed 1601 } 1602 1603 if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString()); 1604 1605 // It would be nice to push the elapsed real-time timestamp 1606 // further down the stack, but this is still useful 1607 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 1608 location.setExtras(mLocationExtras.getBundle()); 1609 1610 try { 1611 mILocationManager.reportLocation(location, false); 1612 } catch (RemoteException e) { 1613 Log.e(TAG, "RemoteException calling reportLocation"); 1614 } 1615 1616 if (mStarted) { 1617 mGnssMetrics.logReceivedLocationStatus(hasLatLong); 1618 if (hasLatLong) { 1619 if (location.hasAccuracy()) { 1620 mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy()); 1621 } 1622 if (mTimeToFirstFix > 0) { 1623 int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime); 1624 mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes); 1625 } 1626 } 1627 } 1628 1629 mLastFixTime = SystemClock.elapsedRealtime(); 1630 // report time to first fix 1631 if (mTimeToFirstFix == 0 && hasLatLong) { 1632 mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime); 1633 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1634 if (mStarted) { 1635 mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix); 1636 } 1637 1638 // notify status listeners 1639 mListenerHelper.onFirstFix(mTimeToFirstFix); 1640 } 1641 1642 if (mSingleShot) { 1643 stopNavigating(); 1644 } 1645 1646 if (mStarted && mStatus != LocationProvider.AVAILABLE) { 1647 // For devices that use framework scheduling, a timer may be set to ensure we don't 1648 // spend too much power searching for a location, when the requested update rate is slow. 1649 // As we just recievied a location, we'll cancel that timer. 1650 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) { 1651 mAlarmManager.cancel(mTimeoutIntent); 1652 } 1653 1654 // send an intent to notify that the GPS is receiving fixes. 1655 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1656 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true); 1657 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1658 updateStatus(LocationProvider.AVAILABLE); 1659 } 1660 1661 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && 1662 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1663 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1664 hibernate(); 1665 } 1666 } 1667 1668 /** 1669 * called from native code to update our status 1670 */ 1671 private void reportStatus(int status) { 1672 if (DEBUG) Log.v(TAG, "reportStatus status: " + status); 1673 1674 boolean wasNavigating = mNavigating; 1675 switch (status) { 1676 case GPS_STATUS_SESSION_BEGIN: 1677 mNavigating = true; 1678 mEngineOn = true; 1679 break; 1680 case GPS_STATUS_SESSION_END: 1681 mNavigating = false; 1682 break; 1683 case GPS_STATUS_ENGINE_ON: 1684 mEngineOn = true; 1685 break; 1686 case GPS_STATUS_ENGINE_OFF: 1687 mEngineOn = false; 1688 mNavigating = false; 1689 break; 1690 } 1691 1692 if (wasNavigating != mNavigating) { 1693 mListenerHelper.onStatusChanged(mNavigating); 1694 1695 // send an intent to notify that the GPS has been enabled or disabled 1696 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION); 1697 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating); 1698 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1699 } 1700 } 1701 1702 // Helper class to carry data to handler for reportSvStatus 1703 private static class SvStatusInfo { 1704 public int mSvCount; 1705 public int[] mSvidWithFlags; 1706 public float[] mCn0s; 1707 public float[] mSvElevations; 1708 public float[] mSvAzimuths; 1709 public float[] mSvCarrierFreqs; 1710 } 1711 1712 /** 1713 * called from native code to update SV info 1714 */ 1715 private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s, 1716 float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) { 1717 SvStatusInfo svStatusInfo = new SvStatusInfo(); 1718 svStatusInfo.mSvCount = svCount; 1719 svStatusInfo.mSvidWithFlags = svidWithFlags; 1720 svStatusInfo.mCn0s = cn0s; 1721 svStatusInfo.mSvElevations = svElevations; 1722 svStatusInfo.mSvAzimuths = svAzimuths; 1723 svStatusInfo.mSvCarrierFreqs = svCarrierFreqs; 1724 1725 sendMessage(REPORT_SV_STATUS, 0, svStatusInfo); 1726 } 1727 1728 private void handleReportSvStatus(SvStatusInfo info) { 1729 mListenerHelper.onSvStatusChanged( 1730 info.mSvCount, 1731 info.mSvidWithFlags, 1732 info.mCn0s, 1733 info.mSvElevations, 1734 info.mSvAzimuths, 1735 info.mSvCarrierFreqs); 1736 1737 // Log CN0 as part of GNSS metrics 1738 mGnssMetrics.logCn0(info.mCn0s, info.mSvCount); 1739 1740 if (VERBOSE) { 1741 Log.v(TAG, "SV count: " + info.mSvCount); 1742 } 1743 // Calculate number of satellites used in fix. 1744 int usedInFixCount = 0; 1745 int maxCn0 = 0; 1746 int meanCn0 = 0; 1747 for (int i = 0; i < info.mSvCount; i++) { 1748 if ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) { 1749 ++usedInFixCount; 1750 if (info.mCn0s[i] > maxCn0) { 1751 maxCn0 = (int) info.mCn0s[i]; 1752 } 1753 meanCn0 += info.mCn0s[i]; 1754 } 1755 if (VERBOSE) { 1756 Log.v(TAG, "svid: " + (info.mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) + 1757 " cn0: " + info.mCn0s[i] + 1758 " elev: " + info.mSvElevations[i] + 1759 " azimuth: " + info.mSvAzimuths[i] + 1760 " carrier frequency: " + info.mSvCarrierFreqs[i] + 1761 ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0 1762 ? " " : " E") + 1763 ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0 1764 ? " " : " A") + 1765 ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0 1766 ? "" : "U") + 1767 ((info.mSvidWithFlags[i] & 1768 GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0 1769 ? "" : "F")); 1770 } 1771 } 1772 if (usedInFixCount > 0) { 1773 meanCn0 /= usedInFixCount; 1774 } 1775 // return number of sats used in fix instead of total reported 1776 mLocationExtras.set(usedInFixCount, meanCn0, maxCn0); 1777 1778 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && 1779 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) { 1780 // send an intent to notify that the GPS is no longer receiving fixes. 1781 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION); 1782 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false); 1783 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 1784 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE); 1785 } 1786 } 1787 1788 /** 1789 * called from native code to update AGPS status 1790 */ 1791 private void reportAGpsStatus(int type, int status, byte[] ipaddr) { 1792 switch (status) { 1793 case GPS_REQUEST_AGPS_DATA_CONN: 1794 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN"); 1795 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr)); 1796 InetAddress connectionIpAddress = null; 1797 if (ipaddr != null) { 1798 try { 1799 connectionIpAddress = InetAddress.getByAddress(ipaddr); 1800 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress); 1801 } catch (UnknownHostException e) { 1802 Log.e(TAG, "Bad IP Address: " + ipaddr, e); 1803 } 1804 } 1805 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress); 1806 break; 1807 case GPS_RELEASE_AGPS_DATA_CONN: 1808 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN"); 1809 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN); 1810 break; 1811 case GPS_AGPS_DATA_CONNECTED: 1812 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); 1813 break; 1814 case GPS_AGPS_DATA_CONN_DONE: 1815 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); 1816 break; 1817 case GPS_AGPS_DATA_CONN_FAILED: 1818 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); 1819 break; 1820 default: 1821 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status); 1822 } 1823 } 1824 1825 private void releaseSuplConnection(int connStatus) { 1826 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/); 1827 } 1828 1829 /** 1830 * called from native code to report NMEA data received 1831 */ 1832 private void reportNmea(long timestamp) { 1833 if (!mItarSpeedLimitExceeded) { 1834 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length); 1835 String nmea = new String(mNmeaBuffer, 0 /* offset */, length); 1836 mListenerHelper.onNmeaReceived(timestamp, nmea); 1837 } 1838 } 1839 1840 /** 1841 * called from native code - GNSS measurements callback 1842 */ 1843 private void reportMeasurementData(GnssMeasurementsEvent event) { 1844 if (!mItarSpeedLimitExceeded) { 1845 // send to handler to allow native to return quickly 1846 mHandler.post(new Runnable() { 1847 @Override 1848 public void run() { 1849 mGnssMeasurementsProvider.onMeasurementsAvailable(event); 1850 } 1851 }); 1852 } 1853 } 1854 1855 /** 1856 * called from native code - GNSS navigation message callback 1857 */ 1858 private void reportNavigationMessage(GnssNavigationMessage event) { 1859 if (!mItarSpeedLimitExceeded) { 1860 // send to handler to allow native to return quickly 1861 mHandler.post(new Runnable() { 1862 @Override 1863 public void run() { 1864 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event); 1865 } 1866 }); 1867 } 1868 } 1869 1870 /** 1871 * called from native code to inform us what the GPS engine capabilities are 1872 */ 1873 private void setEngineCapabilities(final int capabilities) { 1874 // send to handler thread for fast native return, and in-order handling 1875 mHandler.post(new Runnable() { 1876 @Override 1877 public void run() { 1878 mEngineCapabilities = capabilities; 1879 1880 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) { 1881 mNtpTimeHelper.enablePeriodicTimeInjection(); 1882 requestUtcTime(); 1883 } 1884 1885 mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability( 1886 GPS_CAPABILITY_MEASUREMENTS)); 1887 mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability( 1888 GPS_CAPABILITY_NAV_MESSAGES)); 1889 restartRequests(); 1890 } 1891 }); 1892 } 1893 1894 private void restartRequests() { 1895 Log.i(TAG, "restartRequests"); 1896 1897 restartLocationRequest(); 1898 mGnssMeasurementsProvider.resumeIfStarted(); 1899 mGnssNavigationMessageProvider.resumeIfStarted(); 1900 mGnssBatchingProvider.resumeIfStarted(); 1901 mGnssGeofenceProvider.resumeIfStarted(); 1902 } 1903 1904 private void restartLocationRequest() { 1905 if (DEBUG) Log.d(TAG, "restartLocationRequest"); 1906 mStarted = false; 1907 updateRequirements(); 1908 } 1909 1910 /** 1911 * Called from native code to inform us the hardware year. 1912 */ 1913 private void setGnssYearOfHardware(final int yearOfHardware) { 1914 // mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync 1915 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware); 1916 mHardwareYear = yearOfHardware; 1917 } 1918 1919 /** 1920 * Called from native code to inform us the hardware model name. 1921 */ 1922 private void setGnssHardwareModelName(final String modelName) { 1923 // mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync 1924 if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName); 1925 mHardwareModelName = modelName; 1926 } 1927 1928 /** 1929 * Called from native code to inform us GNSS HAL service died. 1930 */ 1931 private void reportGnssServiceDied() { 1932 if (DEBUG) Log.d(TAG, "reportGnssServiceDied"); 1933 mHandler.post(() -> { 1934 class_init_native(); 1935 native_init_once(); 1936 if (isEnabled()) { 1937 // re-calls native_init() and other setup. 1938 handleEnable(); 1939 // resend configuration into the restarted HAL service. 1940 reloadGpsProperties(mContext, mProperties); 1941 } 1942 }); 1943 } 1944 1945 public interface GnssSystemInfoProvider { 1946 /** 1947 * Returns the year of underlying GPS hardware. 1948 */ 1949 int getGnssYearOfHardware(); 1950 /** 1951 * Returns the model name of underlying GPS hardware. 1952 */ 1953 String getGnssHardwareModelName(); 1954 } 1955 1956 /** 1957 * @hide 1958 */ 1959 public GnssSystemInfoProvider getGnssSystemInfoProvider() { 1960 return new GnssSystemInfoProvider() { 1961 @Override 1962 public int getGnssYearOfHardware() { 1963 return mHardwareYear; 1964 } 1965 @Override 1966 public String getGnssHardwareModelName() { 1967 return mHardwareModelName; 1968 } 1969 }; 1970 } 1971 1972 /** 1973 * @hide 1974 */ 1975 public GnssBatchingProvider getGnssBatchingProvider() { 1976 return mGnssBatchingProvider; 1977 } 1978 1979 public interface GnssMetricsProvider { 1980 /** 1981 * Returns GNSS metrics as proto string 1982 */ 1983 String getGnssMetricsAsProtoString(); 1984 } 1985 1986 /** 1987 * @hide 1988 */ 1989 public GnssMetricsProvider getGnssMetricsProvider() { 1990 return new GnssMetricsProvider() { 1991 @Override 1992 public String getGnssMetricsAsProtoString() { 1993 return mGnssMetrics.dumpGnssMetricsAsProtoString(); 1994 } 1995 }; 1996 } 1997 1998 /** 1999 * called from native code - GNSS location batch callback 2000 */ 2001 private void reportLocationBatch(Location[] locationArray) { 2002 List<Location> locations = new ArrayList<>(Arrays.asList(locationArray)); 2003 if (DEBUG) { 2004 Log.d(TAG, "Location batch of size " + locationArray.length + " reported"); 2005 } 2006 try { 2007 mILocationManager.reportLocationBatch(locations); 2008 } catch (RemoteException e) { 2009 Log.e(TAG, "RemoteException calling reportLocationBatch"); 2010 } 2011 } 2012 2013 /** 2014 * called from native code to request XTRA data 2015 */ 2016 private void xtraDownloadRequest() { 2017 if (DEBUG) Log.d(TAG, "xtraDownloadRequest"); 2018 sendMessage(DOWNLOAD_XTRA_DATA, 0, null); 2019 } 2020 2021 /** 2022 * Converts the GPS HAL status to the internal Geofence Hardware status. 2023 */ 2024 private int getGeofenceStatus(int status) { 2025 switch (status) { 2026 case GPS_GEOFENCE_OPERATION_SUCCESS: 2027 return GeofenceHardware.GEOFENCE_SUCCESS; 2028 case GPS_GEOFENCE_ERROR_GENERIC: 2029 return GeofenceHardware.GEOFENCE_FAILURE; 2030 case GPS_GEOFENCE_ERROR_ID_EXISTS: 2031 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS; 2032 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION: 2033 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION; 2034 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES: 2035 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES; 2036 case GPS_GEOFENCE_ERROR_ID_UNKNOWN: 2037 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN; 2038 default: 2039 return -1; 2040 } 2041 } 2042 2043 /** 2044 * Called from native to report GPS Geofence transition 2045 * All geofence callbacks are called on the same thread 2046 */ 2047 private void reportGeofenceTransition(int geofenceId, Location location, int transition, 2048 long transitionTimestamp) { 2049 if (mGeofenceHardwareImpl == null) { 2050 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2051 } 2052 2053 mGeofenceHardwareImpl.reportGeofenceTransition( 2054 geofenceId, 2055 location, 2056 transition, 2057 transitionTimestamp, 2058 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 2059 FusedBatchOptions.SourceTechnologies.GNSS); 2060 } 2061 2062 /** 2063 * called from native code to report GPS status change. 2064 */ 2065 private void reportGeofenceStatus(int status, Location location) { 2066 if (mGeofenceHardwareImpl == null) { 2067 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2068 } 2069 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE; 2070 if (status == GPS_GEOFENCE_AVAILABLE) { 2071 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE; 2072 } 2073 mGeofenceHardwareImpl.reportGeofenceMonitorStatus( 2074 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE, 2075 monitorStatus, 2076 location, 2077 FusedBatchOptions.SourceTechnologies.GNSS); 2078 } 2079 2080 /** 2081 * called from native code - Geofence Add callback 2082 */ 2083 private void reportGeofenceAddStatus(int geofenceId, int status) { 2084 if (mGeofenceHardwareImpl == null) { 2085 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2086 } 2087 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status)); 2088 } 2089 2090 /** 2091 * called from native code - Geofence Remove callback 2092 */ 2093 private void reportGeofenceRemoveStatus(int geofenceId, int status) { 2094 if (mGeofenceHardwareImpl == null) { 2095 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2096 } 2097 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status)); 2098 } 2099 2100 /** 2101 * called from native code - Geofence Pause callback 2102 */ 2103 private void reportGeofencePauseStatus(int geofenceId, int status) { 2104 if (mGeofenceHardwareImpl == null) { 2105 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2106 } 2107 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status)); 2108 } 2109 2110 /** 2111 * called from native code - Geofence Resume callback 2112 */ 2113 private void reportGeofenceResumeStatus(int geofenceId, int status) { 2114 if (mGeofenceHardwareImpl == null) { 2115 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext); 2116 } 2117 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status)); 2118 } 2119 2120 //============================================================= 2121 // NI Client support 2122 //============================================================= 2123 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 2124 // Sends a response for an NI request to HAL. 2125 @Override 2126 public boolean sendNiResponse(int notificationId, int userResponse) { 2127 // TODO Add Permission check 2128 2129 if (DEBUG) { 2130 Log.d(TAG, "sendNiResponse, notifId: " + notificationId + 2131 ", response: " + userResponse); 2132 } 2133 native_send_ni_response(notificationId, userResponse); 2134 return true; 2135 } 2136 }; 2137 2138 public INetInitiatedListener getNetInitiatedListener() { 2139 return mNetInitiatedListener; 2140 } 2141 2142 // Called by JNI function to report an NI request. 2143 public void reportNiNotification( 2144 int notificationId, 2145 int niType, 2146 int notifyFlags, 2147 int timeout, 2148 int defaultResponse, 2149 String requestorId, 2150 String text, 2151 int requestorIdEncoding, 2152 int textEncoding 2153 ) { 2154 Log.i(TAG, "reportNiNotification: entered"); 2155 Log.i(TAG, "notificationId: " + notificationId + 2156 ", niType: " + niType + 2157 ", notifyFlags: " + notifyFlags + 2158 ", timeout: " + timeout + 2159 ", defaultResponse: " + defaultResponse); 2160 2161 Log.i(TAG, "requestorId: " + requestorId + 2162 ", text: " + text + 2163 ", requestorIdEncoding: " + requestorIdEncoding + 2164 ", textEncoding: " + textEncoding); 2165 2166 GpsNiNotification notification = new GpsNiNotification(); 2167 2168 notification.notificationId = notificationId; 2169 notification.niType = niType; 2170 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 2171 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 2172 notification.privacyOverride = 2173 (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 2174 notification.timeout = timeout; 2175 notification.defaultResponse = defaultResponse; 2176 notification.requestorId = requestorId; 2177 notification.text = text; 2178 notification.requestorIdEncoding = requestorIdEncoding; 2179 notification.textEncoding = textEncoding; 2180 2181 mNIHandler.handleNiNotification(notification); 2182 } 2183 2184 /** 2185 * Called from native code to request set id info. 2186 * We should be careful about receiving null string from the TelephonyManager, 2187 * because sending null String to JNI function would cause a crash. 2188 */ 2189 2190 private void requestSetID(int flags) { 2191 TelephonyManager phone = (TelephonyManager) 2192 mContext.getSystemService(Context.TELEPHONY_SERVICE); 2193 int type = AGPS_SETID_TYPE_NONE; 2194 String data = ""; 2195 2196 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) { 2197 String data_temp = phone.getSubscriberId(); 2198 if (data_temp == null) { 2199 // This means the framework does not have the SIM card ready. 2200 } else { 2201 // This means the framework has the SIM card. 2202 data = data_temp; 2203 type = AGPS_SETID_TYPE_IMSI; 2204 } 2205 } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) { 2206 String data_temp = phone.getLine1Number(); 2207 if (data_temp == null) { 2208 // This means the framework does not have the SIM card ready. 2209 } else { 2210 // This means the framework has the SIM card. 2211 data = data_temp; 2212 type = AGPS_SETID_TYPE_MSISDN; 2213 } 2214 } 2215 native_agps_set_id(type, data); 2216 } 2217 2218 /** 2219 * Called from native code to request location info. 2220 */ 2221 private void requestLocation(boolean independentFromGnss) { 2222 if (DEBUG) { 2223 Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss); 2224 } 2225 sendMessage(REQUEST_LOCATION, 0, independentFromGnss); 2226 } 2227 2228 /** 2229 * Called from native code to request utc time info 2230 */ 2231 private void requestUtcTime() { 2232 if (DEBUG) Log.d(TAG, "utcTimeRequest"); 2233 sendMessage(INJECT_NTP_TIME, 0, null); 2234 } 2235 2236 /** 2237 * Called from native code to request reference location info 2238 */ 2239 private void requestRefLocation() { 2240 TelephonyManager phone = (TelephonyManager) 2241 mContext.getSystemService(Context.TELEPHONY_SERVICE); 2242 final int phoneType = phone.getPhoneType(); 2243 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 2244 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation(); 2245 if ((gsm_cell != null) && (phone.getNetworkOperator() != null) 2246 && (phone.getNetworkOperator().length() > 3)) { 2247 int type; 2248 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0, 3)); 2249 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3)); 2250 int networkType = phone.getNetworkType(); 2251 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS 2252 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA 2253 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA 2254 || networkType == TelephonyManager.NETWORK_TYPE_HSPA 2255 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) { 2256 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 2257 } else { 2258 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID; 2259 } 2260 native_agps_set_ref_location_cellid(type, mcc, mnc, 2261 gsm_cell.getLac(), gsm_cell.getCid()); 2262 } else { 2263 Log.e(TAG, "Error getting cell location info."); 2264 } 2265 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 2266 Log.e(TAG, "CDMA not supported."); 2267 } 2268 } 2269 2270 private void sendMessage(int message, int arg, Object obj) { 2271 // hold a wake lock until this message is delivered 2272 // note that this assumes the message will not be removed from the queue before 2273 // it is handled (otherwise the wake lock would be leaked). 2274 mWakeLock.acquire(); 2275 if (Log.isLoggable(TAG, Log.INFO)) { 2276 Log.i(TAG, "WakeLock acquired by sendMessage(" + messageIdAsString(message) + ", " + arg 2277 + ", " + obj + ")"); 2278 } 2279 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget(); 2280 } 2281 2282 private final class ProviderHandler extends Handler { 2283 public ProviderHandler(Looper looper) { 2284 super(looper, null, true /*async*/); 2285 } 2286 2287 @Override 2288 public void handleMessage(Message msg) { 2289 int message = msg.what; 2290 switch (message) { 2291 case ENABLE: 2292 if (msg.arg1 == 1) { 2293 handleEnable(); 2294 } else { 2295 handleDisable(); 2296 } 2297 break; 2298 case SET_REQUEST: 2299 GpsRequest gpsRequest = (GpsRequest) msg.obj; 2300 handleSetRequest(gpsRequest.request, gpsRequest.source); 2301 break; 2302 case UPDATE_NETWORK_STATE: 2303 handleUpdateNetworkState((Network) msg.obj); 2304 break; 2305 case REQUEST_SUPL_CONNECTION: 2306 handleRequestSuplConnection((InetAddress) msg.obj); 2307 break; 2308 case RELEASE_SUPL_CONNECTION: 2309 handleReleaseSuplConnection(msg.arg1); 2310 break; 2311 case INJECT_NTP_TIME: 2312 mNtpTimeHelper.retrieveAndInjectNtpTime(); 2313 break; 2314 case REQUEST_LOCATION: 2315 handleRequestLocation((boolean) msg.obj); 2316 break; 2317 case DOWNLOAD_XTRA_DATA: 2318 handleDownloadXtraData(); 2319 break; 2320 case DOWNLOAD_XTRA_DATA_FINISHED: 2321 mDownloadXtraDataPending = STATE_IDLE; 2322 break; 2323 case UPDATE_LOCATION: 2324 handleUpdateLocation((Location) msg.obj); 2325 break; 2326 case SUBSCRIPTION_OR_SIM_CHANGED: 2327 subscriptionOrSimChanged(mContext); 2328 break; 2329 case INITIALIZE_HANDLER: 2330 handleInitialize(); 2331 break; 2332 case REPORT_LOCATION: 2333 handleReportLocation(msg.arg1 == 1, (Location) msg.obj); 2334 break; 2335 case REPORT_SV_STATUS: 2336 handleReportSvStatus((SvStatusInfo) msg.obj); 2337 break; 2338 } 2339 if (msg.arg2 == 1) { 2340 // wakelock was taken for this message, release it 2341 mWakeLock.release(); 2342 if (Log.isLoggable(TAG, Log.INFO)) { 2343 Log.i(TAG, "WakeLock released by handleMessage(" + messageIdAsString(message) 2344 + ", " + msg.arg1 + ", " + msg.obj + ")"); 2345 } 2346 } 2347 } 2348 2349 /** 2350 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}. 2351 * It is in charge of loading properties and registering for events that will be posted to 2352 * this handler. 2353 */ 2354 private void handleInitialize() { 2355 native_init_once(); 2356 2357 /* 2358 * A cycle of native_init() and native_cleanup() is needed so that callbacks are 2359 * registered after bootup even when location is disabled. 2360 * This will allow Emergency SUPL to work even when location is disabled before device 2361 * restart. 2362 */ 2363 boolean isInitialized = native_init(); 2364 if (!isInitialized) { 2365 Log.w(TAG, "Native initialization failed at bootup"); 2366 } else { 2367 native_cleanup(); 2368 } 2369 2370 // load default GPS configuration 2371 // (this configuration might change in the future based on SIM changes) 2372 reloadGpsProperties(mContext, mProperties); 2373 2374 // TODO: When this object "finishes" we should unregister by invoking 2375 // SubscriptionManager.getInstance(mContext).unregister 2376 // (mOnSubscriptionsChangedListener); 2377 // This is not strictly necessary because it will be unregistered if the 2378 // notification fails but it is good form. 2379 2380 // Register for SubscriptionInfo list changes which is guaranteed 2381 // to invoke onSubscriptionsChanged the first time. 2382 SubscriptionManager.from(mContext) 2383 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener); 2384 2385 // listen for events 2386 IntentFilter intentFilter; 2387 if (native_is_agps_ril_supported()) { 2388 intentFilter = new IntentFilter(); 2389 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); 2390 intentFilter.addDataScheme("sms"); 2391 intentFilter.addDataAuthority("localhost", "7275"); 2392 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2393 2394 intentFilter = new IntentFilter(); 2395 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); 2396 try { 2397 intentFilter.addDataType("application/vnd.omaloc-supl-init"); 2398 } catch (IntentFilter.MalformedMimeTypeException e) { 2399 Log.w(TAG, "Malformed SUPL init mime type"); 2400 } 2401 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2402 } else if (DEBUG) { 2403 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS" 2404 + " HAL is not supported"); 2405 } 2406 2407 intentFilter = new IntentFilter(); 2408 intentFilter.addAction(ALARM_WAKEUP); 2409 intentFilter.addAction(ALARM_TIMEOUT); 2410 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 2411 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 2412 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 2413 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 2414 intentFilter.addAction(SIM_STATE_CHANGED); 2415 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this); 2416 2417 // register for connectivity change events, this is equivalent to the deprecated way of 2418 // registering for CONNECTIVITY_ACTION broadcasts 2419 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); 2420 networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 2421 networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); 2422 networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); 2423 NetworkRequest networkRequest = networkRequestBuilder.build(); 2424 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback); 2425 2426 // listen for PASSIVE_PROVIDER updates 2427 LocationManager locManager = 2428 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 2429 long minTime = 0; 2430 float minDistance = 0; 2431 boolean oneShot = false; 2432 LocationRequest request = LocationRequest.createFromDeprecatedProvider( 2433 LocationManager.PASSIVE_PROVIDER, 2434 minTime, 2435 minDistance, 2436 oneShot); 2437 // Don't keep track of this request since it's done on behalf of other clients 2438 // (which are kept track of separately). 2439 request.setHideFromAppOps(true); 2440 locManager.requestLocationUpdates( 2441 request, 2442 new NetworkLocationListener(), 2443 getLooper()); 2444 } 2445 } 2446 2447 private abstract class LocationChangeListener implements LocationListener { 2448 int numLocationUpdateRequest; 2449 2450 @Override 2451 public void onStatusChanged(String provider, int status, Bundle extras) { 2452 } 2453 2454 @Override 2455 public void onProviderEnabled(String provider) { 2456 } 2457 2458 @Override 2459 public void onProviderDisabled(String provider) { 2460 } 2461 } 2462 2463 private final class NetworkLocationListener extends LocationChangeListener { 2464 @Override 2465 public void onLocationChanged(Location location) { 2466 // this callback happens on mHandler looper 2467 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) { 2468 handleUpdateLocation(location); 2469 } 2470 } 2471 } 2472 2473 private final class FusedLocationListener extends LocationChangeListener { 2474 @Override 2475 public void onLocationChanged(Location location) { 2476 if (LocationManager.FUSED_PROVIDER.equals(location.getProvider())) { 2477 injectBestLocation(location); 2478 } 2479 } 2480 } 2481 2482 private String getSelectedApn() { 2483 Uri uri = Uri.parse("content://telephony/carriers/preferapn"); 2484 Cursor cursor = null; 2485 try { 2486 cursor = mContext.getContentResolver().query( 2487 uri, 2488 new String[]{"apn"}, 2489 null /* selection */, 2490 null /* selectionArgs */, 2491 Carriers.DEFAULT_SORT_ORDER); 2492 if (cursor != null && cursor.moveToFirst()) { 2493 return cursor.getString(0); 2494 } else { 2495 Log.e(TAG, "No APN found to select."); 2496 } 2497 } catch (Exception e) { 2498 Log.e(TAG, "Error encountered on selecting the APN.", e); 2499 } finally { 2500 if (cursor != null) { 2501 cursor.close(); 2502 } 2503 } 2504 2505 return null; 2506 } 2507 2508 private int getApnIpType(String apn) { 2509 ensureInHandlerThread(); 2510 if (apn == null) { 2511 return APN_INVALID; 2512 } 2513 2514 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); 2515 Cursor cursor = null; 2516 try { 2517 cursor = mContext.getContentResolver().query( 2518 Carriers.CONTENT_URI, 2519 new String[]{Carriers.PROTOCOL}, 2520 selection, 2521 null, 2522 Carriers.DEFAULT_SORT_ORDER); 2523 2524 if (null != cursor && cursor.moveToFirst()) { 2525 return translateToApnIpType(cursor.getString(0), apn); 2526 } else { 2527 Log.e(TAG, "No entry found in query for APN: " + apn); 2528 } 2529 } catch (Exception e) { 2530 Log.e(TAG, "Error encountered on APN query for: " + apn, e); 2531 } finally { 2532 if (cursor != null) { 2533 cursor.close(); 2534 } 2535 } 2536 2537 return APN_INVALID; 2538 } 2539 2540 private int translateToApnIpType(String ipProtocol, String apn) { 2541 if ("IP".equals(ipProtocol)) { 2542 return APN_IPV4; 2543 } 2544 if ("IPV6".equals(ipProtocol)) { 2545 return APN_IPV6; 2546 } 2547 if ("IPV4V6".equals(ipProtocol)) { 2548 return APN_IPV4V6; 2549 } 2550 2551 // we hit the default case so the ipProtocol is not recognized 2552 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn); 2553 Log.e(TAG, message); 2554 return APN_INVALID; 2555 } 2556 2557 private void setRouting() { 2558 if (mAGpsDataConnectionIpAddr == null) { 2559 return; 2560 } 2561 2562 // TODO: replace the use of this deprecated API 2563 boolean result = mConnMgr.requestRouteToHostAddress( 2564 ConnectivityManager.TYPE_MOBILE_SUPL, 2565 mAGpsDataConnectionIpAddr); 2566 2567 if (!result) { 2568 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); 2569 } else if (DEBUG) { 2570 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); 2571 } 2572 } 2573 2574 /** 2575 * @return {@code true} if there is a data network available for outgoing connections, 2576 * {@code false} otherwise. 2577 */ 2578 private boolean isDataNetworkConnected() { 2579 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo(); 2580 return activeNetworkInfo != null && activeNetworkInfo.isConnected(); 2581 } 2582 2583 /** 2584 * Ensures the calling function is running in the thread associated with {@link #mHandler}. 2585 */ 2586 private void ensureInHandlerThread() { 2587 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) { 2588 return; 2589 } 2590 throw new RuntimeException("This method must run on the Handler thread."); 2591 } 2592 2593 /** 2594 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}. 2595 */ 2596 private String agpsDataConnStateAsString() { 2597 switch (mAGpsDataConnectionState) { 2598 case AGPS_DATA_CONNECTION_CLOSED: 2599 return "CLOSED"; 2600 case AGPS_DATA_CONNECTION_OPEN: 2601 return "OPEN"; 2602 case AGPS_DATA_CONNECTION_OPENING: 2603 return "OPENING"; 2604 default: 2605 return "<Unknown>"; 2606 } 2607 } 2608 2609 /** 2610 * @return A string representing the given GPS_AGPS_DATA status. 2611 */ 2612 private String agpsDataConnStatusAsString(int agpsDataConnStatus) { 2613 switch (agpsDataConnStatus) { 2614 case GPS_AGPS_DATA_CONNECTED: 2615 return "CONNECTED"; 2616 case GPS_AGPS_DATA_CONN_DONE: 2617 return "DONE"; 2618 case GPS_AGPS_DATA_CONN_FAILED: 2619 return "FAILED"; 2620 case GPS_RELEASE_AGPS_DATA_CONN: 2621 return "RELEASE"; 2622 case GPS_REQUEST_AGPS_DATA_CONN: 2623 return "REQUEST"; 2624 default: 2625 return "<Unknown>"; 2626 } 2627 } 2628 2629 /** 2630 * @return A string representing the given message ID. 2631 */ 2632 private String messageIdAsString(int message) { 2633 switch (message) { 2634 case ENABLE: 2635 return "ENABLE"; 2636 case SET_REQUEST: 2637 return "SET_REQUEST"; 2638 case UPDATE_NETWORK_STATE: 2639 return "UPDATE_NETWORK_STATE"; 2640 case REQUEST_SUPL_CONNECTION: 2641 return "REQUEST_SUPL_CONNECTION"; 2642 case RELEASE_SUPL_CONNECTION: 2643 return "RELEASE_SUPL_CONNECTION"; 2644 case INJECT_NTP_TIME: 2645 return "INJECT_NTP_TIME"; 2646 case REQUEST_LOCATION: 2647 return "REQUEST_LOCATION"; 2648 case DOWNLOAD_XTRA_DATA: 2649 return "DOWNLOAD_XTRA_DATA"; 2650 case DOWNLOAD_XTRA_DATA_FINISHED: 2651 return "DOWNLOAD_XTRA_DATA_FINISHED"; 2652 case UPDATE_LOCATION: 2653 return "UPDATE_LOCATION"; 2654 case SUBSCRIPTION_OR_SIM_CHANGED: 2655 return "SUBSCRIPTION_OR_SIM_CHANGED"; 2656 case INITIALIZE_HANDLER: 2657 return "INITIALIZE_HANDLER"; 2658 case REPORT_LOCATION: 2659 return "REPORT_LOCATION"; 2660 case REPORT_SV_STATUS: 2661 return "REPORT_SV_STATUS"; 2662 default: 2663 return "<Unknown>"; 2664 } 2665 } 2666 2667 2668 @Override 2669 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2670 StringBuilder s = new StringBuilder(); 2671 s.append(" mStarted=").append(mStarted).append('\n'); 2672 s.append(" mFixInterval=").append(mFixInterval).append('\n'); 2673 s.append(" mLowPowerMode=").append(mLowPowerMode).append('\n'); 2674 s.append(" mGnssMeasurementsProvider.isRegistered()=") 2675 .append(mGnssMeasurementsProvider.isRegistered()).append('\n'); 2676 s.append(" mGnssNavigationMessageProvider.isRegistered()=") 2677 .append(mGnssNavigationMessageProvider.isRegistered()).append('\n'); 2678 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n'); 2679 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)); 2680 s.append(" ( "); 2681 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING "); 2682 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB "); 2683 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA "); 2684 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT "); 2685 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME "); 2686 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING "); 2687 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS "); 2688 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES "); 2689 s.append(")\n"); 2690 s.append(mGnssMetrics.dumpGnssMetricsAsText()); 2691 s.append(" native internal state: ").append(native_get_internal_state()); 2692 s.append("\n"); 2693 pw.append(s); 2694 } 2695 2696 // preallocated to avoid memory allocation in reportNmea() 2697 private byte[] mNmeaBuffer = new byte[120]; 2698 2699 static { 2700 class_init_native(); 2701 } 2702 2703 private static native void class_init_native(); 2704 2705 private static native boolean native_is_supported(); 2706 2707 private static native boolean native_is_agps_ril_supported(); 2708 2709 private static native boolean native_is_gnss_configuration_supported(); 2710 2711 private static native void native_init_once(); 2712 2713 private native boolean native_init(); 2714 2715 private native void native_cleanup(); 2716 2717 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval, 2718 int preferred_accuracy, int preferred_time, boolean lowPowerMode); 2719 2720 private native boolean native_start(); 2721 2722 private native boolean native_stop(); 2723 2724 private native void native_delete_aiding_data(int flags); 2725 2726 private native int native_read_nmea(byte[] buffer, int bufferSize); 2727 2728 private native void native_inject_best_location( 2729 int gnssLocationFlags, 2730 double latitudeDegrees, 2731 double longitudeDegrees, 2732 double altitudeMeters, 2733 float speedMetersPerSec, 2734 float bearingDegrees, 2735 float horizontalAccuracyMeters, 2736 float verticalAccuracyMeters, 2737 float speedAccuracyMetersPerSecond, 2738 float bearingAccuracyDegrees, 2739 long timestamp); 2740 2741 private native void native_inject_location(double latitude, double longitude, float accuracy); 2742 2743 // XTRA Support 2744 private native void native_inject_time(long time, long timeReference, int uncertainty); 2745 2746 private native boolean native_supports_xtra(); 2747 2748 private native void native_inject_xtra_data(byte[] data, int length); 2749 2750 // DEBUG Support 2751 private native String native_get_internal_state(); 2752 2753 // AGPS Support 2754 private native void native_agps_data_conn_open(String apn, int apnIpType); 2755 2756 private native void native_agps_data_conn_closed(); 2757 2758 private native void native_agps_data_conn_failed(); 2759 2760 private native void native_agps_ni_message(byte[] msg, int length); 2761 2762 private native void native_set_agps_server(int type, String hostname, int port); 2763 2764 // Network-initiated (NI) Support 2765 private native void native_send_ni_response(int notificationId, int userResponse); 2766 2767 // AGPS ril suport 2768 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc, 2769 int lac, int cid); 2770 2771 private native void native_agps_set_id(int type, String setid); 2772 2773 private native void native_update_network_state(boolean connected, int type, 2774 boolean roaming, boolean available, String extraInfo, String defaultAPN); 2775 2776 // GNSS Configuration 2777 private static native boolean native_set_supl_version(int version); 2778 2779 private static native boolean native_set_supl_mode(int mode); 2780 2781 private static native boolean native_set_supl_es(int es); 2782 2783 private static native boolean native_set_lpp_profile(int lppProfile); 2784 2785 private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect); 2786 2787 private static native boolean native_set_gps_lock(int gpsLock); 2788 2789 private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn); 2790 2791 private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds); 2792 } 2793 2794