1 /* 2 * Copyright (C) 2020 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.gnss; 18 19 import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; 20 import static android.content.pm.PackageManager.FEATURE_WATCH; 21 import static android.location.provider.ProviderProperties.ACCURACY_FINE; 22 import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH; 23 24 import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; 25 import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_GSM_CELLID; 26 import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_LTE_CELLID; 27 import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_NR_CELLID; 28 import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 29 import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_IMSI; 30 import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_MSISDN; 31 import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_NONE; 32 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALL; 33 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALMANAC; 34 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_CELLDB_INFO; 35 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_EPHEMERIS; 36 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_HEALTH; 37 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_IONO; 38 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_POSITION; 39 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_RTI; 40 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SADATA; 41 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVDIR; 42 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVSTEER; 43 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_TIME; 44 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_UTC; 45 import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_ASSISTED; 46 import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_BASED; 47 import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_STANDALONE; 48 import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_RECURRENCE_PERIODIC; 49 50 import static java.lang.Math.abs; 51 import static java.lang.Math.max; 52 import static java.util.concurrent.TimeUnit.MILLISECONDS; 53 54 import android.app.AlarmManager; 55 import android.app.AppOpsManager; 56 import android.content.BroadcastReceiver; 57 import android.content.ContentResolver; 58 import android.content.Context; 59 import android.content.Intent; 60 import android.content.IntentFilter; 61 import android.content.pm.PackageManager; 62 import android.database.ContentObserver; 63 import android.location.GnssCapabilities; 64 import android.location.GnssStatus; 65 import android.location.INetInitiatedListener; 66 import android.location.Location; 67 import android.location.LocationListener; 68 import android.location.LocationManager; 69 import android.location.LocationRequest; 70 import android.location.LocationResult; 71 import android.location.provider.ProviderProperties; 72 import android.location.provider.ProviderRequest; 73 import android.location.util.identity.CallerIdentity; 74 import android.os.BatteryStats; 75 import android.os.Bundle; 76 import android.os.Handler; 77 import android.os.PersistableBundle; 78 import android.os.PowerManager; 79 import android.os.RemoteException; 80 import android.os.ServiceManager; 81 import android.os.SystemClock; 82 import android.os.SystemProperties; 83 import android.os.UserHandle; 84 import android.os.WorkSource; 85 import android.os.WorkSource.WorkChain; 86 import android.provider.Settings; 87 import android.telephony.CarrierConfigManager; 88 import android.telephony.CellIdentity; 89 import android.telephony.CellIdentityGsm; 90 import android.telephony.CellIdentityLte; 91 import android.telephony.CellIdentityNr; 92 import android.telephony.CellIdentityWcdma; 93 import android.telephony.CellInfo; 94 import android.telephony.CellInfoGsm; 95 import android.telephony.CellInfoLte; 96 import android.telephony.CellInfoNr; 97 import android.telephony.CellInfoWcdma; 98 import android.telephony.SubscriptionManager; 99 import android.telephony.TelephonyManager; 100 import android.text.TextUtils; 101 import android.text.format.DateUtils; 102 import android.util.Log; 103 import android.util.TimeUtils; 104 105 import com.android.internal.annotations.GuardedBy; 106 import com.android.internal.app.IBatteryStats; 107 import com.android.internal.location.GpsNetInitiatedHandler; 108 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; 109 import com.android.internal.util.FrameworkStatsLog; 110 import com.android.server.FgThread; 111 import com.android.server.location.gnss.GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback; 112 import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback; 113 import com.android.server.location.gnss.hal.GnssNative; 114 import com.android.server.location.injector.Injector; 115 import com.android.server.location.provider.AbstractLocationProvider; 116 117 import java.io.FileDescriptor; 118 import java.io.PrintWriter; 119 import java.util.ArrayList; 120 import java.util.Arrays; 121 import java.util.Collections; 122 import java.util.Comparator; 123 import java.util.HashMap; 124 import java.util.HashSet; 125 import java.util.List; 126 import java.util.Objects; 127 import java.util.Set; 128 import java.util.concurrent.Executors; 129 import java.util.concurrent.TimeUnit; 130 131 /** 132 * A GNSS implementation of LocationProvider used by LocationManager. 133 * 134 * {@hide} 135 */ 136 public class GnssLocationProvider extends AbstractLocationProvider implements 137 InjectNtpTimeCallback, GnssSatelliteBlocklistCallback, GnssNative.BaseCallbacks, 138 GnssNative.LocationCallbacks, GnssNative.SvStatusCallbacks, GnssNative.AGpsCallbacks, 139 GnssNative.PsdsCallbacks, GnssNative.NotificationCallbacks, 140 GnssNative.LocationRequestCallbacks, GnssNative.TimeCallbacks { 141 142 private static final String TAG = "GnssLocationProvider"; 143 144 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 145 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 146 147 private static final ProviderProperties PROPERTIES = new ProviderProperties.Builder() 148 .setHasSatelliteRequirement(true) 149 .setHasAltitudeSupport(true) 150 .setHasSpeedSupport(true) 151 .setHasBearingSupport(true) 152 .setPowerUsage(POWER_USAGE_HIGH) 153 .setAccuracy(ACCURACY_FINE) 154 .build(); 155 156 // The AGPS SUPL mode 157 private static final int AGPS_SUPL_MODE_MSA = 0x02; 158 private static final int AGPS_SUPL_MODE_MSB = 0x01; 159 160 // TCP/IP constants. 161 // Valid TCP/UDP port range is (0, 65535]. 162 private static final int TCP_MIN_PORT = 0; 163 private static final int TCP_MAX_PORT = 0xffff; 164 165 // 1 second, or 1 Hz frequency. 166 private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000; 167 // Default update duration in milliseconds for REQUEST_LOCATION. 168 private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000; 169 // Update duration extension multiplier for emergency REQUEST_LOCATION. 170 private static final int EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER = 3; 171 // maximum length gnss batching may go for (1 day) 172 private static final int MIN_BATCH_INTERVAL_MS = (int) DateUtils.SECOND_IN_MILLIS; 173 private static final long MAX_BATCH_LENGTH_MS = DateUtils.DAY_IN_MILLIS; 174 private static final long MAX_BATCH_TIMESTAMP_DELTA_MS = 500; 175 176 // Threadsafe class to hold stats reported in the Extras Bundle 177 private static class LocationExtras { 178 private int mSvCount; 179 private int mMeanCn0; 180 private int mMaxCn0; 181 private final Bundle mBundle; 182 LocationExtras()183 LocationExtras() { 184 mBundle = new Bundle(); 185 } 186 set(int svCount, int meanCn0, int maxCn0)187 public void set(int svCount, int meanCn0, int maxCn0) { 188 synchronized (this) { 189 mSvCount = svCount; 190 mMeanCn0 = meanCn0; 191 mMaxCn0 = maxCn0; 192 } 193 setBundle(mBundle); 194 } 195 reset()196 public void reset() { 197 set(0, 0, 0); 198 } 199 200 // Also used by outside methods to add to other bundles setBundle(Bundle extras)201 public void setBundle(Bundle extras) { 202 if (extras != null) { 203 synchronized (this) { 204 extras.putInt("satellites", mSvCount); 205 extras.putInt("meanCn0", mMeanCn0); 206 extras.putInt("maxCn0", mMaxCn0); 207 } 208 } 209 } 210 getBundle()211 public Bundle getBundle() { 212 synchronized (this) { 213 return new Bundle(mBundle); 214 } 215 } 216 } 217 218 // stop trying if we do not receive a fix within 60 seconds 219 private static final int NO_FIX_TIMEOUT = 60 * 1000; 220 221 // if the fix interval is below this we leave GPS on, 222 // if above then we cycle the GPS driver. 223 // Typical hot TTTF is ~5 seconds, so 10 seconds seems valid. 224 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000; 225 226 // how long to wait if we have a network error in NTP or PSDS downloading 227 // the initial value of the exponential backoff 228 // current setting - 5 minutes 229 private static final long RETRY_INTERVAL = 5 * 60 * 1000; 230 // how long to wait if we have a network error in NTP or PSDS downloading 231 // the max value of the exponential backoff 232 // current setting - 4 hours 233 private static final long MAX_RETRY_INTERVAL = 4 * 60 * 60 * 1000; 234 235 // Timeout when holding wakelocks for downloading PSDS data. 236 private static final long DOWNLOAD_PSDS_DATA_TIMEOUT_MS = 60 * 1000; 237 private static final long WAKELOCK_TIMEOUT_MILLIS = 30 * 1000; 238 239 // threshold for delay in GNSS engine turning off before warning & error 240 private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000; 241 private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000; 242 243 private final Object mLock = new Object(); 244 245 private final Context mContext; 246 private final Handler mHandler; 247 248 private final GnssNative mGnssNative; 249 250 @GuardedBy("mLock") 251 private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL, 252 MAX_RETRY_INTERVAL); 253 254 // True if we are enabled 255 @GuardedBy("mLock") 256 private boolean mGpsEnabled; 257 258 @GuardedBy("mLock") 259 private boolean mBatchingEnabled; 260 261 @GuardedBy("mLock") 262 private boolean mAutomotiveSuspend; 263 264 private boolean mShutdown; 265 private boolean mStarted; 266 private boolean mBatchingStarted; 267 private AlarmManager.OnAlarmListener mBatchingAlarm; 268 private long mStartedChangedElapsedRealtime; 269 private int mFixInterval = 1000; 270 271 private ProviderRequest mProviderRequest; 272 273 private int mPositionMode; 274 private GnssPositionMode mLastPositionMode; 275 276 // for calculating time to first fix 277 private long mFixRequestTime = 0; 278 // time to first fix for most recent session 279 private int mTimeToFirstFix = 0; 280 // time we received our last fix 281 private long mLastFixTime; 282 283 private final WorkSource mClientSource = new WorkSource(); 284 285 // true if PSDS is supported 286 private boolean mSupportsPsds; 287 private final Object mPsdsPeriodicDownloadToken = new Object(); 288 @GuardedBy("mLock") 289 private final PowerManager.WakeLock mDownloadPsdsWakeLock; 290 @GuardedBy("mLock") 291 private final Set<Integer> mPendingDownloadPsdsTypes = new HashSet<>(); 292 293 /** 294 * Properties loaded from PROPERTIES_FILE. 295 * It must be accessed only inside {@link #mHandler}. 296 */ 297 private final GnssConfiguration mGnssConfiguration; 298 299 private String mSuplServerHost; 300 private int mSuplServerPort = TCP_MIN_PORT; 301 private String mC2KServerHost; 302 private int mC2KServerPort; 303 private boolean mSuplEsEnabled = false; 304 305 private final LocationExtras mLocationExtras = new LocationExtras(); 306 private final NtpTimeHelper mNtpTimeHelper; 307 private final GnssSatelliteBlocklistHelper mGnssSatelliteBlocklistHelper; 308 309 // Available only on GNSS HAL 2.0 implementations and later. 310 private GnssVisibilityControl mGnssVisibilityControl; 311 312 private final GnssNetworkConnectivityHandler mNetworkConnectivityHandler; 313 private final GpsNetInitiatedHandler mNIHandler; 314 315 // Wakelocks 316 private final PowerManager.WakeLock mWakeLock; 317 318 private final AlarmManager mAlarmManager; 319 private final AlarmManager.OnAlarmListener mWakeupListener = this::startNavigating; 320 private final AlarmManager.OnAlarmListener mTimeoutListener = this::hibernate; 321 322 private final AppOpsManager mAppOps; 323 private final IBatteryStats mBatteryStats; 324 325 @GuardedBy("mLock") 326 private final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0); 327 328 // GNSS Metrics 329 private final GnssMetrics mGnssMetrics; 330 331 /** 332 * Implements {@link GnssSatelliteBlocklistCallback#onUpdateSatelliteBlocklist}. 333 */ 334 @Override onUpdateSatelliteBlocklist(int[] constellations, int[] svids)335 public void onUpdateSatelliteBlocklist(int[] constellations, int[] svids) { 336 mHandler.post(() -> mGnssConfiguration.setSatelliteBlocklist(constellations, svids)); 337 mGnssMetrics.resetConstellationTypes(); 338 } 339 subscriptionOrCarrierConfigChanged()340 private void subscriptionOrCarrierConfigChanged() { 341 if (DEBUG) Log.d(TAG, "received SIM related action: "); 342 TelephonyManager phone = (TelephonyManager) 343 mContext.getSystemService(Context.TELEPHONY_SERVICE); 344 CarrierConfigManager configManager = (CarrierConfigManager) 345 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 346 int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId(); 347 if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { 348 phone = phone.createForSubscriptionId(ddSubId); 349 } 350 String mccMnc = phone.getSimOperator(); 351 boolean isKeepLppProfile = false; 352 if (!TextUtils.isEmpty(mccMnc)) { 353 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc); 354 if (configManager != null) { 355 PersistableBundle b = SubscriptionManager.isValidSubscriptionId(ddSubId) 356 ? configManager.getConfigForSubId(ddSubId) : null; 357 if (b != null) { 358 isKeepLppProfile = 359 b.getBoolean(CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL); 360 } 361 } 362 if (isKeepLppProfile) { 363 // load current properties for the carrier of ddSubId 364 mGnssConfiguration.loadPropertiesFromCarrierConfig(/* inEmergency= */ false, 365 /* activeSubId= */ -1); 366 String lpp_profile = mGnssConfiguration.getLppProfile(); 367 // set the persist property LPP_PROFILE for the value 368 if (lpp_profile != null) { 369 SystemProperties.set(GnssConfiguration.LPP_PROFILE, lpp_profile); 370 } 371 } else { 372 // reset the persist property 373 SystemProperties.set(GnssConfiguration.LPP_PROFILE, ""); 374 } 375 reloadGpsProperties(); 376 } else { 377 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available"); 378 // Reload gnss config for no SIM case 379 mGnssConfiguration.reloadGpsProperties(); 380 } 381 } 382 reloadGpsProperties()383 private void reloadGpsProperties() { 384 mGnssConfiguration.reloadGpsProperties(); 385 setSuplHostPort(); 386 // TODO: we should get rid of C2K specific setting. 387 mC2KServerHost = mGnssConfiguration.getC2KHost(); 388 mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT); 389 mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec()); 390 mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1; 391 mNIHandler.setSuplEsEnabled(mSuplEsEnabled); 392 if (mGnssVisibilityControl != null) { 393 mGnssVisibilityControl.onConfigurationUpdated(mGnssConfiguration); 394 } 395 } 396 GnssLocationProvider(Context context, Injector injector, GnssNative gnssNative, GnssMetrics gnssMetrics)397 public GnssLocationProvider(Context context, Injector injector, GnssNative gnssNative, 398 GnssMetrics gnssMetrics) { 399 super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES, 400 Collections.emptySet()); 401 402 mContext = context; 403 mGnssNative = gnssNative; 404 mGnssMetrics = gnssMetrics; 405 406 // Create a wake lock 407 PowerManager powerManager = Objects.requireNonNull( 408 mContext.getSystemService(PowerManager.class)); 409 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*location*:" + TAG); 410 mWakeLock.setReferenceCounted(true); 411 412 // Create a separate wake lock for psds downloader as it may be released due to timeout. 413 mDownloadPsdsWakeLock = powerManager.newWakeLock( 414 PowerManager.PARTIAL_WAKE_LOCK, "*location*:PsdsDownload"); 415 mDownloadPsdsWakeLock.setReferenceCounted(true); 416 417 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 418 419 // App ops service to keep track of who is accessing the GPS 420 mAppOps = mContext.getSystemService(AppOpsManager.class); 421 422 // Battery statistics service to be notified when GPS turns on or off 423 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 424 BatteryStats.SERVICE_NAME)); 425 426 // Construct internal handler 427 mHandler = FgThread.getHandler(); 428 429 // Load GPS configuration and register listeners in the background: 430 // some operations, such as opening files and registering broadcast receivers, can take a 431 // relative long time, so the ctor() is kept to create objects needed by this instance, 432 // while IO initialization and registration is delegated to our internal handler 433 // this approach is just fine because events are posted to our handler anyway 434 mGnssConfiguration = mGnssNative.getConfiguration(); 435 // Create a GPS net-initiated handler (also needed by handleInitialize) 436 GpsNetInitiatedHandler.EmergencyCallCallback emergencyCallCallback = 437 new GpsNetInitiatedHandler.EmergencyCallCallback() { 438 439 @Override 440 public void onEmergencyCallStart(int subId) { 441 if (!mGnssConfiguration.isActiveSimEmergencySuplEnabled()) { 442 return; 443 } 444 mHandler.post(() -> mGnssConfiguration.reloadGpsProperties( 445 mNIHandler.getInEmergency(), subId)); 446 } 447 448 @Override 449 public void onEmergencyCallEnd() { 450 if (!mGnssConfiguration.isActiveSimEmergencySuplEnabled()) { 451 return; 452 } 453 mHandler.postDelayed(() -> mGnssConfiguration.reloadGpsProperties( 454 /* inEmergency= */ false, 455 SubscriptionManager.getDefaultDataSubscriptionId()), 456 TimeUnit.SECONDS.toMillis(mGnssConfiguration.getEsExtensionSec())); 457 } 458 }; 459 mNIHandler = new GpsNetInitiatedHandler(context, 460 mNetInitiatedListener, 461 emergencyCallCallback, 462 mSuplEsEnabled); 463 // Trigger PSDS data download when the network comes up after booting. 464 mPendingDownloadPsdsTypes.add(GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX); 465 mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context, 466 GnssLocationProvider.this::onNetworkAvailable, 467 mHandler.getLooper(), mNIHandler); 468 469 mNtpTimeHelper = new NtpTimeHelper(mContext, mHandler.getLooper(), this); 470 mGnssSatelliteBlocklistHelper = 471 new GnssSatelliteBlocklistHelper(mContext, 472 mHandler.getLooper(), this); 473 474 setAllowed(true); 475 476 mGnssNative.addBaseCallbacks(this); 477 mGnssNative.addLocationCallbacks(this); 478 mGnssNative.addSvStatusCallbacks(this); 479 mGnssNative.setAGpsCallbacks(this); 480 mGnssNative.setPsdsCallbacks(this); 481 mGnssNative.setNotificationCallbacks(this); 482 mGnssNative.setLocationRequestCallbacks(this); 483 mGnssNative.setTimeCallbacks(this); 484 } 485 486 /** Called when system is ready. */ onSystemReady()487 public synchronized void onSystemReady() { 488 mContext.registerReceiverAsUser(new BroadcastReceiver() { 489 @Override 490 public void onReceive(Context context, Intent intent) { 491 if (getSendingUserId() == UserHandle.USER_ALL) { 492 mShutdown = true; 493 updateEnabled(); 494 } 495 } 496 }, UserHandle.ALL, new IntentFilter(Intent.ACTION_SHUTDOWN), null, mHandler); 497 498 mContext.getContentResolver().registerContentObserver( 499 Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), 500 true, 501 new ContentObserver(mHandler) { 502 @Override 503 public void onChange(boolean selfChange) { 504 updateEnabled(); 505 } 506 }, UserHandle.USER_ALL); 507 508 mHandler.post(this::handleInitialize); 509 mHandler.post(mGnssSatelliteBlocklistHelper::updateSatelliteBlocklist); 510 } 511 handleInitialize()512 private void handleInitialize() { 513 if (mGnssNative.isGnssVisibilityControlSupported()) { 514 mGnssVisibilityControl = new GnssVisibilityControl(mContext, mHandler.getLooper(), 515 mNIHandler); 516 } 517 518 // load default GPS configuration 519 // (this configuration might change in the future based on SIM changes) 520 reloadGpsProperties(); 521 522 // listen for events 523 IntentFilter intentFilter = new IntentFilter(); 524 intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 525 intentFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); 526 mContext.registerReceiver(new BroadcastReceiver() { 527 @Override 528 public void onReceive(Context context, Intent intent) { 529 String action = intent.getAction(); 530 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action); 531 if (action == null) { 532 return; 533 } 534 535 switch (action) { 536 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: 537 case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: 538 subscriptionOrCarrierConfigChanged(); 539 break; 540 } 541 } 542 }, intentFilter, null, mHandler); 543 544 mNetworkConnectivityHandler.registerNetworkCallbacks(); 545 546 // permanently passively listen to all network locations 547 LocationManager locationManager = Objects.requireNonNull( 548 mContext.getSystemService(LocationManager.class)); 549 if (locationManager.getAllProviders().contains(LocationManager.NETWORK_PROVIDER)) { 550 locationManager.requestLocationUpdates( 551 LocationManager.NETWORK_PROVIDER, 552 new LocationRequest.Builder(LocationRequest.PASSIVE_INTERVAL) 553 .setMinUpdateIntervalMillis(0) 554 .setHiddenFromAppOps(true) 555 .build(), 556 DIRECT_EXECUTOR, 557 this::injectLocation); 558 } 559 560 updateEnabled(); 561 } 562 563 /** 564 * Implements {@link InjectNtpTimeCallback#injectTime} 565 */ 566 @Override injectTime(long time, long timeReference, int uncertainty)567 public void injectTime(long time, long timeReference, int uncertainty) { 568 mGnssNative.injectTime(time, timeReference, uncertainty); 569 } 570 571 /** 572 * Implements {@link GnssNetworkConnectivityHandler.GnssNetworkListener#onNetworkAvailable()} 573 */ onNetworkAvailable()574 private void onNetworkAvailable() { 575 mNtpTimeHelper.onNetworkAvailable(); 576 // Download only if supported, (prevents an unnecessary on-boot download) 577 if (mSupportsPsds) { 578 synchronized (mLock) { 579 for (int psdsType : mPendingDownloadPsdsTypes) { 580 postWithWakeLockHeld(() -> handleDownloadPsdsData(psdsType)); 581 } 582 mPendingDownloadPsdsTypes.clear(); 583 } 584 } 585 } 586 handleRequestLocation(boolean independentFromGnss, boolean isUserEmergency)587 private void handleRequestLocation(boolean independentFromGnss, boolean isUserEmergency) { 588 if (isRequestLocationRateLimited()) { 589 if (DEBUG) { 590 Log.d(TAG, "RequestLocation is denied due to too frequent requests."); 591 } 592 return; 593 } 594 ContentResolver resolver = mContext.getContentResolver(); 595 long durationMillis = Settings.Global.getLong( 596 resolver, 597 Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS, 598 LOCATION_UPDATE_DURATION_MILLIS); 599 if (durationMillis == 0) { 600 Log.i(TAG, "GNSS HAL location request is disabled by Settings."); 601 return; 602 } 603 604 LocationManager locationManager = (LocationManager) mContext.getSystemService( 605 Context.LOCATION_SERVICE); 606 String provider; 607 LocationListener locationListener; 608 LocationRequest.Builder locationRequest = new LocationRequest.Builder( 609 LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS).setMaxUpdates(1); 610 611 if (independentFromGnss) { 612 // For fast GNSS TTFF - we use an empty listener because we will rely on the passive 613 // network listener to actually inject the location. this prevents double injection 614 provider = LocationManager.NETWORK_PROVIDER; 615 locationListener = location -> { }; 616 locationRequest.setQuality(LocationRequest.QUALITY_LOW_POWER); 617 } else { 618 // For Device-Based Hybrid (E911) 619 provider = LocationManager.FUSED_PROVIDER; 620 locationListener = this::injectBestLocation; 621 locationRequest.setQuality(LocationRequest.QUALITY_HIGH_ACCURACY); 622 } 623 624 // Ignore location settings if in emergency mode. This is only allowed for 625 // isUserEmergency request (introduced in HAL v2.0), or HAL v1.1. 626 if (mNIHandler.getInEmergency()) { 627 GnssConfiguration.HalInterfaceVersion halVersion = 628 mGnssConfiguration.getHalInterfaceVersion(); 629 if (isUserEmergency || halVersion.mMajor < 2) { 630 locationRequest.setLocationSettingsIgnored(true); 631 durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER; 632 } 633 } 634 635 locationRequest.setDurationMillis(durationMillis); 636 637 Log.i(TAG, 638 String.format( 639 "GNSS HAL Requesting location updates from %s provider for %d millis.", 640 provider, durationMillis)); 641 642 if (locationManager.getProvider(provider) != null) { 643 locationManager.requestLocationUpdates(provider, locationRequest.build(), 644 DIRECT_EXECUTOR, locationListener); 645 } 646 } 647 injectBestLocation(Location location)648 private void injectBestLocation(Location location) { 649 if (DEBUG) { 650 Log.d(TAG, "injectBestLocation: " + location); 651 } 652 653 if (location.isMock()) { 654 return; 655 } 656 657 mGnssNative.injectBestLocation(location); 658 } 659 660 /** Returns true if the location request is too frequent. */ isRequestLocationRateLimited()661 private boolean isRequestLocationRateLimited() { 662 // TODO: implement exponential backoff. 663 return false; 664 } 665 handleDownloadPsdsData(int psdsType)666 private void handleDownloadPsdsData(int psdsType) { 667 if (!mSupportsPsds) { 668 // native code reports psds not supported, don't try 669 Log.d(TAG, "handleDownloadPsdsData() called when PSDS not supported"); 670 return; 671 } 672 if (!mNetworkConnectivityHandler.isDataNetworkConnected()) { 673 // try again when network is up 674 synchronized (mLock) { 675 mPendingDownloadPsdsTypes.add(psdsType); 676 } 677 return; 678 } 679 synchronized (mLock) { 680 // hold wake lock while task runs 681 mDownloadPsdsWakeLock.acquire(DOWNLOAD_PSDS_DATA_TIMEOUT_MS); 682 } 683 Log.i(TAG, "WakeLock acquired by handleDownloadPsdsData()"); 684 Executors.newSingleThreadExecutor().execute(() -> { 685 GnssPsdsDownloader psdsDownloader = new GnssPsdsDownloader( 686 mGnssConfiguration.getProperties()); 687 byte[] data = psdsDownloader.downloadPsdsData(psdsType); 688 if (data != null) { 689 mHandler.post(() -> { 690 FrameworkStatsLog.write(FrameworkStatsLog.GNSS_PSDS_DOWNLOAD_REPORTED, 691 psdsType); 692 if (DEBUG) Log.d(TAG, "calling native_inject_psds_data"); 693 mGnssNative.injectPsdsData(data, data.length, psdsType); 694 synchronized (mLock) { 695 mPsdsBackOff.reset(); 696 } 697 }); 698 PackageManager pm = mContext.getPackageManager(); 699 if (pm != null && pm.hasSystemFeature(FEATURE_WATCH) 700 && psdsType == GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX 701 && mGnssConfiguration.isPsdsPeriodicDownloadEnabled()) { 702 if (DEBUG) Log.d(TAG, "scheduling next long term Psds download"); 703 mHandler.removeCallbacksAndMessages(mPsdsPeriodicDownloadToken); 704 mHandler.postDelayed(() -> handleDownloadPsdsData(psdsType), 705 mPsdsPeriodicDownloadToken, 706 GnssPsdsDownloader.PSDS_INTERVAL); 707 } 708 } else { 709 // Try download PSDS data again later according to backoff time. 710 // Since this is delayed and not urgent, we do not hold a wake lock here. 711 // The arg2 below should not be 1 otherwise the wakelock will be under-locked. 712 long backoffMillis; 713 synchronized (mLock) { 714 backoffMillis = mPsdsBackOff.nextBackoffMillis(); 715 } 716 mHandler.postDelayed(() -> handleDownloadPsdsData(psdsType), backoffMillis); 717 } 718 719 // Release wake lock held by task, synchronize on mLock in case multiple 720 // download tasks overrun. 721 synchronized (mLock) { 722 if (mDownloadPsdsWakeLock.isHeld()) { 723 // This wakelock may have time-out, if a timeout was specified. 724 // Catch (and ignore) any timeout exceptions. 725 mDownloadPsdsWakeLock.release(); 726 if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadPsdsData()"); 727 } else { 728 Log.e(TAG, "WakeLock expired before release in " 729 + "handleDownloadPsdsData()"); 730 } 731 } 732 }); 733 } 734 injectLocation(Location location)735 private void injectLocation(Location location) { 736 if (!location.isMock()) { 737 mGnssNative.injectLocation(location); 738 } 739 } 740 setSuplHostPort()741 private void setSuplHostPort() { 742 mSuplServerHost = mGnssConfiguration.getSuplHost(); 743 mSuplServerPort = mGnssConfiguration.getSuplPort(TCP_MIN_PORT); 744 if (mSuplServerHost != null 745 && mSuplServerPort > TCP_MIN_PORT 746 && mSuplServerPort <= TCP_MAX_PORT) { 747 mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, 748 mSuplServerHost, mSuplServerPort); 749 } 750 } 751 752 /** 753 * Checks what SUPL mode to use, according to the AGPS mode as well as the 754 * allowed mode from properties. 755 * 756 * @param agpsEnabled whether AGPS is enabled by settings value 757 * @return SUPL mode (MSA vs MSB vs STANDALONE) 758 */ getSuplMode(boolean agpsEnabled)759 private int getSuplMode(boolean agpsEnabled) { 760 if (agpsEnabled) { 761 int suplMode = mGnssConfiguration.getSuplMode(0); 762 if (suplMode == 0) { 763 return GNSS_POSITION_MODE_STANDALONE; 764 } 765 766 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor 767 // such mode when it is available 768 if (mGnssNative.getCapabilities().hasMsb() && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { 769 return GNSS_POSITION_MODE_MS_BASED; 770 } 771 } 772 return GNSS_POSITION_MODE_STANDALONE; 773 } 774 setGpsEnabled(boolean enabled)775 private void setGpsEnabled(boolean enabled) { 776 synchronized (mLock) { 777 mGpsEnabled = enabled; 778 } 779 } 780 781 /** 782 * Set whether the GnssLocationProvider is suspended. This method was added to help support 783 * power management use cases on automotive devices. 784 */ setAutomotiveGnssSuspended(boolean suspended)785 public void setAutomotiveGnssSuspended(boolean suspended) { 786 synchronized (mLock) { 787 mAutomotiveSuspend = suspended; 788 } 789 mHandler.post(this::updateEnabled); 790 } 791 792 /** 793 * Return whether the GnssLocationProvider is suspended or not. This method was added to help 794 * support power management use cases on automotive devices. 795 */ isAutomotiveGnssSuspended()796 public boolean isAutomotiveGnssSuspended() { 797 synchronized (mLock) { 798 return mAutomotiveSuspend && !mGpsEnabled; 799 } 800 } 801 handleEnable()802 private void handleEnable() { 803 if (DEBUG) Log.d(TAG, "handleEnable"); 804 805 boolean inited = mGnssNative.init(); 806 807 if (inited) { 808 setGpsEnabled(true); 809 mSupportsPsds = mGnssNative.isPsdsSupported(); 810 811 // TODO: remove the following native calls if we can make sure they are redundant. 812 if (mSuplServerHost != null) { 813 mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, 814 mSuplServerHost, mSuplServerPort); 815 } 816 if (mC2KServerHost != null) { 817 mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K, 818 mC2KServerHost, mC2KServerPort); 819 } 820 821 mBatchingEnabled = mGnssNative.initBatching() && mGnssNative.getBatchSize() > 1; 822 if (mGnssVisibilityControl != null) { 823 mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ true); 824 } 825 } else { 826 setGpsEnabled(false); 827 Log.w(TAG, "Failed to enable location provider"); 828 } 829 } 830 handleDisable()831 private void handleDisable() { 832 if (DEBUG) Log.d(TAG, "handleDisable"); 833 834 setGpsEnabled(false); 835 updateClientUids(new WorkSource()); 836 stopNavigating(); 837 stopBatching(); 838 839 if (mGnssVisibilityControl != null) { 840 mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ false); 841 } 842 // do this before releasing wakelock 843 mGnssNative.cleanupBatching(); 844 mGnssNative.cleanup(); 845 } 846 updateEnabled()847 private void updateEnabled() { 848 // Generally follow location setting for current user 849 boolean enabled = mContext.getSystemService(LocationManager.class) 850 .isLocationEnabledForUser(UserHandle.CURRENT); 851 852 // .. but enable anyway, if there's an active bypass request (e.g. ELS or ADAS) 853 enabled |= (mProviderRequest != null 854 && mProviderRequest.isActive() 855 && mProviderRequest.isBypass()); 856 857 // .. disable if automotive device needs to go into suspend 858 synchronized (mLock) { 859 enabled &= !mAutomotiveSuspend; 860 } 861 862 // ... and, finally, disable anyway, if device is being shut down 863 enabled &= !mShutdown; 864 865 if (enabled == isGpsEnabled()) { 866 return; 867 } 868 869 if (enabled) { 870 handleEnable(); 871 } else { 872 handleDisable(); 873 } 874 } 875 isGpsEnabled()876 private boolean isGpsEnabled() { 877 synchronized (mLock) { 878 return mGpsEnabled; 879 } 880 } 881 882 /** 883 * Returns the hardware batch size available in this hardware implementation. If the available 884 * size is variable, for example, based on other operations consuming memory, this is the 885 * minimum size guaranteed to be available for batching operations. 886 */ getBatchSize()887 public int getBatchSize() { 888 return mGnssNative.getBatchSize(); 889 } 890 891 @Override onFlush(Runnable listener)892 protected void onFlush(Runnable listener) { 893 boolean added = false; 894 synchronized (mLock) { 895 if (mBatchingEnabled) { 896 added = mFlushListeners.add(listener); 897 } 898 } 899 if (!added) { 900 listener.run(); 901 } else { 902 mGnssNative.flushBatch(); 903 } 904 } 905 906 @Override onSetRequest(ProviderRequest request)907 public void onSetRequest(ProviderRequest request) { 908 mProviderRequest = request; 909 updateEnabled(); 910 updateRequirements(); 911 } 912 913 // Called when the requirements for GPS may have changed updateRequirements()914 private void updateRequirements() { 915 if (mProviderRequest == null || mProviderRequest.getWorkSource() == null) { 916 return; 917 } 918 919 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest); 920 if (mProviderRequest.isActive() && isGpsEnabled()) { 921 // update client uids 922 updateClientUids(mProviderRequest.getWorkSource()); 923 924 if (mProviderRequest.getIntervalMillis() <= Integer.MAX_VALUE) { 925 mFixInterval = (int) mProviderRequest.getIntervalMillis(); 926 } else { 927 Log.w(TAG, "interval overflow: " + mProviderRequest.getIntervalMillis()); 928 mFixInterval = Integer.MAX_VALUE; 929 } 930 931 int batchIntervalMs = max(mFixInterval, MIN_BATCH_INTERVAL_MS); 932 long batchLengthMs = Math.min(mProviderRequest.getMaxUpdateDelayMillis(), 933 MAX_BATCH_LENGTH_MS); 934 935 // apply request to GPS engine 936 if (mBatchingEnabled && batchLengthMs / 2 >= batchIntervalMs) { 937 stopNavigating(); 938 mFixInterval = batchIntervalMs; 939 startBatching(batchLengthMs); 940 } else { 941 stopBatching(); 942 943 if (mStarted && mGnssNative.getCapabilities().hasScheduling()) { 944 // change period and/or lowPowerMode 945 if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, 946 mFixInterval, mProviderRequest.isLowPower())) { 947 Log.e(TAG, "set_position_mode failed in updateRequirements"); 948 } 949 } else if (!mStarted) { 950 // start GPS 951 startNavigating(); 952 } else { 953 // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING 954 mAlarmManager.cancel(mTimeoutListener); 955 if (mFixInterval >= NO_FIX_TIMEOUT) { 956 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 957 // and our fix interval is not short 958 mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, 959 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG, 960 mTimeoutListener, mHandler); 961 } 962 } 963 } 964 } else { 965 updateClientUids(new WorkSource()); 966 stopNavigating(); 967 stopBatching(); 968 } 969 } 970 setPositionMode(int mode, int recurrence, int minInterval, boolean lowPowerMode)971 private boolean setPositionMode(int mode, int recurrence, int minInterval, 972 boolean lowPowerMode) { 973 GnssPositionMode positionMode = new GnssPositionMode(mode, recurrence, minInterval, 974 0, 0, lowPowerMode); 975 if (mLastPositionMode != null && mLastPositionMode.equals(positionMode)) { 976 return true; 977 } 978 979 boolean result = mGnssNative.setPositionMode(mode, recurrence, minInterval, 0, 0, 980 lowPowerMode); 981 if (result) { 982 mLastPositionMode = positionMode; 983 } else { 984 mLastPositionMode = null; 985 } 986 return result; 987 } 988 updateClientUids(WorkSource source)989 private void updateClientUids(WorkSource source) { 990 if (source.equals(mClientSource)) { 991 return; 992 } 993 994 // (1) Inform BatteryStats that the list of IDs we're tracking changed. 995 try { 996 mBatteryStats.noteGpsChanged(mClientSource, source); 997 } catch (RemoteException e) { 998 Log.w(TAG, "RemoteException", e); 999 } 1000 1001 // (2) Inform AppOps service about the list of changes to UIDs. 1002 1003 // TODO: this doesn't seem correct, work chain attribution tag != package? 1004 List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source); 1005 if (diffs != null) { 1006 List<WorkChain> newChains = diffs[0]; 1007 List<WorkChain> goneChains = diffs[1]; 1008 1009 if (newChains != null) { 1010 for (WorkChain newChain : newChains) { 1011 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(), 1012 newChain.getAttributionTag()); 1013 } 1014 } 1015 1016 if (goneChains != null) { 1017 for (WorkChain goneChain : goneChains) { 1018 mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(), 1019 goneChain.getAttributionTag()); 1020 } 1021 } 1022 1023 mClientSource.transferWorkChains(source); 1024 } 1025 1026 // Update the flat UIDs and names list and inform app-ops of all changes. 1027 // TODO: why is GnssLocationProvider the only component using these deprecated APIs? 1028 WorkSource[] changes = mClientSource.setReturningDiffs(source); 1029 if (changes != null) { 1030 WorkSource newWork = changes[0]; 1031 WorkSource goneWork = changes[1]; 1032 1033 // Update sources that were not previously tracked. 1034 if (newWork != null) { 1035 for (int i = 0; i < newWork.size(); i++) { 1036 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, 1037 newWork.getUid(i), newWork.getPackageName(i)); 1038 } 1039 } 1040 1041 // Update sources that are no longer tracked. 1042 if (goneWork != null) { 1043 for (int i = 0; i < goneWork.size(); i++) { 1044 mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.getUid(i), 1045 goneWork.getPackageName(i)); 1046 } 1047 } 1048 } 1049 } 1050 1051 @Override onExtraCommand(int uid, int pid, String command, Bundle extras)1052 public void onExtraCommand(int uid, int pid, String command, Bundle extras) { 1053 if ("delete_aiding_data".equals(command)) { 1054 deleteAidingData(extras); 1055 } else if ("force_time_injection".equals(command)) { 1056 requestUtcTime(); 1057 } else if ("force_psds_injection".equals(command)) { 1058 if (mSupportsPsds) { 1059 postWithWakeLockHeld(() -> handleDownloadPsdsData( 1060 GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX)); 1061 } 1062 } else if ("request_power_stats".equals(command)) { 1063 mGnssNative.requestPowerStats(); 1064 } else { 1065 Log.w(TAG, "sendExtraCommand: unknown command " + command); 1066 } 1067 } 1068 deleteAidingData(Bundle extras)1069 private void deleteAidingData(Bundle extras) { 1070 int flags; 1071 1072 if (extras == null) { 1073 flags = GNSS_AIDING_TYPE_ALL; 1074 } else { 1075 flags = 0; 1076 if (extras.getBoolean("ephemeris")) flags |= GNSS_AIDING_TYPE_EPHEMERIS; 1077 if (extras.getBoolean("almanac")) flags |= GNSS_AIDING_TYPE_ALMANAC; 1078 if (extras.getBoolean("position")) flags |= GNSS_AIDING_TYPE_POSITION; 1079 if (extras.getBoolean("time")) flags |= GNSS_AIDING_TYPE_TIME; 1080 if (extras.getBoolean("iono")) flags |= GNSS_AIDING_TYPE_IONO; 1081 if (extras.getBoolean("utc")) flags |= GNSS_AIDING_TYPE_UTC; 1082 if (extras.getBoolean("health")) flags |= GNSS_AIDING_TYPE_HEALTH; 1083 if (extras.getBoolean("svdir")) flags |= GNSS_AIDING_TYPE_SVDIR; 1084 if (extras.getBoolean("svsteer")) flags |= GNSS_AIDING_TYPE_SVSTEER; 1085 if (extras.getBoolean("sadata")) flags |= GNSS_AIDING_TYPE_SADATA; 1086 if (extras.getBoolean("rti")) flags |= GNSS_AIDING_TYPE_RTI; 1087 if (extras.getBoolean("celldb-info")) flags |= GNSS_AIDING_TYPE_CELLDB_INFO; 1088 if (extras.getBoolean("all")) flags |= GNSS_AIDING_TYPE_ALL; 1089 } 1090 1091 if (flags != 0) { 1092 mGnssNative.deleteAidingData(flags); 1093 } 1094 } 1095 startNavigating()1096 private void startNavigating() { 1097 if (!mStarted) { 1098 if (DEBUG) Log.d(TAG, "startNavigating"); 1099 mTimeToFirstFix = 0; 1100 mLastFixTime = 0; 1101 setStarted(true); 1102 mPositionMode = GNSS_POSITION_MODE_STANDALONE; 1103 1104 boolean agpsEnabled = 1105 (Settings.Global.getInt(mContext.getContentResolver(), 1106 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0); 1107 mPositionMode = getSuplMode(agpsEnabled); 1108 1109 if (DEBUG) { 1110 String mode; 1111 1112 switch (mPositionMode) { 1113 case GNSS_POSITION_MODE_STANDALONE: 1114 mode = "standalone"; 1115 break; 1116 case GNSS_POSITION_MODE_MS_ASSISTED: 1117 mode = "MS_ASSISTED"; 1118 break; 1119 case GNSS_POSITION_MODE_MS_BASED: 1120 mode = "MS_BASED"; 1121 break; 1122 default: 1123 mode = "unknown"; 1124 break; 1125 } 1126 Log.d(TAG, "setting position_mode to " + mode); 1127 } 1128 1129 int interval = mGnssNative.getCapabilities().hasScheduling() ? mFixInterval : 1000; 1130 if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, 1131 interval, mProviderRequest.isLowPower())) { 1132 setStarted(false); 1133 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1134 return; 1135 } 1136 if (!mGnssNative.start()) { 1137 setStarted(false); 1138 Log.e(TAG, "native_start failed in startNavigating()"); 1139 return; 1140 } 1141 1142 // reset SV count to zero 1143 mLocationExtras.reset(); 1144 mFixRequestTime = SystemClock.elapsedRealtime(); 1145 if (!mGnssNative.getCapabilities().hasScheduling()) { 1146 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1147 // and our fix interval is not short 1148 if (mFixInterval >= NO_FIX_TIMEOUT) { 1149 mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, 1150 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG, mTimeoutListener, 1151 mHandler); 1152 } 1153 } 1154 } 1155 } 1156 stopNavigating()1157 private void stopNavigating() { 1158 if (DEBUG) Log.d(TAG, "stopNavigating"); 1159 if (mStarted) { 1160 setStarted(false); 1161 mGnssNative.stop(); 1162 mLastFixTime = 0; 1163 // native_stop() may reset the position mode in hardware. 1164 mLastPositionMode = null; 1165 1166 // reset SV count to zero 1167 mLocationExtras.reset(); 1168 } 1169 mAlarmManager.cancel(mTimeoutListener); 1170 mAlarmManager.cancel(mWakeupListener); 1171 } 1172 startBatching(long batchLengthMs)1173 private void startBatching(long batchLengthMs) { 1174 long batchSize = batchLengthMs / mFixInterval; 1175 1176 if (DEBUG) { 1177 Log.d(TAG, "startBatching " + mFixInterval + " " + batchLengthMs); 1178 } 1179 if (mGnssNative.startBatch(MILLISECONDS.toNanos(mFixInterval), 0, true)) { 1180 mBatchingStarted = true; 1181 1182 if (batchSize < getBatchSize()) { 1183 // if the batch size is smaller than the hardware batch size, use an alarm to flush 1184 // locations as appropriate 1185 mBatchingAlarm = () -> { 1186 boolean flush = false; 1187 synchronized (mLock) { 1188 if (mBatchingAlarm != null) { 1189 flush = true; 1190 mAlarmManager.setExact(ELAPSED_REALTIME_WAKEUP, 1191 SystemClock.elapsedRealtime() + batchLengthMs, TAG, 1192 mBatchingAlarm, FgThread.getHandler()); 1193 } 1194 } 1195 1196 if (flush) { 1197 mGnssNative.flushBatch(); 1198 } 1199 }; 1200 mAlarmManager.setExact(ELAPSED_REALTIME_WAKEUP, 1201 SystemClock.elapsedRealtime() + batchLengthMs, TAG, 1202 mBatchingAlarm, FgThread.getHandler()); 1203 } 1204 } else { 1205 Log.e(TAG, "native_start_batch failed in startBatching()"); 1206 } 1207 } 1208 stopBatching()1209 private void stopBatching() { 1210 if (DEBUG) Log.d(TAG, "stopBatching"); 1211 if (mBatchingStarted) { 1212 if (mBatchingAlarm != null) { 1213 mAlarmManager.cancel(mBatchingAlarm); 1214 mBatchingAlarm = null; 1215 } 1216 mGnssNative.flushBatch(); 1217 mGnssNative.stopBatch(); 1218 mBatchingStarted = false; 1219 } 1220 } 1221 setStarted(boolean started)1222 private void setStarted(boolean started) { 1223 if (mStarted != started) { 1224 mStarted = started; 1225 mStartedChangedElapsedRealtime = SystemClock.elapsedRealtime(); 1226 } 1227 } 1228 hibernate()1229 private void hibernate() { 1230 // stop GPS until our next fix interval arrives 1231 stopNavigating(); 1232 long now = SystemClock.elapsedRealtime(); 1233 mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, now + mFixInterval, TAG, 1234 mWakeupListener, mHandler); 1235 } 1236 handleReportLocation(boolean hasLatLong, Location location)1237 private void handleReportLocation(boolean hasLatLong, Location location) { 1238 if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString()); 1239 1240 location.setExtras(mLocationExtras.getBundle()); 1241 1242 reportLocation(LocationResult.wrap(location).validate()); 1243 1244 if (mStarted) { 1245 mGnssMetrics.logReceivedLocationStatus(hasLatLong); 1246 if (hasLatLong) { 1247 if (location.hasAccuracy()) { 1248 mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy()); 1249 } 1250 if (mTimeToFirstFix > 0) { 1251 int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime); 1252 mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes); 1253 } 1254 } 1255 } else { 1256 // Warn or error about long delayed GNSS engine shutdown as this generally wastes 1257 // power and sends location when not expected. 1258 long locationAfterStartedFalseMillis = 1259 SystemClock.elapsedRealtime() - mStartedChangedElapsedRealtime; 1260 if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS) { 1261 String logMessage = "Unexpected GNSS Location report " 1262 + TimeUtils.formatDuration(locationAfterStartedFalseMillis) 1263 + " after location turned off"; 1264 if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS) { 1265 Log.e(TAG, logMessage); 1266 } else { 1267 Log.w(TAG, logMessage); 1268 } 1269 } 1270 } 1271 1272 mLastFixTime = SystemClock.elapsedRealtime(); 1273 // report time to first fix 1274 if (mTimeToFirstFix == 0 && hasLatLong) { 1275 mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime); 1276 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1277 if (mStarted) { 1278 mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix); 1279 } 1280 } 1281 1282 if (mStarted) { 1283 // For devices that use framework scheduling, a timer may be set to ensure we don't 1284 // spend too much power searching for a location, when the requested update rate is 1285 // slow. 1286 // As we just recievied a location, we'll cancel that timer. 1287 if (!mGnssNative.getCapabilities().hasScheduling() && mFixInterval < NO_FIX_TIMEOUT) { 1288 mAlarmManager.cancel(mTimeoutListener); 1289 } 1290 } 1291 1292 if (!mGnssNative.getCapabilities().hasScheduling() && mStarted 1293 && mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1294 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1295 hibernate(); 1296 } 1297 } 1298 handleReportSvStatus(GnssStatus gnssStatus)1299 private void handleReportSvStatus(GnssStatus gnssStatus) { 1300 // Log CN0 as part of GNSS metrics 1301 mGnssMetrics.logCn0(gnssStatus); 1302 1303 if (VERBOSE) { 1304 Log.v(TAG, "SV count: " + gnssStatus.getSatelliteCount()); 1305 } 1306 1307 int usedInFixCount = 0; 1308 int maxCn0 = 0; 1309 int meanCn0 = 0; 1310 for (int i = 0; i < gnssStatus.getSatelliteCount(); i++) { 1311 if (gnssStatus.usedInFix(i)) { 1312 ++usedInFixCount; 1313 if (gnssStatus.getCn0DbHz(i) > maxCn0) { 1314 maxCn0 = (int) gnssStatus.getCn0DbHz(i); 1315 } 1316 meanCn0 += gnssStatus.getCn0DbHz(i); 1317 mGnssMetrics.logConstellationType(gnssStatus.getConstellationType(i)); 1318 } 1319 } 1320 if (usedInFixCount > 0) { 1321 meanCn0 /= usedInFixCount; 1322 } 1323 // return number of sats used in fix instead of total reported 1324 mLocationExtras.set(usedInFixCount, meanCn0, maxCn0); 1325 1326 mGnssMetrics.logSvStatus(gnssStatus); 1327 } 1328 restartLocationRequest()1329 private void restartLocationRequest() { 1330 if (DEBUG) Log.d(TAG, "restartLocationRequest"); 1331 setStarted(false); 1332 updateRequirements(); 1333 } 1334 1335 //============================================================= 1336 // NI Client support 1337 //============================================================= 1338 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1339 // Sends a response for an NI request to HAL. 1340 @Override 1341 public boolean sendNiResponse(int notificationId, int userResponse) { 1342 // TODO Add Permission check 1343 1344 if (DEBUG) { 1345 Log.d(TAG, "sendNiResponse, notifId: " + notificationId 1346 + ", response: " + userResponse); 1347 } 1348 mGnssNative.sendNiResponse(notificationId, userResponse); 1349 1350 FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED, 1351 FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE, 1352 notificationId, 1353 /* niType= */ 0, 1354 /* needNotify= */ false, 1355 /* needVerify= */ false, 1356 /* privacyOverride= */ false, 1357 /* timeout= */ 0, 1358 /* defaultResponse= */ 0, 1359 /* requestorId= */ null, 1360 /* text= */ null, 1361 /* requestorIdEncoding= */ 0, 1362 /* textEncoding= */ 0, 1363 mSuplEsEnabled, 1364 isGpsEnabled(), 1365 userResponse); 1366 1367 return true; 1368 } 1369 }; 1370 getNetInitiatedListener()1371 public INetInitiatedListener getNetInitiatedListener() { 1372 return mNetInitiatedListener; 1373 } 1374 1375 /** Reports a NI notification. */ reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, int defaultResponse, String requestorId, String text, int requestorIdEncoding, int textEncoding)1376 private void reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, 1377 int defaultResponse, String requestorId, String text, int requestorIdEncoding, 1378 int textEncoding) { 1379 Log.i(TAG, "reportNiNotification: entered"); 1380 Log.i(TAG, "notificationId: " + notificationId 1381 + ", niType: " + niType 1382 + ", notifyFlags: " + notifyFlags 1383 + ", timeout: " + timeout 1384 + ", defaultResponse: " + defaultResponse); 1385 1386 Log.i(TAG, "requestorId: " + requestorId 1387 + ", text: " + text 1388 + ", requestorIdEncoding: " + requestorIdEncoding 1389 + ", textEncoding: " + textEncoding); 1390 1391 GpsNiNotification notification = new GpsNiNotification(); 1392 1393 notification.notificationId = notificationId; 1394 notification.niType = niType; 1395 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 1396 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 1397 notification.privacyOverride = 1398 (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 1399 notification.timeout = timeout; 1400 notification.defaultResponse = defaultResponse; 1401 notification.requestorId = requestorId; 1402 notification.text = text; 1403 notification.requestorIdEncoding = requestorIdEncoding; 1404 notification.textEncoding = textEncoding; 1405 1406 mNIHandler.handleNiNotification(notification); 1407 FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED, 1408 FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_REQUEST, 1409 notification.notificationId, 1410 notification.niType, 1411 notification.needNotify, 1412 notification.needVerify, 1413 notification.privacyOverride, 1414 notification.timeout, 1415 notification.defaultResponse, 1416 notification.requestorId, 1417 notification.text, 1418 notification.requestorIdEncoding, 1419 notification.textEncoding, 1420 mSuplEsEnabled, 1421 isGpsEnabled(), 1422 /* userResponse= */ 0); 1423 } 1424 requestUtcTime()1425 private void requestUtcTime() { 1426 if (DEBUG) Log.d(TAG, "utcTimeRequest"); 1427 postWithWakeLockHeld(mNtpTimeHelper::retrieveAndInjectNtpTime); 1428 } 1429 1430 getCellType(CellInfo ci)1431 private static int getCellType(CellInfo ci) { 1432 if (ci instanceof CellInfoGsm) { 1433 return CellInfo.TYPE_GSM; 1434 } else if (ci instanceof CellInfoWcdma) { 1435 return CellInfo.TYPE_WCDMA; 1436 } else if (ci instanceof CellInfoLte) { 1437 return CellInfo.TYPE_LTE; 1438 } else if (ci instanceof CellInfoNr) { 1439 return CellInfo.TYPE_NR; 1440 } 1441 return CellInfo.TYPE_UNKNOWN; 1442 } 1443 1444 /** 1445 * Extract the CID/CI for GSM/WCDMA/LTE/NR 1446 * 1447 * @return the cell ID or -1 if invalid 1448 */ getCidFromCellIdentity(CellIdentity id)1449 private static long getCidFromCellIdentity(CellIdentity id) { 1450 if (id == null) return -1; 1451 long cid = -1; 1452 switch(id.getType()) { 1453 case CellInfo.TYPE_GSM: cid = ((CellIdentityGsm) id).getCid(); break; 1454 case CellInfo.TYPE_WCDMA: cid = ((CellIdentityWcdma) id).getCid(); break; 1455 case CellInfo.TYPE_LTE: cid = ((CellIdentityLte) id).getCi(); break; 1456 case CellInfo.TYPE_NR: cid = ((CellIdentityNr) id).getNci(); break; 1457 default: break; 1458 } 1459 // If the CID is unreported 1460 if (cid == (id.getType() == CellInfo.TYPE_NR 1461 ? CellInfo.UNAVAILABLE_LONG : CellInfo.UNAVAILABLE)) { 1462 cid = -1; 1463 } 1464 1465 return cid; 1466 } 1467 setRefLocation(int type, CellIdentity ci)1468 private void setRefLocation(int type, CellIdentity ci) { 1469 String mcc_str = ci.getMccString(); 1470 String mnc_str = ci.getMncString(); 1471 int mcc = mcc_str != null ? Integer.parseInt(mcc_str) : CellInfo.UNAVAILABLE; 1472 int mnc = mnc_str != null ? Integer.parseInt(mnc_str) : CellInfo.UNAVAILABLE; 1473 int lac = CellInfo.UNAVAILABLE; 1474 int tac = CellInfo.UNAVAILABLE; 1475 int pcid = CellInfo.UNAVAILABLE; 1476 int arfcn = CellInfo.UNAVAILABLE; 1477 long cid = CellInfo.UNAVAILABLE_LONG; 1478 1479 switch (type) { 1480 case AGPS_REF_LOCATION_TYPE_GSM_CELLID: 1481 CellIdentityGsm cig = (CellIdentityGsm) ci; 1482 cid = cig.getCid(); 1483 lac = cig.getLac(); 1484 break; 1485 case AGPS_REF_LOCATION_TYPE_UMTS_CELLID: 1486 CellIdentityWcdma ciw = (CellIdentityWcdma) ci; 1487 cid = ciw.getCid(); 1488 lac = ciw.getLac(); 1489 break; 1490 case AGPS_REF_LOCATION_TYPE_LTE_CELLID: 1491 CellIdentityLte cil = (CellIdentityLte) ci; 1492 cid = cil.getCi(); 1493 tac = cil.getTac(); 1494 pcid = cil.getPci(); 1495 break; 1496 case AGPS_REF_LOCATION_TYPE_NR_CELLID: 1497 CellIdentityNr cin = (CellIdentityNr) ci; 1498 cid = cin.getNci(); 1499 tac = cin.getTac(); 1500 pcid = cin.getPci(); 1501 arfcn = cin.getNrarfcn(); 1502 break; 1503 default: 1504 } 1505 1506 mGnssNative.setAgpsReferenceLocationCellId( 1507 type, mcc, mnc, lac, cid, tac, pcid, arfcn); 1508 } 1509 requestRefLocation()1510 private void requestRefLocation() { 1511 TelephonyManager phone = (TelephonyManager) 1512 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1513 1514 final int phoneType = phone.getPhoneType(); 1515 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 1516 1517 List<CellInfo> cil = phone.getAllCellInfo(); 1518 if (cil != null) { 1519 HashMap<Integer, CellIdentity> cellIdentityMap = new HashMap<>(); 1520 cil.sort(Comparator.comparingInt( 1521 (CellInfo ci) -> ci.getCellSignalStrength().getAsuLevel()).reversed()); 1522 1523 for (CellInfo ci : cil) { 1524 int status = ci.getCellConnectionStatus(); 1525 if (status == CellInfo.CONNECTION_PRIMARY_SERVING 1526 || status == CellInfo.CONNECTION_SECONDARY_SERVING) { 1527 CellIdentity c = ci.getCellIdentity(); 1528 int t = getCellType(ci); 1529 if (getCidFromCellIdentity(c) != -1 1530 && !cellIdentityMap.containsKey(t)) { 1531 cellIdentityMap.put(t, c); 1532 } 1533 } 1534 } 1535 1536 if (cellIdentityMap.containsKey(CellInfo.TYPE_GSM)) { 1537 setRefLocation(AGPS_REF_LOCATION_TYPE_GSM_CELLID, 1538 cellIdentityMap.get(CellInfo.TYPE_GSM)); 1539 } else if (cellIdentityMap.containsKey(CellInfo.TYPE_WCDMA)) { 1540 setRefLocation(AGPS_REF_LOCATION_TYPE_UMTS_CELLID, 1541 cellIdentityMap.get(CellInfo.TYPE_WCDMA)); 1542 } else if (cellIdentityMap.containsKey(CellInfo.TYPE_LTE)) { 1543 setRefLocation(AGPS_REF_LOCATION_TYPE_LTE_CELLID, 1544 cellIdentityMap.get(CellInfo.TYPE_LTE)); 1545 } else if (cellIdentityMap.containsKey(CellInfo.TYPE_NR)) { 1546 setRefLocation(AGPS_REF_LOCATION_TYPE_NR_CELLID, 1547 cellIdentityMap.get(CellInfo.TYPE_NR)); 1548 } else { 1549 Log.e(TAG, "No available serving cell information."); 1550 } 1551 } else { 1552 Log.e(TAG, "Error getting cell location info."); 1553 } 1554 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 1555 Log.e(TAG, "CDMA not supported."); 1556 } 1557 } 1558 postWithWakeLockHeld(Runnable runnable)1559 private void postWithWakeLockHeld(Runnable runnable) { 1560 // hold a wake lock until this message is delivered 1561 // note that this assumes the message will not be removed from the queue before 1562 // it is handled (otherwise the wake lock would be leaked). 1563 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS); 1564 boolean success = mHandler.post(() -> { 1565 try { 1566 runnable.run(); 1567 } finally { 1568 mWakeLock.release(); 1569 } 1570 }); 1571 if (!success) { 1572 mWakeLock.release(); 1573 } 1574 } 1575 1576 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1577 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1578 boolean dumpAll = false; 1579 1580 int opti = 0; 1581 while (opti < args.length) { 1582 String opt = args[opti]; 1583 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { 1584 break; 1585 } 1586 opti++; 1587 if ("-a".equals(opt)) { 1588 dumpAll = true; 1589 break; 1590 } 1591 } 1592 1593 pw.print("mStarted=" + mStarted + " (changed "); 1594 TimeUtils.formatDuration(SystemClock.elapsedRealtime() 1595 - mStartedChangedElapsedRealtime, pw); 1596 pw.println(" ago)"); 1597 pw.println("mBatchingEnabled=" + mBatchingEnabled); 1598 pw.println("mBatchingStarted=" + mBatchingStarted); 1599 pw.println("mBatchSize=" + getBatchSize()); 1600 pw.println("mFixInterval=" + mFixInterval); 1601 pw.print(mGnssMetrics.dumpGnssMetricsAsText()); 1602 if (dumpAll) { 1603 pw.println("mSupportsPsds=" + mSupportsPsds); 1604 pw.println( 1605 "PsdsServerConfigured=" + mGnssConfiguration.isLongTermPsdsServerConfigured()); 1606 pw.println("native internal state: "); 1607 pw.println(" " + mGnssNative.getInternalState()); 1608 } 1609 } 1610 1611 @Override onHalRestarted()1612 public void onHalRestarted() { 1613 reloadGpsProperties(); 1614 if (isGpsEnabled()) { 1615 setGpsEnabled(false); 1616 updateEnabled(); 1617 restartLocationRequest(); 1618 } 1619 } 1620 1621 @Override onCapabilitiesChanged(GnssCapabilities oldCapabilities, GnssCapabilities newCapabilities)1622 public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, 1623 GnssCapabilities newCapabilities) { 1624 mHandler.post(() -> { 1625 if (mGnssNative.getCapabilities().hasOnDemandTime()) { 1626 mNtpTimeHelper.enablePeriodicTimeInjection(); 1627 requestUtcTime(); 1628 } 1629 1630 restartLocationRequest(); 1631 }); 1632 } 1633 1634 @Override onReportLocation(boolean hasLatLong, Location location)1635 public void onReportLocation(boolean hasLatLong, Location location) { 1636 postWithWakeLockHeld(() -> handleReportLocation(hasLatLong, location)); 1637 } 1638 1639 @Override onReportLocations(Location[] locations)1640 public void onReportLocations(Location[] locations) { 1641 if (DEBUG) { 1642 Log.d(TAG, "Location batch of size " + locations.length + " reported"); 1643 } 1644 1645 if (locations.length > 0) { 1646 // attempt to fix up timestamps if necessary 1647 if (locations.length > 1) { 1648 // check any realtimes outside of expected bounds 1649 boolean fixRealtime = false; 1650 for (int i = locations.length - 2; i >= 0; i--) { 1651 long timeDeltaMs = locations[i + 1].getTime() - locations[i].getTime(); 1652 long realtimeDeltaMs = locations[i + 1].getElapsedRealtimeMillis() 1653 - locations[i].getElapsedRealtimeMillis(); 1654 if (abs(timeDeltaMs - realtimeDeltaMs) > MAX_BATCH_TIMESTAMP_DELTA_MS) { 1655 fixRealtime = true; 1656 break; 1657 } 1658 } 1659 1660 if (fixRealtime) { 1661 // sort for monotonically increasing time before fixing realtime - realtime will 1662 // thus also be monotonically increasing 1663 Arrays.sort(locations, 1664 Comparator.comparingLong(Location::getTime)); 1665 1666 long expectedDeltaMs = 1667 locations[locations.length - 1].getTime() 1668 - locations[locations.length - 1].getElapsedRealtimeMillis(); 1669 for (int i = locations.length - 2; i >= 0; i--) { 1670 locations[i].setElapsedRealtimeNanos( 1671 MILLISECONDS.toNanos( 1672 max(locations[i].getTime() - expectedDeltaMs, 0))); 1673 } 1674 } else { 1675 // sort for monotonically increasing realttime 1676 Arrays.sort(locations, 1677 Comparator.comparingLong(Location::getElapsedRealtimeNanos)); 1678 } 1679 } 1680 1681 reportLocation(LocationResult.wrap(locations).validate()); 1682 } 1683 1684 Runnable[] listeners; 1685 synchronized (mLock) { 1686 listeners = mFlushListeners.toArray(new Runnable[0]); 1687 mFlushListeners.clear(); 1688 } 1689 for (Runnable listener : listeners) { 1690 listener.run(); 1691 } 1692 } 1693 1694 @Override onReportSvStatus(GnssStatus gnssStatus)1695 public void onReportSvStatus(GnssStatus gnssStatus) { 1696 postWithWakeLockHeld(() -> handleReportSvStatus(gnssStatus)); 1697 } 1698 1699 @Override onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr)1700 public void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { 1701 mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); 1702 } 1703 1704 @Override onRequestPsdsDownload(int psdsType)1705 public void onRequestPsdsDownload(int psdsType) { 1706 postWithWakeLockHeld(() -> handleDownloadPsdsData(psdsType)); 1707 } 1708 1709 @Override onReportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, int defaultResponse, String requestorId, String text, int requestorIdEncoding, int textEncoding)1710 public void onReportNiNotification(int notificationId, int niType, int notifyFlags, 1711 int timeout, int defaultResponse, String requestorId, String text, 1712 int requestorIdEncoding, int textEncoding) { 1713 reportNiNotification(notificationId, niType, notifyFlags, timeout, 1714 defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); 1715 } 1716 1717 @Override onRequestSetID(@nssNative.AGpsCallbacks.AgpsSetIdFlags int flags)1718 public void onRequestSetID(@GnssNative.AGpsCallbacks.AgpsSetIdFlags int flags) { 1719 TelephonyManager phone = (TelephonyManager) 1720 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1721 int type = AGPS_SETID_TYPE_NONE; 1722 String setId = null; 1723 1724 int subId = SubscriptionManager.getDefaultDataSubscriptionId(); 1725 if (mNIHandler.getInEmergency() && mNetworkConnectivityHandler.getActiveSubId() >= 0) { 1726 subId = mNetworkConnectivityHandler.getActiveSubId(); 1727 } 1728 if (SubscriptionManager.isValidSubscriptionId(subId)) { 1729 phone = phone.createForSubscriptionId(subId); 1730 } 1731 if ((flags & AGPS_REQUEST_SETID_IMSI) == AGPS_REQUEST_SETID_IMSI) { 1732 setId = phone.getSubscriberId(); 1733 if (setId != null) { 1734 // This means the framework has the SIM card. 1735 type = AGPS_SETID_TYPE_IMSI; 1736 } 1737 } else if ((flags & AGPS_REQUEST_SETID_MSISDN) == AGPS_REQUEST_SETID_MSISDN) { 1738 setId = phone.getLine1Number(); 1739 if (setId != null) { 1740 // This means the framework has the SIM card. 1741 type = AGPS_SETID_TYPE_MSISDN; 1742 } 1743 } 1744 1745 mGnssNative.setAgpsSetId(type, (setId == null) ? "" : setId); 1746 } 1747 1748 @Override onRequestLocation(boolean independentFromGnss, boolean isUserEmergency)1749 public void onRequestLocation(boolean independentFromGnss, boolean isUserEmergency) { 1750 if (DEBUG) { 1751 Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss 1752 + ", isUserEmergency: " 1753 + isUserEmergency); 1754 } 1755 postWithWakeLockHeld(() -> handleRequestLocation(independentFromGnss, isUserEmergency)); 1756 } 1757 1758 @Override onRequestUtcTime()1759 public void onRequestUtcTime() { 1760 requestUtcTime(); 1761 } 1762 1763 @Override onRequestRefLocation()1764 public void onRequestRefLocation() { 1765 requestRefLocation(); 1766 } 1767 1768 @Override onReportNfwNotification(String proxyAppPackageName, byte protocolStack, String otherProtocolStackName, byte requestor, String requestorId, byte responseType, boolean inEmergencyMode, boolean isCachedLocation)1769 public void onReportNfwNotification(String proxyAppPackageName, byte protocolStack, 1770 String otherProtocolStackName, byte requestor, String requestorId, 1771 byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { 1772 if (mGnssVisibilityControl == null) { 1773 Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl uninitialized."); 1774 return; 1775 } 1776 1777 mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack, 1778 otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, 1779 isCachedLocation); 1780 } 1781 } 1782