1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.location.gnss; 18 19 import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP; 20 import static android.content.pm.PackageManager.FEATURE_WATCH; 21 import static android.location.provider.ProviderProperties.ACCURACY_FINE; 22 import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH; 23 24 import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; 25 import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_GSM_CELLID; 26 import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_LTE_CELLID; 27 import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_NR_CELLID; 28 import static com.android.server.location.gnss.hal.GnssNative.AGPS_REF_LOCATION_TYPE_UMTS_CELLID; 29 import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_IMSI; 30 import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_MSISDN; 31 import static com.android.server.location.gnss.hal.GnssNative.AGPS_SETID_TYPE_NONE; 32 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALL; 33 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_ALMANAC; 34 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_CELLDB_INFO; 35 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_EPHEMERIS; 36 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_HEALTH; 37 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_IONO; 38 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_POSITION; 39 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_RTI; 40 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SADATA; 41 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVDIR; 42 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_SVSTEER; 43 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_TIME; 44 import static com.android.server.location.gnss.hal.GnssNative.GNSS_AIDING_TYPE_UTC; 45 import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_ASSISTED; 46 import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_MS_BASED; 47 import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_MODE_STANDALONE; 48 import static com.android.server.location.gnss.hal.GnssNative.GNSS_POSITION_RECURRENCE_PERIODIC; 49 50 import static java.lang.Math.abs; 51 import static java.lang.Math.max; 52 import static java.util.concurrent.TimeUnit.MILLISECONDS; 53 54 import android.app.AlarmManager; 55 import android.app.AppOpsManager; 56 import android.content.BroadcastReceiver; 57 import android.content.ContentResolver; 58 import android.content.Context; 59 import android.content.Intent; 60 import android.content.IntentFilter; 61 import android.content.pm.PackageManager; 62 import android.database.ContentObserver; 63 import android.location.GnssCapabilities; 64 import android.location.GnssStatus; 65 import android.location.INetInitiatedListener; 66 import android.location.Location; 67 import android.location.LocationListener; 68 import android.location.LocationManager; 69 import android.location.LocationRequest; 70 import android.location.LocationResult; 71 import android.location.provider.ProviderProperties; 72 import android.location.provider.ProviderRequest; 73 import android.location.util.identity.CallerIdentity; 74 import android.os.BatteryStats; 75 import android.os.Bundle; 76 import android.os.Handler; 77 import android.os.PersistableBundle; 78 import android.os.PowerManager; 79 import android.os.RemoteException; 80 import android.os.ServiceManager; 81 import android.os.SystemClock; 82 import android.os.SystemProperties; 83 import android.os.UserHandle; 84 import android.os.UserManager; 85 import android.os.WorkSource; 86 import android.os.WorkSource.WorkChain; 87 import android.provider.Settings; 88 import android.provider.Telephony.Sms.Intents; 89 import android.telephony.CarrierConfigManager; 90 import android.telephony.CellIdentity; 91 import android.telephony.CellIdentityGsm; 92 import android.telephony.CellIdentityLte; 93 import android.telephony.CellIdentityNr; 94 import android.telephony.CellIdentityWcdma; 95 import android.telephony.CellInfo; 96 import android.telephony.CellInfoGsm; 97 import android.telephony.CellInfoLte; 98 import android.telephony.CellInfoNr; 99 import android.telephony.CellInfoWcdma; 100 import android.telephony.SmsMessage; 101 import android.telephony.SubscriptionManager; 102 import android.telephony.TelephonyManager; 103 import android.text.TextUtils; 104 import android.text.format.DateUtils; 105 import android.util.Log; 106 import android.util.Pair; 107 import android.util.TimeUtils; 108 109 import com.android.internal.annotations.GuardedBy; 110 import com.android.internal.app.IBatteryStats; 111 import com.android.internal.location.GpsNetInitiatedHandler; 112 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification; 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 301 /** 302 * Properties loaded from PROPERTIES_FILE. 303 * It must be accessed only inside {@link #mHandler}. 304 */ 305 private final GnssConfiguration mGnssConfiguration; 306 307 private String mSuplServerHost; 308 private int mSuplServerPort = TCP_MIN_PORT; 309 private String mC2KServerHost; 310 private int mC2KServerPort; 311 private boolean mSuplEsEnabled = false; 312 313 private final LocationExtras mLocationExtras = new LocationExtras(); 314 private final NetworkTimeHelper mNetworkTimeHelper; 315 private final GnssSatelliteBlocklistHelper mGnssSatelliteBlocklistHelper; 316 317 // Available only on GNSS HAL 2.0 implementations and later. 318 private GnssVisibilityControl mGnssVisibilityControl; 319 320 private final GnssNetworkConnectivityHandler mNetworkConnectivityHandler; 321 private final GpsNetInitiatedHandler mNIHandler; 322 323 // Wakelocks 324 private final PowerManager.WakeLock mWakeLock; 325 326 private final AlarmManager mAlarmManager; 327 private final AlarmManager.OnAlarmListener mWakeupListener = this::startNavigating; 328 private final AlarmManager.OnAlarmListener mTimeoutListener = this::hibernate; 329 330 private final AppOpsManager mAppOps; 331 private final IBatteryStats mBatteryStats; 332 333 @GuardedBy("mLock") 334 private final ArrayList<Runnable> mFlushListeners = new ArrayList<>(0); 335 336 // GNSS Metrics 337 private final GnssMetrics mGnssMetrics; 338 339 /** 340 * Implements {@link GnssSatelliteBlocklistCallback#onUpdateSatelliteBlocklist}. 341 */ 342 @Override onUpdateSatelliteBlocklist(int[] constellations, int[] svids)343 public void onUpdateSatelliteBlocklist(int[] constellations, int[] svids) { 344 mHandler.post(() -> mGnssConfiguration.setSatelliteBlocklist(constellations, svids)); 345 mGnssMetrics.resetConstellationTypes(); 346 } 347 subscriptionOrCarrierConfigChanged()348 private void subscriptionOrCarrierConfigChanged() { 349 if (DEBUG) Log.d(TAG, "received SIM related action: "); 350 TelephonyManager phone = (TelephonyManager) 351 mContext.getSystemService(Context.TELEPHONY_SERVICE); 352 CarrierConfigManager configManager = (CarrierConfigManager) 353 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 354 int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId(); 355 if (SubscriptionManager.isValidSubscriptionId(ddSubId)) { 356 phone = phone.createForSubscriptionId(ddSubId); 357 } 358 String mccMnc = phone.getSimOperator(); 359 boolean isKeepLppProfile = false; 360 if (!TextUtils.isEmpty(mccMnc)) { 361 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc); 362 if (configManager != null) { 363 PersistableBundle b = SubscriptionManager.isValidSubscriptionId(ddSubId) 364 ? configManager.getConfigForSubId(ddSubId) : null; 365 if (b != null) { 366 isKeepLppProfile = 367 b.getBoolean(CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL); 368 } 369 } 370 if (isKeepLppProfile) { 371 // load current properties for the carrier of ddSubId 372 mGnssConfiguration.loadPropertiesFromCarrierConfig(/* inEmergency= */ false, 373 /* activeSubId= */ -1); 374 String lpp_profile = mGnssConfiguration.getLppProfile(); 375 // set the persist property LPP_PROFILE for the value 376 if (lpp_profile != null) { 377 SystemProperties.set(GnssConfiguration.LPP_PROFILE, lpp_profile); 378 } 379 } else { 380 // reset the persist property 381 SystemProperties.set(GnssConfiguration.LPP_PROFILE, ""); 382 } 383 reloadGpsProperties(); 384 } else { 385 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available"); 386 // Reload gnss config for no SIM case 387 mGnssConfiguration.reloadGpsProperties(); 388 } 389 } 390 reloadGpsProperties()391 private void reloadGpsProperties() { 392 mGnssConfiguration.reloadGpsProperties(); 393 setSuplHostPort(); 394 // TODO: we should get rid of C2K specific setting. 395 mC2KServerHost = mGnssConfiguration.getC2KHost(); 396 mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT); 397 mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec()); 398 mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1; 399 mNIHandler.setSuplEsEnabled(mSuplEsEnabled); 400 if (mGnssVisibilityControl != null) { 401 mGnssVisibilityControl.onConfigurationUpdated(mGnssConfiguration); 402 } 403 } 404 GnssLocationProvider(Context context, GnssNative gnssNative, GnssMetrics gnssMetrics)405 public GnssLocationProvider(Context context, GnssNative gnssNative, 406 GnssMetrics gnssMetrics) { 407 super(FgThread.getExecutor(), CallerIdentity.fromContext(context), PROPERTIES, 408 Collections.emptySet()); 409 410 mContext = context; 411 mGnssNative = gnssNative; 412 mGnssMetrics = gnssMetrics; 413 414 // Create a wake lock 415 PowerManager powerManager = Objects.requireNonNull( 416 mContext.getSystemService(PowerManager.class)); 417 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*location*:" + TAG); 418 mWakeLock.setReferenceCounted(true); 419 420 // Create a separate wake lock for psds downloader as it may be released due to timeout. 421 mDownloadPsdsWakeLock = powerManager.newWakeLock( 422 PowerManager.PARTIAL_WAKE_LOCK, "*location*:PsdsDownload"); 423 mDownloadPsdsWakeLock.setReferenceCounted(true); 424 425 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 426 427 // App ops service to keep track of who is accessing the GPS 428 mAppOps = mContext.getSystemService(AppOpsManager.class); 429 430 // Battery statistics service to be notified when GPS turns on or off 431 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( 432 BatteryStats.SERVICE_NAME)); 433 434 // Construct internal handler 435 mHandler = FgThread.getHandler(); 436 437 // Load GPS configuration and register listeners in the background: 438 // some operations, such as opening files and registering broadcast receivers, can take a 439 // relative long time, so the ctor() is kept to create objects needed by this instance, 440 // while IO initialization and registration is delegated to our internal handler 441 // this approach is just fine because events are posted to our handler anyway 442 mGnssConfiguration = mGnssNative.getConfiguration(); 443 // Create a GPS net-initiated handler (also needed by handleInitialize) 444 GpsNetInitiatedHandler.EmergencyCallCallback emergencyCallCallback = 445 new GpsNetInitiatedHandler.EmergencyCallCallback() { 446 447 @Override 448 public void onEmergencyCallStart(int subId) { 449 if (!mGnssConfiguration.isActiveSimEmergencySuplEnabled()) { 450 return; 451 } 452 mHandler.post(() -> mGnssConfiguration.reloadGpsProperties( 453 mNIHandler.getInEmergency(), subId)); 454 } 455 456 @Override 457 public void onEmergencyCallEnd() { 458 if (!mGnssConfiguration.isActiveSimEmergencySuplEnabled()) { 459 return; 460 } 461 mHandler.postDelayed(() -> mGnssConfiguration.reloadGpsProperties( 462 /* inEmergency= */ false, 463 SubscriptionManager.getDefaultDataSubscriptionId()), 464 TimeUnit.SECONDS.toMillis(mGnssConfiguration.getEsExtensionSec())); 465 } 466 }; 467 mNIHandler = new GpsNetInitiatedHandler(context, 468 mNetInitiatedListener, 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 // hold wake lock while task runs 775 mDownloadPsdsWakeLock.acquire(DOWNLOAD_PSDS_DATA_TIMEOUT_MS); 776 } 777 Log.i(TAG, "WakeLock acquired by handleDownloadPsdsData()"); 778 Executors.newSingleThreadExecutor().execute(() -> { 779 GnssPsdsDownloader psdsDownloader = new GnssPsdsDownloader( 780 mGnssConfiguration.getProperties()); 781 byte[] data = psdsDownloader.downloadPsdsData(psdsType); 782 if (data != null) { 783 mHandler.post(() -> { 784 FrameworkStatsLog.write(FrameworkStatsLog.GNSS_PSDS_DOWNLOAD_REPORTED, 785 psdsType); 786 if (DEBUG) Log.d(TAG, "calling native_inject_psds_data"); 787 mGnssNative.injectPsdsData(data, data.length, psdsType); 788 synchronized (mLock) { 789 mPsdsBackOff.reset(); 790 } 791 }); 792 PackageManager pm = mContext.getPackageManager(); 793 if (pm != null && pm.hasSystemFeature(FEATURE_WATCH) 794 && psdsType == GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX 795 && mGnssConfiguration.isPsdsPeriodicDownloadEnabled()) { 796 if (DEBUG) Log.d(TAG, "scheduling next long term Psds download"); 797 mHandler.removeCallbacksAndMessages(mPsdsPeriodicDownloadToken); 798 mHandler.postDelayed(() -> handleDownloadPsdsData(psdsType), 799 mPsdsPeriodicDownloadToken, 800 GnssPsdsDownloader.PSDS_INTERVAL); 801 } 802 } else { 803 // Try download PSDS data again later according to backoff time. 804 // Since this is delayed and not urgent, we do not hold a wake lock here. 805 // The arg2 below should not be 1 otherwise the wakelock will be under-locked. 806 long backoffMillis; 807 synchronized (mLock) { 808 backoffMillis = mPsdsBackOff.nextBackoffMillis(); 809 } 810 mHandler.postDelayed(() -> handleDownloadPsdsData(psdsType), backoffMillis); 811 } 812 813 // Release wake lock held by task, synchronize on mLock in case multiple 814 // download tasks overrun. 815 synchronized (mLock) { 816 if (mDownloadPsdsWakeLock.isHeld()) { 817 // This wakelock may have time-out, if a timeout was specified. 818 // Catch (and ignore) any timeout exceptions. 819 mDownloadPsdsWakeLock.release(); 820 if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadPsdsData()"); 821 } else { 822 Log.e(TAG, "WakeLock expired before release in " 823 + "handleDownloadPsdsData()"); 824 } 825 } 826 }); 827 } 828 injectLocation(Location location)829 private void injectLocation(Location location) { 830 if (!location.isMock()) { 831 mGnssNative.injectLocation(location); 832 } 833 } 834 setSuplHostPort()835 private void setSuplHostPort() { 836 mSuplServerHost = mGnssConfiguration.getSuplHost(); 837 mSuplServerPort = mGnssConfiguration.getSuplPort(TCP_MIN_PORT); 838 if (mSuplServerHost != null 839 && mSuplServerPort > TCP_MIN_PORT 840 && mSuplServerPort <= TCP_MAX_PORT) { 841 mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, 842 mSuplServerHost, mSuplServerPort); 843 } 844 } 845 846 /** 847 * Checks what SUPL mode to use, according to the AGPS mode as well as the 848 * allowed mode from properties. 849 * 850 * @param agpsEnabled whether AGPS is enabled by settings value 851 * @return SUPL mode (MSA vs MSB vs STANDALONE) 852 */ getSuplMode(boolean agpsEnabled)853 private int getSuplMode(boolean agpsEnabled) { 854 if (agpsEnabled) { 855 int suplMode = mGnssConfiguration.getSuplMode(0); 856 if (suplMode == 0) { 857 return GNSS_POSITION_MODE_STANDALONE; 858 } 859 860 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor 861 // such mode when it is available 862 if (mGnssNative.getCapabilities().hasMsb() && (suplMode & AGPS_SUPL_MODE_MSB) != 0) { 863 return GNSS_POSITION_MODE_MS_BASED; 864 } 865 } 866 return GNSS_POSITION_MODE_STANDALONE; 867 } 868 setGpsEnabled(boolean enabled)869 private void setGpsEnabled(boolean enabled) { 870 synchronized (mLock) { 871 mGpsEnabled = enabled; 872 } 873 } 874 875 /** 876 * Set whether the GnssLocationProvider is suspended. This method was added to help support 877 * power management use cases on automotive devices. 878 */ setAutomotiveGnssSuspended(boolean suspended)879 public void setAutomotiveGnssSuspended(boolean suspended) { 880 synchronized (mLock) { 881 mAutomotiveSuspend = suspended; 882 } 883 mHandler.post(this::updateEnabled); 884 } 885 886 /** 887 * Return whether the GnssLocationProvider is suspended or not. This method was added to help 888 * support power management use cases on automotive devices. 889 */ isAutomotiveGnssSuspended()890 public boolean isAutomotiveGnssSuspended() { 891 synchronized (mLock) { 892 return mAutomotiveSuspend && !mGpsEnabled; 893 } 894 } 895 handleEnable()896 private void handleEnable() { 897 if (DEBUG) Log.d(TAG, "handleEnable"); 898 899 boolean inited = mGnssNative.init(); 900 901 if (inited) { 902 setGpsEnabled(true); 903 mSupportsPsds = mGnssNative.isPsdsSupported(); 904 905 // TODO: remove the following native calls if we can make sure they are redundant. 906 if (mSuplServerHost != null) { 907 mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL, 908 mSuplServerHost, mSuplServerPort); 909 } 910 if (mC2KServerHost != null) { 911 mGnssNative.setAgpsServer(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K, 912 mC2KServerHost, mC2KServerPort); 913 } 914 915 mBatchingEnabled = mGnssNative.initBatching() && mGnssNative.getBatchSize() > 1; 916 if (mGnssVisibilityControl != null) { 917 mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ true); 918 } 919 } else { 920 setGpsEnabled(false); 921 Log.w(TAG, "Failed to enable location provider"); 922 } 923 } 924 handleDisable()925 private void handleDisable() { 926 if (DEBUG) Log.d(TAG, "handleDisable"); 927 928 setGpsEnabled(false); 929 updateClientUids(new WorkSource()); 930 stopNavigating(); 931 stopBatching(); 932 933 if (mGnssVisibilityControl != null) { 934 mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ false); 935 } 936 // do this before releasing wakelock 937 mGnssNative.cleanupBatching(); 938 mGnssNative.cleanup(); 939 } 940 updateEnabled()941 private void updateEnabled() { 942 boolean enabled = false; 943 944 // Generally follow location setting for visible users 945 LocationManager locationManager = mContext.getSystemService(LocationManager.class); 946 Set<UserHandle> visibleUserHandles = 947 mContext.getSystemService(UserManager.class).getVisibleUsers(); 948 for (UserHandle visibleUserHandle : visibleUserHandles) { 949 enabled |= locationManager.isLocationEnabledForUser(visibleUserHandle); 950 } 951 952 // .. but enable anyway, if there's an active bypass request (e.g. ELS or ADAS) 953 enabled |= (mProviderRequest != null 954 && mProviderRequest.isActive() 955 && mProviderRequest.isBypass()); 956 957 // .. disable if automotive device needs to go into suspend 958 synchronized (mLock) { 959 enabled &= !mAutomotiveSuspend; 960 } 961 962 // ... and, finally, disable anyway, if device is being shut down 963 enabled &= !mShutdown; 964 965 if (enabled == isGpsEnabled()) { 966 return; 967 } 968 969 if (enabled) { 970 handleEnable(); 971 } else { 972 handleDisable(); 973 } 974 } 975 isGpsEnabled()976 private boolean isGpsEnabled() { 977 synchronized (mLock) { 978 return mGpsEnabled; 979 } 980 } 981 982 /** 983 * Returns the hardware batch size available in this hardware implementation. If the available 984 * size is variable, for example, based on other operations consuming memory, this is the 985 * minimum size guaranteed to be available for batching operations. 986 */ getBatchSize()987 public int getBatchSize() { 988 return mGnssNative.getBatchSize(); 989 } 990 991 @Override onFlush(Runnable listener)992 protected void onFlush(Runnable listener) { 993 boolean added = false; 994 synchronized (mLock) { 995 if (mBatchingEnabled) { 996 added = mFlushListeners.add(listener); 997 } 998 } 999 if (!added) { 1000 listener.run(); 1001 } else { 1002 mGnssNative.flushBatch(); 1003 } 1004 } 1005 1006 @Override onSetRequest(ProviderRequest request)1007 public void onSetRequest(ProviderRequest request) { 1008 mProviderRequest = request; 1009 updateEnabled(); 1010 updateRequirements(); 1011 } 1012 1013 // Called when the requirements for GPS may have changed updateRequirements()1014 private void updateRequirements() { 1015 if (mProviderRequest == null || mProviderRequest.getWorkSource() == null) { 1016 return; 1017 } 1018 1019 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest); 1020 if (mProviderRequest.isActive() && isGpsEnabled()) { 1021 // update client uids 1022 updateClientUids(mProviderRequest.getWorkSource()); 1023 1024 if (mProviderRequest.getIntervalMillis() <= Integer.MAX_VALUE) { 1025 mFixInterval = (int) mProviderRequest.getIntervalMillis(); 1026 } else { 1027 Log.w(TAG, "interval overflow: " + mProviderRequest.getIntervalMillis()); 1028 mFixInterval = Integer.MAX_VALUE; 1029 } 1030 1031 int batchIntervalMs = max(mFixInterval, MIN_BATCH_INTERVAL_MS); 1032 long batchLengthMs = Math.min(mProviderRequest.getMaxUpdateDelayMillis(), 1033 MAX_BATCH_LENGTH_MS); 1034 1035 // apply request to GPS engine 1036 if (mBatchingEnabled && batchLengthMs / 2 >= batchIntervalMs) { 1037 stopNavigating(); 1038 mFixInterval = batchIntervalMs; 1039 startBatching(batchLengthMs); 1040 } else { 1041 stopBatching(); 1042 1043 if (mStarted && mGnssNative.getCapabilities().hasScheduling()) { 1044 // change period and/or lowPowerMode 1045 if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, 1046 mFixInterval, mProviderRequest.isLowPower())) { 1047 Log.e(TAG, "set_position_mode failed in updateRequirements"); 1048 } 1049 } else if (!mStarted) { 1050 // start GPS 1051 startNavigating(); 1052 } else { 1053 // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING 1054 mAlarmManager.cancel(mTimeoutListener); 1055 if (mFixInterval >= NO_FIX_TIMEOUT) { 1056 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1057 // and our fix interval is not short 1058 mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, 1059 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG, 1060 mTimeoutListener, mHandler); 1061 } 1062 } 1063 } 1064 } else { 1065 updateClientUids(new WorkSource()); 1066 stopNavigating(); 1067 stopBatching(); 1068 } 1069 } 1070 setPositionMode(int mode, int recurrence, int minInterval, boolean lowPowerMode)1071 private boolean setPositionMode(int mode, int recurrence, int minInterval, 1072 boolean lowPowerMode) { 1073 GnssPositionMode positionMode = new GnssPositionMode(mode, recurrence, minInterval, 1074 0, 0, lowPowerMode); 1075 if (mLastPositionMode != null && mLastPositionMode.equals(positionMode)) { 1076 return true; 1077 } 1078 1079 boolean result = mGnssNative.setPositionMode(mode, recurrence, minInterval, 0, 0, 1080 lowPowerMode); 1081 if (result) { 1082 mLastPositionMode = positionMode; 1083 } else { 1084 mLastPositionMode = null; 1085 } 1086 return result; 1087 } 1088 updateClientUids(WorkSource source)1089 private void updateClientUids(WorkSource source) { 1090 if (source.equals(mClientSource)) { 1091 return; 1092 } 1093 1094 // (1) Inform BatteryStats that the list of IDs we're tracking changed. 1095 try { 1096 mBatteryStats.noteGpsChanged(mClientSource, source); 1097 } catch (RemoteException e) { 1098 Log.w(TAG, "RemoteException", e); 1099 } 1100 1101 // (2) Inform AppOps service about the list of changes to UIDs. 1102 1103 // TODO: this doesn't seem correct, work chain attribution tag != package? 1104 List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source); 1105 if (diffs != null) { 1106 List<WorkChain> newChains = diffs[0]; 1107 List<WorkChain> goneChains = diffs[1]; 1108 1109 if (newChains != null) { 1110 for (WorkChain newChain : newChains) { 1111 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(), 1112 newChain.getAttributionTag()); 1113 } 1114 } 1115 1116 if (goneChains != null) { 1117 for (WorkChain goneChain : goneChains) { 1118 mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(), 1119 goneChain.getAttributionTag()); 1120 } 1121 } 1122 1123 mClientSource.transferWorkChains(source); 1124 } 1125 1126 // Update the flat UIDs and names list and inform app-ops of all changes. 1127 // TODO: why is GnssLocationProvider the only component using these deprecated APIs? 1128 WorkSource[] changes = mClientSource.setReturningDiffs(source); 1129 if (changes != null) { 1130 WorkSource newWork = changes[0]; 1131 WorkSource goneWork = changes[1]; 1132 1133 // Update sources that were not previously tracked. 1134 if (newWork != null) { 1135 for (int i = 0; i < newWork.size(); i++) { 1136 mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, 1137 newWork.getUid(i), newWork.getPackageName(i)); 1138 } 1139 } 1140 1141 // Update sources that are no longer tracked. 1142 if (goneWork != null) { 1143 for (int i = 0; i < goneWork.size(); i++) { 1144 mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.getUid(i), 1145 goneWork.getPackageName(i)); 1146 } 1147 } 1148 } 1149 } 1150 1151 @Override onExtraCommand(int uid, int pid, String command, Bundle extras)1152 public void onExtraCommand(int uid, int pid, String command, Bundle extras) { 1153 if ("delete_aiding_data".equals(command)) { 1154 deleteAidingData(extras); 1155 } else if ("force_time_injection".equals(command)) { 1156 demandUtcTimeInjection(); 1157 } else if ("force_psds_injection".equals(command)) { 1158 if (mSupportsPsds) { 1159 postWithWakeLockHeld(() -> handleDownloadPsdsData( 1160 GnssPsdsDownloader.LONG_TERM_PSDS_SERVER_INDEX)); 1161 } 1162 } else if ("request_power_stats".equals(command)) { 1163 mGnssNative.requestPowerStats(); 1164 } else { 1165 Log.w(TAG, "sendExtraCommand: unknown command " + command); 1166 } 1167 } 1168 deleteAidingData(Bundle extras)1169 private void deleteAidingData(Bundle extras) { 1170 int flags; 1171 1172 if (extras == null) { 1173 flags = GNSS_AIDING_TYPE_ALL; 1174 } else { 1175 flags = 0; 1176 if (extras.getBoolean("ephemeris")) flags |= GNSS_AIDING_TYPE_EPHEMERIS; 1177 if (extras.getBoolean("almanac")) flags |= GNSS_AIDING_TYPE_ALMANAC; 1178 if (extras.getBoolean("position")) flags |= GNSS_AIDING_TYPE_POSITION; 1179 if (extras.getBoolean("time")) flags |= GNSS_AIDING_TYPE_TIME; 1180 if (extras.getBoolean("iono")) flags |= GNSS_AIDING_TYPE_IONO; 1181 if (extras.getBoolean("utc")) flags |= GNSS_AIDING_TYPE_UTC; 1182 if (extras.getBoolean("health")) flags |= GNSS_AIDING_TYPE_HEALTH; 1183 if (extras.getBoolean("svdir")) flags |= GNSS_AIDING_TYPE_SVDIR; 1184 if (extras.getBoolean("svsteer")) flags |= GNSS_AIDING_TYPE_SVSTEER; 1185 if (extras.getBoolean("sadata")) flags |= GNSS_AIDING_TYPE_SADATA; 1186 if (extras.getBoolean("rti")) flags |= GNSS_AIDING_TYPE_RTI; 1187 if (extras.getBoolean("celldb-info")) flags |= GNSS_AIDING_TYPE_CELLDB_INFO; 1188 if (extras.getBoolean("all")) flags |= GNSS_AIDING_TYPE_ALL; 1189 } 1190 1191 if (flags != 0) { 1192 mGnssNative.deleteAidingData(flags); 1193 } 1194 } 1195 startNavigating()1196 private void startNavigating() { 1197 if (!mStarted) { 1198 if (DEBUG) Log.d(TAG, "startNavigating"); 1199 mTimeToFirstFix = 0; 1200 mLastFixTime = 0; 1201 setStarted(true); 1202 mPositionMode = GNSS_POSITION_MODE_STANDALONE; 1203 1204 boolean agpsEnabled = 1205 (Settings.Global.getInt(mContext.getContentResolver(), 1206 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0); 1207 mPositionMode = getSuplMode(agpsEnabled); 1208 1209 if (DEBUG) { 1210 String mode; 1211 1212 switch (mPositionMode) { 1213 case GNSS_POSITION_MODE_STANDALONE: 1214 mode = "standalone"; 1215 break; 1216 case GNSS_POSITION_MODE_MS_ASSISTED: 1217 mode = "MS_ASSISTED"; 1218 break; 1219 case GNSS_POSITION_MODE_MS_BASED: 1220 mode = "MS_BASED"; 1221 break; 1222 default: 1223 mode = "unknown"; 1224 break; 1225 } 1226 Log.d(TAG, "setting position_mode to " + mode); 1227 } 1228 1229 int interval = mGnssNative.getCapabilities().hasScheduling() ? mFixInterval : 1000; 1230 if (!setPositionMode(mPositionMode, GNSS_POSITION_RECURRENCE_PERIODIC, 1231 interval, mProviderRequest.isLowPower())) { 1232 setStarted(false); 1233 Log.e(TAG, "set_position_mode failed in startNavigating()"); 1234 return; 1235 } 1236 if (!mGnssNative.start()) { 1237 setStarted(false); 1238 Log.e(TAG, "native_start failed in startNavigating()"); 1239 return; 1240 } 1241 1242 // reset SV count to zero 1243 mLocationExtras.reset(); 1244 mFixRequestTime = SystemClock.elapsedRealtime(); 1245 if (!mGnssNative.getCapabilities().hasScheduling()) { 1246 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT 1247 // and our fix interval is not short 1248 if (mFixInterval >= NO_FIX_TIMEOUT) { 1249 mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, 1250 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, TAG, mTimeoutListener, 1251 mHandler); 1252 } 1253 } 1254 } 1255 } 1256 stopNavigating()1257 private void stopNavigating() { 1258 if (DEBUG) Log.d(TAG, "stopNavigating"); 1259 if (mStarted) { 1260 setStarted(false); 1261 mGnssNative.stop(); 1262 mLastFixTime = 0; 1263 // native_stop() may reset the position mode in hardware. 1264 mLastPositionMode = null; 1265 1266 // reset SV count to zero 1267 mLocationExtras.reset(); 1268 } 1269 mAlarmManager.cancel(mTimeoutListener); 1270 mAlarmManager.cancel(mWakeupListener); 1271 } 1272 startBatching(long batchLengthMs)1273 private void startBatching(long batchLengthMs) { 1274 long batchSize = batchLengthMs / mFixInterval; 1275 1276 if (DEBUG) { 1277 Log.d(TAG, "startBatching " + mFixInterval + " " + batchLengthMs); 1278 } 1279 if (mGnssNative.startBatch(MILLISECONDS.toNanos(mFixInterval), 0, true)) { 1280 mBatchingStarted = true; 1281 1282 if (batchSize < getBatchSize()) { 1283 // if the batch size is smaller than the hardware batch size, use an alarm to flush 1284 // locations as appropriate 1285 mBatchingAlarm = () -> { 1286 boolean flush = false; 1287 synchronized (mLock) { 1288 if (mBatchingAlarm != null) { 1289 flush = true; 1290 mAlarmManager.setExact(ELAPSED_REALTIME_WAKEUP, 1291 SystemClock.elapsedRealtime() + batchLengthMs, TAG, 1292 mBatchingAlarm, FgThread.getHandler()); 1293 } 1294 } 1295 1296 if (flush) { 1297 mGnssNative.flushBatch(); 1298 } 1299 }; 1300 mAlarmManager.setExact(ELAPSED_REALTIME_WAKEUP, 1301 SystemClock.elapsedRealtime() + batchLengthMs, TAG, 1302 mBatchingAlarm, FgThread.getHandler()); 1303 } 1304 } else { 1305 Log.e(TAG, "native_start_batch failed in startBatching()"); 1306 } 1307 } 1308 stopBatching()1309 private void stopBatching() { 1310 if (DEBUG) Log.d(TAG, "stopBatching"); 1311 if (mBatchingStarted) { 1312 if (mBatchingAlarm != null) { 1313 mAlarmManager.cancel(mBatchingAlarm); 1314 mBatchingAlarm = null; 1315 } 1316 mGnssNative.flushBatch(); 1317 mGnssNative.stopBatch(); 1318 mBatchingStarted = false; 1319 } 1320 } 1321 setStarted(boolean started)1322 private void setStarted(boolean started) { 1323 if (mStarted != started) { 1324 mStarted = started; 1325 mStartedChangedElapsedRealtime = SystemClock.elapsedRealtime(); 1326 } 1327 } 1328 hibernate()1329 private void hibernate() { 1330 // stop GPS until our next fix interval arrives 1331 stopNavigating(); 1332 long now = SystemClock.elapsedRealtime(); 1333 mAlarmManager.set(ELAPSED_REALTIME_WAKEUP, now + mFixInterval, TAG, 1334 mWakeupListener, mHandler); 1335 } 1336 handleReportLocation(boolean hasLatLong, Location location)1337 private void handleReportLocation(boolean hasLatLong, Location location) { 1338 if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString()); 1339 1340 location.setExtras(mLocationExtras.getBundle()); 1341 1342 reportLocation(LocationResult.wrap(location).validate()); 1343 1344 if (mStarted) { 1345 mGnssMetrics.logReceivedLocationStatus(hasLatLong); 1346 if (hasLatLong) { 1347 if (location.hasAccuracy()) { 1348 mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy()); 1349 } 1350 if (mTimeToFirstFix > 0) { 1351 int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime); 1352 mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes); 1353 } 1354 } 1355 } else { 1356 // Warn or error about long delayed GNSS engine shutdown as this generally wastes 1357 // power and sends location when not expected. 1358 long locationAfterStartedFalseMillis = 1359 SystemClock.elapsedRealtime() - mStartedChangedElapsedRealtime; 1360 if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS) { 1361 String logMessage = "Unexpected GNSS Location report " 1362 + TimeUtils.formatDuration(locationAfterStartedFalseMillis) 1363 + " after location turned off"; 1364 if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS) { 1365 Log.e(TAG, logMessage); 1366 } else { 1367 Log.w(TAG, logMessage); 1368 } 1369 } 1370 } 1371 1372 mLastFixTime = SystemClock.elapsedRealtime(); 1373 // report time to first fix 1374 if (mTimeToFirstFix == 0 && hasLatLong) { 1375 mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime); 1376 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix); 1377 if (mStarted) { 1378 mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix); 1379 } 1380 } 1381 1382 if (mStarted) { 1383 // For devices that use framework scheduling, a timer may be set to ensure we don't 1384 // spend too much power searching for a location, when the requested update rate is 1385 // slow. 1386 // As we just recievied a location, we'll cancel that timer. 1387 if (!mGnssNative.getCapabilities().hasScheduling() && mFixInterval < NO_FIX_TIMEOUT) { 1388 mAlarmManager.cancel(mTimeoutListener); 1389 } 1390 } 1391 1392 if (!mGnssNative.getCapabilities().hasScheduling() && mStarted 1393 && mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) { 1394 if (DEBUG) Log.d(TAG, "got fix, hibernating"); 1395 hibernate(); 1396 } 1397 } 1398 handleReportSvStatus(GnssStatus gnssStatus)1399 private void handleReportSvStatus(GnssStatus gnssStatus) { 1400 // Log CN0 as part of GNSS metrics 1401 mGnssMetrics.logCn0(gnssStatus); 1402 1403 if (VERBOSE) { 1404 Log.v(TAG, "SV count: " + gnssStatus.getSatelliteCount()); 1405 } 1406 1407 Set<Pair<Integer, Integer>> satellites = new HashSet<>(); 1408 int usedInFixCount = 0; 1409 int maxCn0 = 0; 1410 int meanCn0 = 0; 1411 for (int i = 0; i < gnssStatus.getSatelliteCount(); i++) { 1412 if (gnssStatus.usedInFix(i)) { 1413 satellites.add( 1414 new Pair<>(gnssStatus.getConstellationType(i), gnssStatus.getSvid(i))); 1415 ++usedInFixCount; 1416 if (gnssStatus.getCn0DbHz(i) > maxCn0) { 1417 maxCn0 = (int) gnssStatus.getCn0DbHz(i); 1418 } 1419 meanCn0 += gnssStatus.getCn0DbHz(i); 1420 mGnssMetrics.logConstellationType(gnssStatus.getConstellationType(i)); 1421 } 1422 } 1423 if (usedInFixCount > 0) { 1424 meanCn0 /= usedInFixCount; 1425 } 1426 // return number of sats used in fix instead of total reported 1427 mLocationExtras.set(satellites.size(), meanCn0, maxCn0); 1428 1429 mGnssMetrics.logSvStatus(gnssStatus); 1430 } 1431 restartLocationRequest()1432 private void restartLocationRequest() { 1433 if (DEBUG) Log.d(TAG, "restartLocationRequest"); 1434 setStarted(false); 1435 updateRequirements(); 1436 } 1437 1438 //============================================================= 1439 // NI Client support 1440 //============================================================= 1441 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() { 1442 // Sends a response for an NI request to HAL. 1443 @Override 1444 public boolean sendNiResponse(int notificationId, int userResponse) { 1445 // TODO Add Permission check 1446 1447 if (DEBUG) { 1448 Log.d(TAG, "sendNiResponse, notifId: " + notificationId 1449 + ", response: " + userResponse); 1450 } 1451 mGnssNative.sendNiResponse(notificationId, userResponse); 1452 1453 FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED, 1454 FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE, 1455 notificationId, 1456 /* niType= */ 0, 1457 /* needNotify= */ false, 1458 /* needVerify= */ false, 1459 /* privacyOverride= */ false, 1460 /* timeout= */ 0, 1461 /* defaultResponse= */ 0, 1462 /* requestorId= */ null, 1463 /* text= */ null, 1464 /* requestorIdEncoding= */ 0, 1465 /* textEncoding= */ 0, 1466 mSuplEsEnabled, 1467 isGpsEnabled(), 1468 userResponse); 1469 1470 return true; 1471 } 1472 }; 1473 getNetInitiatedListener()1474 public INetInitiatedListener getNetInitiatedListener() { 1475 return mNetInitiatedListener; 1476 } 1477 1478 /** Reports a NI notification. */ reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, int defaultResponse, String requestorId, String text, int requestorIdEncoding, int textEncoding)1479 private void reportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, 1480 int defaultResponse, String requestorId, String text, int requestorIdEncoding, 1481 int textEncoding) { 1482 Log.i(TAG, "reportNiNotification: entered"); 1483 Log.i(TAG, "notificationId: " + notificationId 1484 + ", niType: " + niType 1485 + ", notifyFlags: " + notifyFlags 1486 + ", timeout: " + timeout 1487 + ", defaultResponse: " + defaultResponse); 1488 1489 Log.i(TAG, "requestorId: " + requestorId 1490 + ", text: " + text 1491 + ", requestorIdEncoding: " + requestorIdEncoding 1492 + ", textEncoding: " + textEncoding); 1493 1494 GpsNiNotification notification = new GpsNiNotification(); 1495 1496 notification.notificationId = notificationId; 1497 notification.niType = niType; 1498 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0; 1499 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0; 1500 notification.privacyOverride = 1501 (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0; 1502 notification.timeout = timeout; 1503 notification.defaultResponse = defaultResponse; 1504 notification.requestorId = requestorId; 1505 notification.text = text; 1506 notification.requestorIdEncoding = requestorIdEncoding; 1507 notification.textEncoding = textEncoding; 1508 1509 mNIHandler.handleNiNotification(notification); 1510 FrameworkStatsLog.write(FrameworkStatsLog.GNSS_NI_EVENT_REPORTED, 1511 FrameworkStatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_REQUEST, 1512 notification.notificationId, 1513 notification.niType, 1514 notification.needNotify, 1515 notification.needVerify, 1516 notification.privacyOverride, 1517 notification.timeout, 1518 notification.defaultResponse, 1519 notification.requestorId, 1520 notification.text, 1521 notification.requestorIdEncoding, 1522 notification.textEncoding, 1523 mSuplEsEnabled, 1524 isGpsEnabled(), 1525 /* userResponse= */ 0); 1526 } 1527 demandUtcTimeInjection()1528 private void demandUtcTimeInjection() { 1529 if (DEBUG) Log.d(TAG, "demandUtcTimeInjection"); 1530 postWithWakeLockHeld(mNetworkTimeHelper::demandUtcTimeInjection); 1531 } 1532 1533 getCellType(CellInfo ci)1534 private static int getCellType(CellInfo ci) { 1535 if (ci instanceof CellInfoGsm) { 1536 return CellInfo.TYPE_GSM; 1537 } else if (ci instanceof CellInfoWcdma) { 1538 return CellInfo.TYPE_WCDMA; 1539 } else if (ci instanceof CellInfoLte) { 1540 return CellInfo.TYPE_LTE; 1541 } else if (ci instanceof CellInfoNr) { 1542 return CellInfo.TYPE_NR; 1543 } 1544 return CellInfo.TYPE_UNKNOWN; 1545 } 1546 1547 /** 1548 * Extract the CID/CI for GSM/WCDMA/LTE/NR 1549 * 1550 * @return the cell ID or -1 if invalid 1551 */ getCidFromCellIdentity(CellIdentity id)1552 private static long getCidFromCellIdentity(CellIdentity id) { 1553 if (id == null) { 1554 return -1; 1555 } 1556 long cid = -1; 1557 switch(id.getType()) { 1558 case CellInfo.TYPE_GSM: cid = ((CellIdentityGsm) id).getCid(); break; 1559 case CellInfo.TYPE_WCDMA: cid = ((CellIdentityWcdma) id).getCid(); break; 1560 case CellInfo.TYPE_LTE: cid = ((CellIdentityLte) id).getCi(); break; 1561 case CellInfo.TYPE_NR: cid = ((CellIdentityNr) id).getNci(); break; 1562 default: break; 1563 } 1564 // If the CID is unreported 1565 if (cid == (id.getType() == CellInfo.TYPE_NR 1566 ? CellInfo.UNAVAILABLE_LONG : CellInfo.UNAVAILABLE)) { 1567 cid = -1; 1568 } 1569 1570 return cid; 1571 } 1572 setRefLocation(int type, CellIdentity ci)1573 private void setRefLocation(int type, CellIdentity ci) { 1574 String mcc_str = ci.getMccString(); 1575 String mnc_str = ci.getMncString(); 1576 int mcc = mcc_str != null ? Integer.parseInt(mcc_str) : CellInfo.UNAVAILABLE; 1577 int mnc = mnc_str != null ? Integer.parseInt(mnc_str) : CellInfo.UNAVAILABLE; 1578 int lac = CellInfo.UNAVAILABLE; 1579 int tac = CellInfo.UNAVAILABLE; 1580 int pcid = CellInfo.UNAVAILABLE; 1581 int arfcn = CellInfo.UNAVAILABLE; 1582 long cid = CellInfo.UNAVAILABLE_LONG; 1583 1584 switch (type) { 1585 case AGPS_REF_LOCATION_TYPE_GSM_CELLID: 1586 CellIdentityGsm cig = (CellIdentityGsm) ci; 1587 cid = cig.getCid(); 1588 lac = cig.getLac(); 1589 break; 1590 case AGPS_REF_LOCATION_TYPE_UMTS_CELLID: 1591 CellIdentityWcdma ciw = (CellIdentityWcdma) ci; 1592 cid = ciw.getCid(); 1593 lac = ciw.getLac(); 1594 break; 1595 case AGPS_REF_LOCATION_TYPE_LTE_CELLID: 1596 CellIdentityLte cil = (CellIdentityLte) ci; 1597 cid = cil.getCi(); 1598 tac = cil.getTac(); 1599 pcid = cil.getPci(); 1600 break; 1601 case AGPS_REF_LOCATION_TYPE_NR_CELLID: 1602 CellIdentityNr cin = (CellIdentityNr) ci; 1603 cid = cin.getNci(); 1604 tac = cin.getTac(); 1605 pcid = cin.getPci(); 1606 arfcn = cin.getNrarfcn(); 1607 break; 1608 default: 1609 } 1610 1611 mGnssNative.setAgpsReferenceLocationCellId( 1612 type, mcc, mnc, lac, cid, tac, pcid, arfcn); 1613 } 1614 requestRefLocation()1615 private void requestRefLocation() { 1616 TelephonyManager phone = (TelephonyManager) 1617 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1618 1619 final int phoneType = phone.getPhoneType(); 1620 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { 1621 1622 List<CellInfo> cil = phone.getAllCellInfo(); 1623 if (cil != null) { 1624 HashMap<Integer, CellIdentity> cellIdentityMap = new HashMap<>(); 1625 cil.sort(Comparator.comparingInt( 1626 (CellInfo ci) -> ci.getCellSignalStrength().getAsuLevel()).reversed()); 1627 1628 for (CellInfo ci : cil) { 1629 int status = ci.getCellConnectionStatus(); 1630 if (ci.isRegistered() 1631 || status == CellInfo.CONNECTION_PRIMARY_SERVING 1632 || status == CellInfo.CONNECTION_SECONDARY_SERVING) { 1633 CellIdentity c = ci.getCellIdentity(); 1634 int t = getCellType(ci); 1635 if (getCidFromCellIdentity(c) != -1 1636 && !cellIdentityMap.containsKey(t)) { 1637 cellIdentityMap.put(t, c); 1638 } 1639 } 1640 } 1641 1642 if (cellIdentityMap.containsKey(CellInfo.TYPE_GSM)) { 1643 setRefLocation(AGPS_REF_LOCATION_TYPE_GSM_CELLID, 1644 cellIdentityMap.get(CellInfo.TYPE_GSM)); 1645 } else if (cellIdentityMap.containsKey(CellInfo.TYPE_WCDMA)) { 1646 setRefLocation(AGPS_REF_LOCATION_TYPE_UMTS_CELLID, 1647 cellIdentityMap.get(CellInfo.TYPE_WCDMA)); 1648 } else if (cellIdentityMap.containsKey(CellInfo.TYPE_LTE)) { 1649 setRefLocation(AGPS_REF_LOCATION_TYPE_LTE_CELLID, 1650 cellIdentityMap.get(CellInfo.TYPE_LTE)); 1651 } else if (cellIdentityMap.containsKey(CellInfo.TYPE_NR)) { 1652 setRefLocation(AGPS_REF_LOCATION_TYPE_NR_CELLID, 1653 cellIdentityMap.get(CellInfo.TYPE_NR)); 1654 } else { 1655 Log.e(TAG, "No available serving cell information."); 1656 } 1657 } else { 1658 Log.e(TAG, "Error getting cell location info."); 1659 } 1660 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { 1661 Log.e(TAG, "CDMA not supported."); 1662 } 1663 } 1664 postWithWakeLockHeld(Runnable runnable)1665 private void postWithWakeLockHeld(Runnable runnable) { 1666 // hold a wake lock until this message is delivered 1667 // note that this assumes the message will not be removed from the queue before 1668 // it is handled (otherwise the wake lock would be leaked). 1669 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS); 1670 boolean success = mHandler.post(() -> { 1671 try { 1672 runnable.run(); 1673 } finally { 1674 mWakeLock.release(); 1675 } 1676 }); 1677 if (!success) { 1678 mWakeLock.release(); 1679 } 1680 } 1681 1682 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1683 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1684 boolean dumpAll = false; 1685 1686 int opti = 0; 1687 while (opti < args.length) { 1688 String opt = args[opti]; 1689 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { 1690 break; 1691 } 1692 opti++; 1693 if ("-a".equals(opt)) { 1694 dumpAll = true; 1695 break; 1696 } 1697 } 1698 1699 pw.print("mStarted=" + mStarted + " (changed "); 1700 TimeUtils.formatDuration(SystemClock.elapsedRealtime() 1701 - mStartedChangedElapsedRealtime, pw); 1702 pw.println(" ago)"); 1703 pw.println("mBatchingEnabled=" + mBatchingEnabled); 1704 pw.println("mBatchingStarted=" + mBatchingStarted); 1705 pw.println("mBatchSize=" + getBatchSize()); 1706 pw.println("mFixInterval=" + mFixInterval); 1707 pw.print(mGnssMetrics.dumpGnssMetricsAsText()); 1708 if (dumpAll) { 1709 mNetworkTimeHelper.dump(pw); 1710 pw.println("mSupportsPsds=" + mSupportsPsds); 1711 pw.println( 1712 "PsdsServerConfigured=" + mGnssConfiguration.isLongTermPsdsServerConfigured()); 1713 pw.println("native internal state: "); 1714 pw.println(" " + mGnssNative.getInternalState()); 1715 } 1716 } 1717 1718 @Override onHalRestarted()1719 public void onHalRestarted() { 1720 reloadGpsProperties(); 1721 if (isGpsEnabled()) { 1722 setGpsEnabled(false); 1723 updateEnabled(); 1724 restartLocationRequest(); 1725 } 1726 1727 // Re-register network callbacks to get an update of available networks right away. 1728 synchronized (mLock) { 1729 if (mInitialized) { 1730 mNetworkConnectivityHandler.unregisterNetworkCallbacks(); 1731 mNetworkConnectivityHandler.registerNetworkCallbacks(); 1732 } 1733 } 1734 } 1735 1736 @Override onCapabilitiesChanged(GnssCapabilities oldCapabilities, GnssCapabilities newCapabilities)1737 public void onCapabilitiesChanged(GnssCapabilities oldCapabilities, 1738 GnssCapabilities newCapabilities) { 1739 mHandler.post(() -> { 1740 boolean useOnDemandTimeInjection = mGnssNative.getCapabilities().hasOnDemandTime(); 1741 1742 // b/73893222: There is a historic bug on Android, which means that the capability 1743 // "on demand time" is interpreted as "enable periodic injection" elsewhere but an 1744 // on-demand injection is done here. GNSS developers may have come to rely on the 1745 // periodic behavior, so it has been kept and all methods named to reflect what is 1746 // actually done. "On demand" requests are supported regardless of the capability. 1747 mNetworkTimeHelper.setPeriodicTimeInjectionMode(useOnDemandTimeInjection); 1748 if (useOnDemandTimeInjection) { 1749 demandUtcTimeInjection(); 1750 } 1751 1752 restartLocationRequest(); 1753 }); 1754 } 1755 1756 @Override onReportLocation(boolean hasLatLong, Location location)1757 public void onReportLocation(boolean hasLatLong, Location location) { 1758 postWithWakeLockHeld(() -> handleReportLocation(hasLatLong, location)); 1759 } 1760 1761 @Override onReportLocations(Location[] locations)1762 public void onReportLocations(Location[] locations) { 1763 if (DEBUG) { 1764 Log.d(TAG, "Location batch of size " + locations.length + " reported"); 1765 } 1766 1767 if (locations.length > 0) { 1768 // attempt to fix up timestamps if necessary 1769 if (locations.length > 1) { 1770 // check any realtimes outside of expected bounds 1771 boolean fixRealtime = false; 1772 for (int i = locations.length - 2; i >= 0; i--) { 1773 long timeDeltaMs = locations[i + 1].getTime() - locations[i].getTime(); 1774 long realtimeDeltaMs = locations[i + 1].getElapsedRealtimeMillis() 1775 - locations[i].getElapsedRealtimeMillis(); 1776 if (abs(timeDeltaMs - realtimeDeltaMs) > MAX_BATCH_TIMESTAMP_DELTA_MS) { 1777 fixRealtime = true; 1778 break; 1779 } 1780 } 1781 1782 if (fixRealtime) { 1783 // sort for monotonically increasing time before fixing realtime - realtime will 1784 // thus also be monotonically increasing 1785 Arrays.sort(locations, 1786 Comparator.comparingLong(Location::getTime)); 1787 1788 long expectedDeltaMs = 1789 locations[locations.length - 1].getTime() 1790 - locations[locations.length - 1].getElapsedRealtimeMillis(); 1791 for (int i = locations.length - 2; i >= 0; i--) { 1792 locations[i].setElapsedRealtimeNanos( 1793 MILLISECONDS.toNanos( 1794 max(locations[i].getTime() - expectedDeltaMs, 0))); 1795 } 1796 } else { 1797 // sort for monotonically increasing realttime 1798 Arrays.sort(locations, 1799 Comparator.comparingLong(Location::getElapsedRealtimeNanos)); 1800 } 1801 } 1802 1803 reportLocation(LocationResult.wrap(locations).validate()); 1804 } 1805 1806 Runnable[] listeners; 1807 synchronized (mLock) { 1808 listeners = mFlushListeners.toArray(new Runnable[0]); 1809 mFlushListeners.clear(); 1810 } 1811 for (Runnable listener : listeners) { 1812 listener.run(); 1813 } 1814 } 1815 1816 @Override onReportSvStatus(GnssStatus gnssStatus)1817 public void onReportSvStatus(GnssStatus gnssStatus) { 1818 postWithWakeLockHeld(() -> handleReportSvStatus(gnssStatus)); 1819 } 1820 1821 @Override onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr)1822 public void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { 1823 mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr); 1824 } 1825 1826 @Override onRequestPsdsDownload(int psdsType)1827 public void onRequestPsdsDownload(int psdsType) { 1828 postWithWakeLockHeld(() -> handleDownloadPsdsData(psdsType)); 1829 } 1830 1831 @Override onReportNiNotification(int notificationId, int niType, int notifyFlags, int timeout, int defaultResponse, String requestorId, String text, int requestorIdEncoding, int textEncoding)1832 public void onReportNiNotification(int notificationId, int niType, int notifyFlags, 1833 int timeout, int defaultResponse, String requestorId, String text, 1834 int requestorIdEncoding, int textEncoding) { 1835 reportNiNotification(notificationId, niType, notifyFlags, timeout, 1836 defaultResponse, requestorId, text, requestorIdEncoding, textEncoding); 1837 } 1838 1839 @Override onRequestSetID(@nssNative.AGpsCallbacks.AgpsSetIdFlags int flags)1840 public void onRequestSetID(@GnssNative.AGpsCallbacks.AgpsSetIdFlags int flags) { 1841 TelephonyManager phone = (TelephonyManager) 1842 mContext.getSystemService(Context.TELEPHONY_SERVICE); 1843 int type = AGPS_SETID_TYPE_NONE; 1844 String setId = null; 1845 1846 int subId = SubscriptionManager.getDefaultDataSubscriptionId(); 1847 if (mGnssConfiguration.isActiveSimEmergencySuplEnabled() && mNIHandler.getInEmergency() 1848 && mNetworkConnectivityHandler.getActiveSubId() >= 0) { 1849 subId = mNetworkConnectivityHandler.getActiveSubId(); 1850 } 1851 if (SubscriptionManager.isValidSubscriptionId(subId)) { 1852 phone = phone.createForSubscriptionId(subId); 1853 } 1854 if ((flags & AGPS_REQUEST_SETID_IMSI) == AGPS_REQUEST_SETID_IMSI) { 1855 setId = phone.getSubscriberId(); 1856 if (setId != null) { 1857 // This means the framework has the SIM card. 1858 type = AGPS_SETID_TYPE_IMSI; 1859 } 1860 } else if ((flags & AGPS_REQUEST_SETID_MSISDN) == AGPS_REQUEST_SETID_MSISDN) { 1861 setId = phone.getLine1Number(); 1862 if (setId != null) { 1863 // This means the framework has the SIM card. 1864 type = AGPS_SETID_TYPE_MSISDN; 1865 } 1866 } 1867 1868 mGnssNative.setAgpsSetId(type, (setId == null) ? "" : setId); 1869 } 1870 1871 @Override onRequestLocation(boolean independentFromGnss, boolean isUserEmergency)1872 public void onRequestLocation(boolean independentFromGnss, boolean isUserEmergency) { 1873 if (DEBUG) { 1874 Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss 1875 + ", isUserEmergency: " 1876 + isUserEmergency); 1877 } 1878 postWithWakeLockHeld(() -> handleRequestLocation(independentFromGnss, isUserEmergency)); 1879 } 1880 1881 @Override onRequestUtcTime()1882 public void onRequestUtcTime() { 1883 demandUtcTimeInjection(); 1884 } 1885 1886 @Override onRequestRefLocation()1887 public void onRequestRefLocation() { 1888 requestRefLocation(); 1889 } 1890 1891 @Override onReportNfwNotification(String proxyAppPackageName, byte protocolStack, String otherProtocolStackName, byte requestor, String requestorId, byte responseType, boolean inEmergencyMode, boolean isCachedLocation)1892 public void onReportNfwNotification(String proxyAppPackageName, byte protocolStack, 1893 String otherProtocolStackName, byte requestor, String requestorId, 1894 byte responseType, boolean inEmergencyMode, boolean isCachedLocation) { 1895 if (mGnssVisibilityControl == null) { 1896 Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl uninitialized."); 1897 return; 1898 } 1899 1900 mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack, 1901 otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode, 1902 isCachedLocation); 1903 } 1904 } 1905