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