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 315 private final LocationExtras mLocationExtras = new LocationExtras(); 316 private final NetworkTimeHelper mNetworkTimeHelper; 317 private final GnssSatelliteBlocklistHelper mGnssSatelliteBlocklistHelper; 318 319 // Available only on GNSS HAL 2.0 implementations and later. 320 private GnssVisibilityControl mGnssVisibilityControl; 321 322 private final GnssNetworkConnectivityHandler mNetworkConnectivityHandler; 323 private final GpsNetInitiatedHandler mNIHandler; 324 325 // Wakelocks 326 private final PowerManager.WakeLock mWakeLock; 327 328 private final AlarmManager mAlarmManager; 329 private final AlarmManager.OnAlarmListener mWakeupListener = this::startNavigating; 330 private final AlarmManager.OnAlarmListener mTimeoutListener = this::hibernate; 331 332 private final AppOpsManager mAppOps; 333 private final IBatteryStats mBatteryStats; 334 335 @GuardedBy("mLock") 336 private final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0); 337 338 // GNSS Metrics 339 private final GnssMetrics mGnssMetrics; 340 341 /** 342 * Implements {@link GnssSatelliteBlocklistCallback#onUpdateSatelliteBlocklist}. 343 */ 344 @Override onUpdateSatelliteBlocklist(int[] constellations, int[] svids)345 public void onUpdateSatelliteBlocklist(int[] constellations, int[] svids) { 346 mHandler.post(() -> mGnssConfiguration.setSatelliteBlocklist(constellations, svids)); 347 mGnssMetrics.resetConstellationTypes(); 348 } 349 subscriptionOrCarrierConfigChanged()350 private void subscriptionOrCarrierConfigChanged() { 351 if (DEBUG) Log.d(TAG, "received SIM related action: "); 352 TelephonyManager phone = (TelephonyManager) 353 mContext.getSystemService(Context.TELEPHONY_SERVICE); 354 CarrierConfigManager configManager = (CarrierConfigManager) 355 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 356 int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId(); 357 if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { 358 phone = phone.createForSubscriptionId(ddSubId); 359 } 360 String mccMnc = phone.getSimOperator(); 361 boolean isKeepLppProfile = false; 362 if (!TextUtils.isEmpty(mccMnc)) { 363 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc); 364 if (configManager != null) { 365 PersistableBundle b = SubscriptionManager.isValidSubscriptionId(ddSubId) 366 ? configManager.getConfigForSubId(ddSubId) : null; 367 if (b != null) { 368 isKeepLppProfile = 369 b.getBoolean(CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL); 370 } 371 } 372 if (isKeepLppProfile) { 373 // load current properties for the carrier of ddSubId 374 mGnssConfiguration.loadPropertiesFromCarrierConfig(/* inEmergency= */ false, 375 /* activeSubId= */ -1); 376 String lpp_profile = mGnssConfiguration.getLppProfile(); 377 // set the persist property LPP_PROFILE for the value 378 if (lpp_profile != null) { 379 SystemProperties.set(GnssConfiguration.LPP_PROFILE, lpp_profile); 380 } 381 } else { 382 // reset the persist property 383 SystemProperties.set(GnssConfiguration.LPP_PROFILE, ""); 384 } 385 reloadGpsProperties(); 386 } else { 387 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available"); 388 // Reload gnss config for no SIM case 389 mGnssConfiguration.reloadGpsProperties(); 390 } 391 } 392 reloadGpsProperties()393 private void reloadGpsProperties() { 394 mGnssConfiguration.reloadGpsProperties(); 395 setSuplHostPort(); 396 // TODO: we should get rid of C2K specific setting. 397 mC2KServerHost = mGnssConfiguration.getC2KHost(); 398 mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT); 399 mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec()); 400 mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1; 401 if (mGnssVisibilityControl != null) { 402 mGnssVisibilityControl.onConfigurationUpdated(mGnssConfiguration); 403 } 404 } 405 GnssLocationProvider(Context context, GnssNative gnssNative, GnssMetrics gnssMetrics)406 public GnssLocationProvider(Context context, GnssNative gnssNative, 407 GnssMetrics gnssMetrics) { 408 super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES, 409 Collections.emptySet()); 410 411 mContext = context; 412 mGnssNative = gnssNative; 413 mGnssMetrics = gnssMetrics; 414 415 // Create a wake lock 416 PowerManager powerManager = Objects.requireNonNull( 417 mContext.getSystemService(PowerManager.class)); 418 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*location*:" + TAG); 419 mWakeLock.setReferenceCounted(true); 420 421 // Create a separate wake lock for psds downloader as it may be released due to timeout. 422 mDownloadPsdsWakeLock = powerManager.newWakeLock( 423 PowerManager.PARTIAL_WAKE_LOCK, "*location*:PsdsDownload"); 424 mDownloadPsdsWakeLock.setReferenceCounted(true); 425 426 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 427 428 // App ops service to keep track of who is accessing the GPS 429 mAppOps = mContext.getSystemService(AppOpsManager.class); 430 431 // Battery statistics service to be notified when GPS turns on or off 432 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 433 BatteryStats.SERVICE_NAME)); 434 435 // Construct internal handler 436 mHandler = FgThread.getHandler(); 437 438 // Load GPS configuration and register listeners in the background: 439 // some operations, such as opening files and registering broadcast receivers, can take a 440 // relative long time, so the ctor() is kept to create objects needed by this instance, 441 // while IO initialization and registration is delegated to our internal handler 442 // this approach is just fine because events are posted to our handler anyway 443 mGnssConfiguration = mGnssNative.getConfiguration(); 444 // Create a GPS net-initiated handler (also needed by handleInitialize) 445 GpsNetInitiatedHandler.EmergencyCallCallback emergencyCallCallback = 446 new GpsNetInitiatedHandler.EmergencyCallCallback() { 447 448 @Override 449 public void onEmergencyCallStart(int subId) { 450 if (!mGnssConfiguration.isActiveSimEmergencySuplEnabled()) { 451 return; 452 } 453 mHandler.post(() -> mGnssConfiguration.reloadGpsProperties( 454 mNIHandler.getInEmergency(), subId)); 455 } 456 457 @Override 458 public void onEmergencyCallEnd() { 459 if (!mGnssConfiguration.isActiveSimEmergencySuplEnabled()) { 460 return; 461 } 462 mHandler.postDelayed(() -> mGnssConfiguration.reloadGpsProperties( 463 /* inEmergency= */ false, 464 SubscriptionManager.getDefaultDataSubscriptionId()), 465 TimeUnit.SECONDS.toMillis(mGnssConfiguration.getEsExtensionSec())); 466 } 467 }; 468 mNIHandler = new GpsNetInitiatedHandler(context, 469 emergencyCallCallback, 470 mSuplEsEnabled); 471 // Trigger PSDS data download when the network comes up after booting. 472 mPendingDownloadPsdsTypes.add(GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX); 473 mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context, 474 GnssLocationProvider.this::onNetworkAvailable, 475 mHandler.getLooper(), mNIHandler); 476 477 mNetworkTimeHelper = NetworkTimeHelper.create(mContext, mHandler.getLooper(), this); 478 mGnssSatelliteBlocklistHelper = 479 new GnssSatelliteBlocklistHelper(mContext, 480 mHandler.getLooper(), this); 481 482 setAllowed(true); 483 484 mGnssNative.addBaseCallbacks(this); 485 mGnssNative.addLocationCallbacks(this); 486 mGnssNative.addSvStatusCallbacks(this); 487 mGnssNative.setAGpsCallbacks(this); 488 mGnssNative.setPsdsCallbacks(this); 489 mGnssNative.setNotificationCallbacks(this); 490 mGnssNative.setLocationRequestCallbacks(this); 491 mGnssNative.setTimeCallbacks(this); 492 } 493 494 /** Called when system is ready. */ onSystemReady()495 public synchronized void onSystemReady() { 496 mContext.registerReceiverAsUser(new BroadcastReceiver() { 497 @Override 498 public void onReceive(Context context, Intent intent) { 499 if (getSendingUserId() == UserHandle.USER_ALL) { 500 mShutdown = true; 501 updateEnabled(); 502 } 503 } 504 }, UserHandle.ALL, new IntentFilter(Intent.ACTION_SHUTDOWN), null, mHandler); 505 506 mContext.getContentResolver().registerContentObserver( 507 Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE), 508 true, 509 new ContentObserver(mHandler) { 510 @Override 511 public void onChange(boolean selfChange) { 512 updateEnabled(); 513 } 514 }, UserHandle.USER_ALL); 515 516 mHandler.post(this::handleInitialize); 517 mHandler.post(mGnssSatelliteBlocklistHelper::updateSatelliteBlocklist); 518 } 519 handleInitialize()520 private void handleInitialize() { 521 if (mGnssNative.isGnssVisibilityControlSupported()) { 522 mGnssVisibilityControl = new GnssVisibilityControl(mContext, mHandler.getLooper(), 523 mNIHandler); 524 } 525 526 // load default GPS configuration 527 // (this configuration might change in the future based on SIM changes) 528 reloadGpsProperties(); 529 530 // listen for events 531 IntentFilter intentFilter = new IntentFilter(); 532 intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 533 intentFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED); 534 mContext.registerReceiver(mIntentReceiver, intentFilter, null, mHandler); 535 536 if (mNetworkConnectivityHandler.isNativeAgpsRilSupported() 537 && mGnssConfiguration.isNiSuplMessageInjectionEnabled()) { 538 // Listen to WAP PUSH NI SUPL message. 539 // See User Plane Location Protocol Candidate Version 3.0, 540 // OMA-TS-ULP-V3_0-20110920-C, Section 8.3 OMA Push. 541 intentFilter = new IntentFilter(); 542 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION); 543 try { 544 intentFilter.addDataType("application/vnd.omaloc-supl-init"); 545 } catch (IntentFilter.MalformedMimeTypeException e) { 546 Log.w(TAG, "Malformed SUPL init mime type"); 547 } 548 mContext.registerReceiver(mIntentReceiver, intentFilter, null, mHandler); 549 550 // Listen to MT SMS NI SUPL message. 551 // See User Plane Location Protocol Candidate Version 3.0, 552 // OMA-TS-ULP-V3_0-20110920-C, Section 8.4 MT SMS. 553 intentFilter = new IntentFilter(); 554 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION); 555 intentFilter.addDataScheme("sms"); 556 intentFilter.addDataAuthority("localhost", "7275"); 557 mContext.registerReceiver(mIntentReceiver, intentFilter, null, mHandler); 558 } 559 560 mNetworkConnectivityHandler.registerNetworkCallbacks(); 561 562 // permanently passively listen to all network locations 563 LocationManager locationManager = Objects.requireNonNull( 564 mContext.getSystemService(LocationManager.class)); 565 if (locationManager.getAllProviders().contains(LocationManager.NETWORK_PROVIDER)) { 566 locationManager.requestLocationUpdates( 567 LocationManager.NETWORK_PROVIDER, 568 new LocationRequest.Builder(LocationRequest.PASSIVE_INTERVAL) 569 .setMinUpdateIntervalMillis(0) 570 .setHiddenFromAppOps(true) 571 .build(), 572 DIRECT_EXECUTOR, 573 this::injectLocation); 574 } 575 576 updateEnabled(); 577 synchronized (mLock) { 578 mInitialized = true; 579 } 580 } 581 582 private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 583 @Override 584 public void onReceive(Context context, Intent intent) { 585 String action = intent.getAction(); 586 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action); 587 if (action == null) { 588 return; 589 } 590 591 switch (action) { 592 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: 593 case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED: 594 subscriptionOrCarrierConfigChanged(); 595 break; 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 if (Flags.gnssCallStopBeforeSetPositionMode()) { 1054 GnssPositionMode positionMode = new GnssPositionMode(mPositionMode, 1055 GNSS_POSITION_RECURRENCE_PERIODIC, mFixInterval, 1056 /* preferredAccuracy= */ 0, 1057 /* preferredTime= */ 0, 1058 mProviderRequest.isLowPower()); 1059 if (!positionMode.equals(mLastPositionMode)) { 1060 stopNavigating(); 1061 startNavigating(); 1062 } 1063 } else { 1064 // change period and/or lowPowerMode 1065 if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, 1066 mFixInterval, mProviderRequest.isLowPower())) { 1067 Log.e(TAG, "set_position_mode failed in updateRequirements"); 1068 } 1069 } 1070 } else if (!mStarted) { 1071 // start GPS 1072 startNavigating(); 1073 } else { 1074 // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING 1075 mAlarmManager.cancel(mTimeoutListener); 1076 if (mFixInterval >= NO_FIX_TIMEOUT) { 1077 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1078 // and our fix interval is not short 1079 mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, 1080 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG, 1081 mTimeoutListener, mHandler); 1082 } 1083 } 1084 } 1085 } else { 1086 updateClientUids(new WorkSource()); 1087 stopNavigating(); 1088 stopBatching(); 1089 } 1090 } 1091 setPositionMode(int mode, int recurrence, int minInterval, boolean lowPowerMode)1092 private boolean setPositionMode(int mode, int recurrence, int minInterval, 1093 boolean lowPowerMode) { 1094 GnssPositionMode positionMode = new GnssPositionMode(mode, recurrence, minInterval, 1095 0, 0, lowPowerMode); 1096 if (mLastPositionMode != null && mLastPositionMode.equals(positionMode)) { 1097 return true; 1098 } 1099 1100 boolean result = mGnssNative.setPositionMode(mode, recurrence, minInterval, 0, 0, 1101 lowPowerMode); 1102 if (result) { 1103 mLastPositionMode = positionMode; 1104 } else { 1105 mLastPositionMode = null; 1106 } 1107 return result; 1108 } 1109 updateClientUids(WorkSource source)1110 private void updateClientUids(WorkSource source) { 1111 if (source.equals(mClientSource)) { 1112 return; 1113 } 1114 1115 // (1) Inform BatteryStats that the list of IDs we're tracking changed. 1116 try { 1117 mBatteryStats.noteGpsChanged(mClientSource, source); 1118 } catch (RemoteException e) { 1119 Log.w(TAG, "RemoteException", e); 1120 } 1121 1122 // (2) Inform AppOps service about the list of changes to UIDs. 1123 1124 // TODO: this doesn't seem correct, work chain attribution tag != package? 1125 List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source); 1126 if (diffs != null) { 1127 List<WorkChain> newChains = diffs[0]; 1128 List<WorkChain> goneChains = diffs[1]; 1129 1130 if (newChains != null) { 1131 for (WorkChain newChain : newChains) { 1132 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(), 1133 newChain.getAttributionTag()); 1134 } 1135 } 1136 1137 if (goneChains != null) { 1138 for (WorkChain goneChain : goneChains) { 1139 mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(), 1140 goneChain.getAttributionTag()); 1141 } 1142 } 1143 1144 mClientSource.transferWorkChains(source); 1145 } 1146 1147 // Update the flat UIDs and names list and inform app-ops of all changes. 1148 // TODO: why is GnssLocationProvider the only component using these deprecated APIs? 1149 WorkSource[] changes = mClientSource.setReturningDiffs(source); 1150 if (changes != null) { 1151 WorkSource newWork = changes[0]; 1152 WorkSource goneWork = changes[1]; 1153 1154 // Update sources that were not previously tracked. 1155 if (newWork != null) { 1156 for (int i = 0; i < newWork.size(); i++) { 1157 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, 1158 newWork.getUid(i), newWork.getPackageName(i)); 1159 } 1160 } 1161 1162 // Update sources that are no longer tracked. 1163 if (goneWork != null) { 1164 for (int i = 0; i < goneWork.size(); i++) { 1165 mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.getUid(i), 1166 goneWork.getPackageName(i)); 1167 } 1168 } 1169 } 1170 } 1171 1172 @Override onExtraCommand(int uid, int pid, String command, Bundle extras)1173 public void onExtraCommand(int uid, int pid, String command, Bundle extras) { 1174 if ("delete_aiding_data".equals(command)) { 1175 deleteAidingData(extras); 1176 } else if ("force_time_injection".equals(command)) { 1177 demandUtcTimeInjection(); 1178 } else if ("force_psds_injection".equals(command)) { 1179 if (mSupportsPsds) { 1180 postWithWakeLockHeld(() -> handleDownloadPsdsData( 1181 GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX)); 1182 } 1183 } else if ("request_power_stats".equals(command)) { 1184 mGnssNative.requestPowerStats(Runnable::run, powerStats -> {}); 1185 } else { 1186 Log.w(TAG, "sendExtraCommand: unknown command " + command); 1187 } 1188 } 1189 deleteAidingData(Bundle extras)1190 private void deleteAidingData(Bundle extras) { 1191 int flags; 1192 1193 if (extras == null) { 1194 flags = GNSS_AIDING_TYPE_ALL; 1195 } else { 1196 flags = 0; 1197 if (extras.getBoolean("ephemeris")) flags |= GNSS_AIDING_TYPE_EPHEMERIS; 1198 if (extras.getBoolean("almanac")) flags |= GNSS_AIDING_TYPE_ALMANAC; 1199 if (extras.getBoolean("position")) flags |= GNSS_AIDING_TYPE_POSITION; 1200 if (extras.getBoolean("time")) flags |= GNSS_AIDING_TYPE_TIME; 1201 if (extras.getBoolean("iono")) flags |= GNSS_AIDING_TYPE_IONO; 1202 if (extras.getBoolean("utc")) flags |= GNSS_AIDING_TYPE_UTC; 1203 if (extras.getBoolean("health")) flags |= GNSS_AIDING_TYPE_HEALTH; 1204 if (extras.getBoolean("svdir")) flags |= GNSS_AIDING_TYPE_SVDIR; 1205 if (extras.getBoolean("svsteer")) flags |= GNSS_AIDING_TYPE_SVSTEER; 1206 if (extras.getBoolean("sadata")) flags |= GNSS_AIDING_TYPE_SADATA; 1207 if (extras.getBoolean("rti")) flags |= GNSS_AIDING_TYPE_RTI; 1208 if (extras.getBoolean("celldb-info")) flags |= GNSS_AIDING_TYPE_CELLDB_INFO; 1209 if (extras.getBoolean("all")) flags |= GNSS_AIDING_TYPE_ALL; 1210 } 1211 1212 if (flags != 0) { 1213 mGnssNative.deleteAidingData(flags); 1214 } 1215 } 1216 startNavigating()1217 private void startNavigating() { 1218 if (!mStarted) { 1219 if (DEBUG) Log.d(TAG, "startNavigating"); 1220 mTimeToFirstFix = 0; 1221 mLastFixTime = 0; 1222 setStarted(true); 1223 mPositionMode = GNSS_POSITION_MODE_STANDALONE; 1224 1225 boolean agpsEnabled = 1226 (Settings.Global.getInt(mContext.getContentResolver(), 1227 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0); 1228 mPositionMode = getSuplMode(agpsEnabled); 1229 1230 if (DEBUG) { 1231 String mode; 1232 1233 switch (mPositionMode) { 1234 case GNSS_POSITION_MODE_STANDALONE: 1235 mode = "standalone"; 1236 break; 1237 case GNSS_POSITION_MODE_MS_ASSISTED: 1238 mode = "MS_ASSISTED"; 1239 break; 1240 case GNSS_POSITION_MODE_MS_BASED: 1241 mode = "MS_BASED"; 1242 break; 1243 default: 1244 mode = "unknown"; 1245 break; 1246 } 1247 Log.d(TAG, "setting position_mode to " + mode); 1248 } 1249 1250 int interval = mGnssNative.getCapabilities().hasScheduling() ? mFixInterval : 1000; 1251 1252 if (Flags.gnssCallStopBeforeSetPositionMode()) { 1253 boolean success = mGnssNative.setPositionMode(mPositionMode, 1254 GNSS_POSITION_RECURRENCE_PERIODIC, interval, 1255 /* preferredAccuracy= */ 0, 1256 /* preferredTime= */ 0, 1257 mProviderRequest.isLowPower()); 1258 if (success) { 1259 mLastPositionMode = new GnssPositionMode(mPositionMode, 1260 GNSS_POSITION_RECURRENCE_PERIODIC, interval, 1261 /* preferredAccuracy= */ 0, 1262 /* preferredTime= */ 0, 1263 mProviderRequest.isLowPower()); 1264 } else { 1265 mLastPositionMode = null; 1266 setStarted(false); 1267 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1268 return; 1269 } 1270 } else { 1271 if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, 1272 interval, mProviderRequest.isLowPower())) { 1273 setStarted(false); 1274 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1275 return; 1276 } 1277 } 1278 if (!mGnssNative.start()) { 1279 setStarted(false); 1280 Log.e(TAG, "native_start failed in startNavigating()"); 1281 return; 1282 } 1283 1284 // reset SV count to zero 1285 mLocationExtras.reset(); 1286 mFixRequestTime = SystemClock.elapsedRealtime(); 1287 if (!mGnssNative.getCapabilities().hasScheduling()) { 1288 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1289 // and our fix interval is not short 1290 if (mFixInterval >= NO_FIX_TIMEOUT) { 1291 mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, 1292 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG, mTimeoutListener, 1293 mHandler); 1294 } 1295 } 1296 } 1297 } 1298 stopNavigating()1299 private void stopNavigating() { 1300 if (DEBUG) Log.d(TAG, "stopNavigating"); 1301 if (mStarted) { 1302 setStarted(false); 1303 mGnssNative.stop(); 1304 mLastFixTime = 0; 1305 // native_stop() may reset the position mode in hardware. 1306 mLastPositionMode = null; 1307 1308 // reset SV count to zero 1309 mLocationExtras.reset(); 1310 } 1311 mAlarmManager.cancel(mTimeoutListener); 1312 mAlarmManager.cancel(mWakeupListener); 1313 } 1314 startBatching(long batchLengthMs)1315 private void startBatching(long batchLengthMs) { 1316 long batchSize = batchLengthMs / mFixInterval; 1317 1318 if (DEBUG) { 1319 Log.d(TAG, "startBatching " + mFixInterval + " " + batchLengthMs); 1320 } 1321 if (mGnssNative.startBatch(MILLISECONDS.toNanos(mFixInterval), 0, true)) { 1322 mBatchingStarted = true; 1323 1324 if (batchSize < getBatchSize()) { 1325 // if the batch size is smaller than the hardware batch size, use an alarm to flush 1326 // locations as appropriate 1327 mBatchingAlarm = () -> { 1328 boolean flush = false; 1329 synchronized (mLock) { 1330 if (mBatchingAlarm != null) { 1331 flush = true; 1332 mAlarmManager.setExact(ELAPSED_REALTIME_WAKEUP, 1333 SystemClock.elapsedRealtime() + batchLengthMs, TAG, 1334 mBatchingAlarm, FgThread.getHandler()); 1335 } 1336 } 1337 1338 if (flush) { 1339 mGnssNative.flushBatch(); 1340 } 1341 }; 1342 mAlarmManager.setExact(ELAPSED_REALTIME_WAKEUP, 1343 SystemClock.elapsedRealtime() + batchLengthMs, TAG, 1344 mBatchingAlarm, FgThread.getHandler()); 1345 } 1346 } else { 1347 Log.e(TAG, "native_start_batch failed in startBatching()"); 1348 } 1349 } 1350 stopBatching()1351 private void stopBatching() { 1352 if (DEBUG) Log.d(TAG, "stopBatching"); 1353 if (mBatchingStarted) { 1354 if (mBatchingAlarm != null) { 1355 mAlarmManager.cancel(mBatchingAlarm); 1356 mBatchingAlarm = null; 1357 } 1358 mGnssNative.flushBatch(); 1359 mGnssNative.stopBatch(); 1360 mBatchingStarted = false; 1361 } 1362 } 1363 setStarted(boolean started)1364 private void setStarted(boolean started) { 1365 if (mStarted != started) { 1366 mStarted = started; 1367 mStartedChangedElapsedRealtime = SystemClock.elapsedRealtime(); 1368 } 1369 } 1370 hibernate()1371 private void hibernate() { 1372 // stop GPS until our next fix interval arrives 1373 stopNavigating(); 1374 long now = SystemClock.elapsedRealtime(); 1375 mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, now + mFixInterval, TAG, 1376 mWakeupListener, mHandler); 1377 } 1378 handleReportLocation(boolean hasLatLong, Location location)1379 private void handleReportLocation(boolean hasLatLong, Location location) { 1380 if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString()); 1381 1382 location.setExtras(mLocationExtras.getBundle()); 1383 1384 try { 1385 reportLocation(LocationResult.wrap(location).validate()); 1386 } catch (BadLocationException e) { 1387 Log.e(TAG, "Dropping invalid location: " + e); 1388 return; 1389 } 1390 1391 if (mStarted) { 1392 mGnssMetrics.logReceivedLocationStatus(hasLatLong); 1393 if (hasLatLong) { 1394 if (location.hasAccuracy()) { 1395 mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy()); 1396 } 1397 if (mTimeToFirstFix > 0) { 1398 int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime); 1399 mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes); 1400 } 1401 } 1402 } else { 1403 // Warn or error about long delayed GNSS engine shutdown as this generally wastes 1404 // power and sends location when not expected. 1405 long locationAfterStartedFalseMillis = 1406 SystemClock.elapsedRealtime() - mStartedChangedElapsedRealtime; 1407 if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS) { 1408 String logMessage = "Unexpected GNSS Location report " 1409 + TimeUtils.formatDuration(locationAfterStartedFalseMillis) 1410 + " after location turned off"; 1411 if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS) { 1412 Log.e(TAG, logMessage); 1413 } else { 1414 Log.w(TAG, logMessage); 1415 } 1416 } 1417 } 1418 1419 mLastFixTime = SystemClock.elapsedRealtime(); 1420 // report time to first fix 1421 if (mTimeToFirstFix == 0 && hasLatLong) { 1422 mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime); 1423 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1424 if (mStarted) { 1425 mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix); 1426 } 1427 } 1428 1429 if (mStarted) { 1430 // For devices that use framework scheduling, a timer may be set to ensure we don't 1431 // spend too much power searching for a location, when the requested update rate is 1432 // slow. 1433 // As we just recievied a location, we'll cancel that timer. 1434 if (!mGnssNative.getCapabilities().hasScheduling() && mFixInterval < NO_FIX_TIMEOUT) { 1435 mAlarmManager.cancel(mTimeoutListener); 1436 } 1437 } 1438 1439 if (!mGnssNative.getCapabilities().hasScheduling() && mStarted 1440 && mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1441 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1442 hibernate(); 1443 } 1444 } 1445 handleReportSvStatus(GnssStatus gnssStatus)1446 private void handleReportSvStatus(GnssStatus gnssStatus) { 1447 // Log CN0 as part of GNSS metrics 1448 mGnssMetrics.logCn0(gnssStatus); 1449 1450 if (VERBOSE) { 1451 Log.v(TAG, "SV count: " + gnssStatus.getSatelliteCount()); 1452 } 1453 1454 Set<Pair<Integer, Integer>> satellites = new HashSet<>(); 1455 int usedInFixCount = 0; 1456 int maxCn0 = 0; 1457 int meanCn0 = 0; 1458 for (int i = 0; i < gnssStatus.getSatelliteCount(); i++) { 1459 if (gnssStatus.usedInFix(i)) { 1460 satellites.add( 1461 new Pair<>(gnssStatus.getConstellationType(i), gnssStatus.getSvid(i))); 1462 ++usedInFixCount; 1463 if (gnssStatus.getCn0DbHz(i) > maxCn0) { 1464 maxCn0 = (int) gnssStatus.getCn0DbHz(i); 1465 } 1466 meanCn0 += gnssStatus.getCn0DbHz(i); 1467 mGnssMetrics.logConstellationType(gnssStatus.getConstellationType(i)); 1468 } 1469 } 1470 if (usedInFixCount > 0) { 1471 meanCn0 /= usedInFixCount; 1472 } 1473 // return number of sats used in fix instead of total reported 1474 mLocationExtras.set(satellites.size(), meanCn0, maxCn0); 1475 1476 mGnssMetrics.logSvStatus(gnssStatus); 1477 } 1478 restartLocationRequest()1479 private void restartLocationRequest() { 1480 if (DEBUG) Log.d(TAG, "restartLocationRequest"); 1481 setStarted(false); 1482 updateRequirements(); 1483 } 1484 demandUtcTimeInjection()1485 private void demandUtcTimeInjection() { 1486 if (DEBUG) Log.d(TAG, "demandUtcTimeInjection"); 1487 postWithWakeLockHeld(mNetworkTimeHelper::demandUtcTimeInjection); 1488 } 1489 1490 getCellType(CellInfo ci)1491 private static int getCellType(CellInfo ci) { 1492 if (ci instanceof CellInfoGsm) { 1493 return CellInfo.TYPE_GSM; 1494 } else if (ci instanceof CellInfoWcdma) { 1495 return CellInfo.TYPE_WCDMA; 1496 } else if (ci instanceof CellInfoLte) { 1497 return CellInfo.TYPE_LTE; 1498 } else if (ci instanceof CellInfoNr) { 1499 return CellInfo.TYPE_NR; 1500 } 1501 return CellInfo.TYPE_UNKNOWN; 1502 } 1503 1504 /** 1505 * Extract the CID/CI for GSM/WCDMA/LTE/NR 1506 * 1507 * @return the cell ID or -1 if invalid 1508 */ getCidFromCellIdentity(CellIdentity id)1509 private static long getCidFromCellIdentity(CellIdentity id) { 1510 if (id == null) { 1511 return -1; 1512 } 1513 long cid = -1; 1514 switch(id.getType()) { 1515 case CellInfo.TYPE_GSM: cid = ((CellIdentityGsm) id).getCid(); break; 1516 case CellInfo.TYPE_WCDMA: cid = ((CellIdentityWcdma) id).getCid(); break; 1517 case CellInfo.TYPE_LTE: cid = ((CellIdentityLte) id).getCi(); break; 1518 case CellInfo.TYPE_NR: cid = ((CellIdentityNr) id).getNci(); break; 1519 default: break; 1520 } 1521 // If the CID is unreported 1522 if (cid == (id.getType() == CellInfo.TYPE_NR 1523 ? CellInfo.UNAVAILABLE_LONG : CellInfo.UNAVAILABLE)) { 1524 cid = -1; 1525 } 1526 1527 return cid; 1528 } 1529 setRefLocation(int type, CellIdentity ci)1530 private void setRefLocation(int type, CellIdentity ci) { 1531 String mcc_str = ci.getMccString(); 1532 String mnc_str = ci.getMncString(); 1533 int mcc = mcc_str != null ? Integer.parseInt(mcc_str) : CellInfo.UNAVAILABLE; 1534 int mnc = mnc_str != null ? Integer.parseInt(mnc_str) : CellInfo.UNAVAILABLE; 1535 int lac = CellInfo.UNAVAILABLE; 1536 int tac = CellInfo.UNAVAILABLE; 1537 int pcid = CellInfo.UNAVAILABLE; 1538 int arfcn = CellInfo.UNAVAILABLE; 1539 long cid = CellInfo.UNAVAILABLE_LONG; 1540 1541 switch (type) { 1542 case AGPS_REF_LOCATION_TYPE_GSM_CELLID: 1543 CellIdentityGsm cig = (CellIdentityGsm) ci; 1544 cid = cig.getCid(); 1545 lac = cig.getLac(); 1546 break; 1547 case AGPS_REF_LOCATION_TYPE_UMTS_CELLID: 1548 CellIdentityWcdma ciw = (CellIdentityWcdma) ci; 1549 cid = ciw.getCid(); 1550 lac = ciw.getLac(); 1551 break; 1552 case AGPS_REF_LOCATION_TYPE_LTE_CELLID: 1553 CellIdentityLte cil = (CellIdentityLte) ci; 1554 cid = cil.getCi(); 1555 tac = cil.getTac(); 1556 pcid = cil.getPci(); 1557 break; 1558 case AGPS_REF_LOCATION_TYPE_NR_CELLID: 1559 CellIdentityNr cin = (CellIdentityNr) ci; 1560 cid = cin.getNci(); 1561 tac = cin.getTac(); 1562 pcid = cin.getPci(); 1563 arfcn = cin.getNrarfcn(); 1564 break; 1565 default: 1566 } 1567 1568 mGnssNative.setAgpsReferenceLocationCellId( 1569 type, mcc, mnc, lac, cid, tac, pcid, arfcn); 1570 } 1571 requestRefLocation()1572 private void requestRefLocation() { 1573 TelephonyManager phone = (TelephonyManager) 1574 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1575 1576 final int phoneType = phone.getPhoneType(); 1577 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 1578 1579 List<CellInfo> cil = phone.getAllCellInfo(); 1580 if (cil != null) { 1581 HashMap<Integer, CellIdentity> cellIdentityMap = new HashMap<>(); 1582 cil.sort(Comparator.comparingInt( 1583 (CellInfo ci) -> ci.getCellSignalStrength().getAsuLevel()).reversed()); 1584 1585 for (CellInfo ci : cil) { 1586 int status = ci.getCellConnectionStatus(); 1587 if (ci.isRegistered() 1588 || status == CellInfo.CONNECTION_PRIMARY_SERVING 1589 || status == CellInfo.CONNECTION_SECONDARY_SERVING) { 1590 CellIdentity c = ci.getCellIdentity(); 1591 int t = getCellType(ci); 1592 if (getCidFromCellIdentity(c) != -1 1593 && !cellIdentityMap.containsKey(t)) { 1594 cellIdentityMap.put(t, c); 1595 } 1596 } 1597 } 1598 1599 if (cellIdentityMap.containsKey(CellInfo.TYPE_GSM)) { 1600 setRefLocation(AGPS_REF_LOCATION_TYPE_GSM_CELLID, 1601 cellIdentityMap.get(CellInfo.TYPE_GSM)); 1602 } else if (cellIdentityMap.containsKey(CellInfo.TYPE_WCDMA)) { 1603 setRefLocation(AGPS_REF_LOCATION_TYPE_UMTS_CELLID, 1604 cellIdentityMap.get(CellInfo.TYPE_WCDMA)); 1605 } else if (cellIdentityMap.containsKey(CellInfo.TYPE_LTE)) { 1606 setRefLocation(AGPS_REF_LOCATION_TYPE_LTE_CELLID, 1607 cellIdentityMap.get(CellInfo.TYPE_LTE)); 1608 } else if (cellIdentityMap.containsKey(CellInfo.TYPE_NR)) { 1609 setRefLocation(AGPS_REF_LOCATION_TYPE_NR_CELLID, 1610 cellIdentityMap.get(CellInfo.TYPE_NR)); 1611 } else { 1612 Log.e(TAG, "No available serving cell information."); 1613 } 1614 } else { 1615 Log.e(TAG, "Error getting cell location info."); 1616 } 1617 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 1618 Log.e(TAG, "CDMA not supported."); 1619 } 1620 } 1621 postWithWakeLockHeld(Runnable runnable)1622 private void postWithWakeLockHeld(Runnable runnable) { 1623 // hold a wake lock until this message is delivered 1624 // note that this assumes the message will not be removed from the queue before 1625 // it is handled (otherwise the wake lock would be leaked). 1626 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS); 1627 boolean success = mHandler.post(() -> { 1628 try { 1629 runnable.run(); 1630 } finally { 1631 mWakeLock.release(); 1632 } 1633 }); 1634 if (!success) { 1635 mWakeLock.release(); 1636 } 1637 } 1638 1639 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1640 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1641 boolean dumpAll = false; 1642 1643 int opti = 0; 1644 while (opti < args.length) { 1645 String opt = args[opti]; 1646 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { 1647 break; 1648 } 1649 opti++; 1650 if ("-a".equals(opt)) { 1651 dumpAll = true; 1652 break; 1653 } 1654 } 1655 1656 pw.print("mStarted=" + mStarted + " (changed "); 1657 TimeUtils.formatDuration(SystemClock.elapsedRealtime() 1658 - mStartedChangedElapsedRealtime, pw); 1659 pw.println(" ago)"); 1660 pw.println("mBatchingEnabled=" + mBatchingEnabled); 1661 pw.println("mBatchingStarted=" + mBatchingStarted); 1662 pw.println("mBatchSize=" + getBatchSize()); 1663 pw.println("mFixInterval=" + mFixInterval); 1664 pw.print(mGnssMetrics.dumpGnssMetricsAsText()); 1665 if (dumpAll) { 1666 mNetworkTimeHelper.dump(pw); 1667 pw.println("mSupportsPsds=" + mSupportsPsds); 1668 pw.println( 1669 "PsdsServerConfigured=" + mGnssConfiguration.isLongTermPsdsServerConfigured()); 1670 pw.println("native internal state: "); 1671 pw.println(" " + mGnssNative.getInternalState()); 1672 } 1673 } 1674 1675 @Override onHalRestarted()1676 public void onHalRestarted() { 1677 reloadGpsProperties(); 1678 if (isGpsEnabled()) { 1679 setGpsEnabled(false); 1680 updateEnabled(); 1681 restartLocationRequest(); 1682 } 1683 1684 // Re-register network callbacks to get an update of available networks right away. 1685 synchronized (mLock) { 1686 if (mInitialized) { 1687 mNetworkConnectivityHandler.unregisterNetworkCallbacks(); 1688 mNetworkConnectivityHandler.registerNetworkCallbacks(); 1689 } 1690 } 1691 } 1692 1693 @Override onCapabilitiesChanged(GnssCapabilities oldCapabilities, GnssCapabilities newCapabilities)1694 public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, 1695 GnssCapabilities newCapabilities) { 1696 mHandler.post(() -> { 1697 boolean useOnDemandTimeInjection = mGnssNative.getCapabilities().hasOnDemandTime(); 1698 1699 // b/73893222: There is a historic bug on Android, which means that the capability 1700 // "on demand time" is interpreted as "enable periodic injection" elsewhere but an 1701 // on-demand injection is done here. GNSS developers may have come to rely on the 1702 // periodic behavior, so it has been kept and all methods named to reflect what is 1703 // actually done. "On demand" requests are supported regardless of the capability. 1704 mNetworkTimeHelper.setPeriodicTimeInjectionMode(useOnDemandTimeInjection); 1705 if (useOnDemandTimeInjection) { 1706 demandUtcTimeInjection(); 1707 } 1708 1709 restartLocationRequest(); 1710 }); 1711 } 1712 1713 @Override onReportLocation(boolean hasLatLong, Location location)1714 public void onReportLocation(boolean hasLatLong, Location location) { 1715 postWithWakeLockHeld(() -> handleReportLocation(hasLatLong, location)); 1716 } 1717 1718 @Override onReportLocations(Location[] locations)1719 public void onReportLocations(Location[] locations) { 1720 if (DEBUG) { 1721 Log.d(TAG, "Location batch of size " + locations.length + " reported"); 1722 } 1723 1724 if (locations.length > 0) { 1725 // attempt to fix up timestamps if necessary 1726 if (locations.length > 1) { 1727 // check any realtimes outside of expected bounds 1728 boolean fixRealtime = false; 1729 for (int i = locations.length - 2; i >= 0; i--) { 1730 long timeDeltaMs = locations[i + 1].getTime() - locations[i].getTime(); 1731 long realtimeDeltaMs = locations[i + 1].getElapsedRealtimeMillis() 1732 - locations[i].getElapsedRealtimeMillis(); 1733 if (abs(timeDeltaMs - realtimeDeltaMs) > MAX_BATCH_TIMESTAMP_DELTA_MS) { 1734 fixRealtime = true; 1735 break; 1736 } 1737 } 1738 1739 if (fixRealtime) { 1740 // sort for monotonically increasing time before fixing realtime - realtime will 1741 // thus also be monotonically increasing 1742 Arrays.sort(locations, 1743 Comparator.comparingLong(Location::getTime)); 1744 1745 long expectedDeltaMs = 1746 locations[locations.length - 1].getTime() 1747 - locations[locations.length - 1].getElapsedRealtimeMillis(); 1748 for (int i = locations.length - 2; i >= 0; i--) { 1749 locations[i].setElapsedRealtimeNanos( 1750 MILLISECONDS.toNanos( 1751 max(locations[i].getTime() - expectedDeltaMs, 0))); 1752 } 1753 } else { 1754 // sort for monotonically increasing realttime 1755 Arrays.sort(locations, 1756 Comparator.comparingLong(Location::getElapsedRealtimeNanos)); 1757 } 1758 } 1759 1760 try { 1761 reportLocation(LocationResult.wrap(locations).validate()); 1762 } catch (BadLocationException e) { 1763 Log.e(TAG, "Dropping invalid locations: " + e); 1764 return; 1765 } 1766 } 1767 1768 Runnable[] listeners; 1769 synchronized (mLock) { 1770 listeners = mFlushListeners.toArray(new Runnable[0]); 1771 mFlushListeners.clear(); 1772 } 1773 for (Runnable listener : listeners) { 1774 listener.run(); 1775 } 1776 } 1777 1778 @Override onReportSvStatus(GnssStatus gnssStatus)1779 public void onReportSvStatus(GnssStatus gnssStatus) { 1780 postWithWakeLockHeld(() -> handleReportSvStatus(gnssStatus)); 1781 } 1782 1783 @Override onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr)1784 public void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { 1785 mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); 1786 } 1787 1788 @Override onRequestPsdsDownload(int psdsType)1789 public void onRequestPsdsDownload(int psdsType) { 1790 postWithWakeLockHeld(() -> handleDownloadPsdsData(psdsType)); 1791 } 1792 1793 @Override onRequestSetID(@nssNative.AGpsCallbacks.AgpsSetIdFlags int flags)1794 public void onRequestSetID(@GnssNative.AGpsCallbacks.AgpsSetIdFlags int flags) { 1795 TelephonyManager phone = (TelephonyManager) 1796 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1797 int type = AGPS_SETID_TYPE_NONE; 1798 String setId = null; 1799 1800 int subId = SubscriptionManager.getDefaultDataSubscriptionId(); 1801 if (mGnssConfiguration.isActiveSimEmergencySuplEnabled() && mNIHandler.getInEmergency() 1802 && mNetworkConnectivityHandler.getActiveSubId() >= 0) { 1803 subId = mNetworkConnectivityHandler.getActiveSubId(); 1804 } 1805 if (SubscriptionManager.isValidSubscriptionId(subId)) { 1806 phone = phone.createForSubscriptionId(subId); 1807 } 1808 if ((flags & AGPS_REQUEST_SETID_IMSI) == AGPS_REQUEST_SETID_IMSI) { 1809 setId = phone.getSubscriberId(); 1810 if (setId != null) { 1811 // This means the framework has the SIM card. 1812 type = AGPS_SETID_TYPE_IMSI; 1813 } 1814 } else if ((flags & AGPS_REQUEST_SETID_MSISDN) == AGPS_REQUEST_SETID_MSISDN) { 1815 setId = phone.getLine1Number(); 1816 if (setId != null) { 1817 // This means the framework has the SIM card. 1818 type = AGPS_SETID_TYPE_MSISDN; 1819 } 1820 } 1821 1822 mGnssNative.setAgpsSetId(type, (setId == null) ? "" : setId); 1823 } 1824 1825 @Override onRequestLocation(boolean independentFromGnss, boolean isUserEmergency)1826 public void onRequestLocation(boolean independentFromGnss, boolean isUserEmergency) { 1827 if (DEBUG) { 1828 Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss 1829 + ", isUserEmergency: " 1830 + isUserEmergency); 1831 } 1832 postWithWakeLockHeld(() -> handleRequestLocation(independentFromGnss, isUserEmergency)); 1833 } 1834 1835 @Override onRequestUtcTime()1836 public void onRequestUtcTime() { 1837 demandUtcTimeInjection(); 1838 } 1839 1840 @Override onRequestRefLocation()1841 public void onRequestRefLocation() { 1842 requestRefLocation(); 1843 } 1844 1845 @Override onReportNfwNotification(String proxyAppPackageName, byte protocolStack, String otherProtocolStackName, byte requestor, String requestorId, byte responseType, boolean inEmergencyMode, boolean isCachedLocation)1846 public void onReportNfwNotification(String proxyAppPackageName, byte protocolStack, 1847 String otherProtocolStackName, byte requestor, String requestorId, 1848 byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { 1849 if (mGnssVisibilityControl == null) { 1850 Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl uninitialized."); 1851 return; 1852 } 1853 1854 mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack, 1855 otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, 1856 isCachedLocation); 1857 } 1858 } 1859