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