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