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