1 /*
2  * Copyright (C) 2008 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;
18 
19 import android.app.AlarmManager;
20 import android.app.AppOpsManager;
21 import android.app.PendingIntent;
22 import android.content.BroadcastReceiver;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.database.ContentObserver;
28 import android.hardware.location.GeofenceHardware;
29 import android.hardware.location.GeofenceHardwareImpl;
30 import android.location.Criteria;
31 import android.location.FusedBatchOptions;
32 import android.location.GnssMeasurementsEvent;
33 import android.location.GnssNavigationMessage;
34 import android.location.GnssStatus;
35 import android.location.IGpsGeofenceHardware;
36 import android.location.INetInitiatedListener;
37 import android.location.Location;
38 import android.location.LocationListener;
39 import android.location.LocationManager;
40 import android.location.LocationProvider;
41 import android.location.LocationRequest;
42 import android.os.AsyncTask;
43 import android.os.BatteryStats;
44 import android.os.Binder;
45 import android.os.Bundle;
46 import android.os.Handler;
47 import android.os.Looper;
48 import android.os.Message;
49 import android.os.PersistableBundle;
50 import android.os.PowerManager;
51 import android.os.PowerManager.ServiceType;
52 import android.os.PowerSaveState;
53 import android.os.RemoteException;
54 import android.os.ServiceManager;
55 import android.os.SystemClock;
56 import android.os.SystemProperties;
57 import android.os.UserHandle;
58 import android.os.WorkSource;
59 import android.os.WorkSource.WorkChain;
60 import android.provider.Settings;
61 import android.telephony.CarrierConfigManager;
62 import android.telephony.SubscriptionManager;
63 import android.telephony.TelephonyManager;
64 import android.telephony.gsm.GsmCellLocation;
65 import android.text.TextUtils;
66 import android.util.Log;
67 import android.util.StatsLog;
68 import android.util.TimeUtils;
69 
70 import com.android.internal.annotations.GuardedBy;
71 import com.android.internal.app.IBatteryStats;
72 import com.android.internal.location.GpsNetInitiatedHandler;
73 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
74 import com.android.internal.location.ProviderProperties;
75 import com.android.internal.location.ProviderRequest;
76 import com.android.internal.location.gnssmetrics.GnssMetrics;
77 import com.android.internal.telephony.TelephonyIntents;
78 import com.android.server.DeviceIdleController;
79 import com.android.server.LocalServices;
80 import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
81 import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
82 
83 import java.io.FileDescriptor;
84 import java.io.PrintWriter;
85 import java.lang.annotation.ElementType;
86 import java.lang.annotation.Retention;
87 import java.lang.annotation.RetentionPolicy;
88 import java.lang.annotation.Target;
89 import java.util.ArrayList;
90 import java.util.Arrays;
91 import java.util.List;
92 
93 /**
94  * A GNSS implementation of LocationProvider used by LocationManager.
95  *
96  * {@hide}
97  */
98 public class GnssLocationProvider extends AbstractLocationProvider implements
99         InjectNtpTimeCallback,
100         GnssSatelliteBlacklistCallback {
101 
102     /**
103      * Indicates that this method is a native entry point. Useful purely for IDEs which can
104      * understand entry points, and thus eliminate incorrect warnings about methods not used.
105      */
106     @Target(ElementType.METHOD)
107     @Retention(RetentionPolicy.SOURCE)
108     private @interface NativeEntryPoint {
109     }
110 
111     private static final String TAG = "GnssLocationProvider";
112 
113     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
114     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
115 
116     private static final ProviderProperties PROPERTIES = new ProviderProperties(
117             true, true, false, false, true, true, true,
118             Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
119 
120     // these need to match GnssPositionMode enum in IGnss.hal
121     private static final int GPS_POSITION_MODE_STANDALONE = 0;
122     private static final int GPS_POSITION_MODE_MS_BASED = 1;
123     private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
124 
125     // these need to match GnssPositionRecurrence enum in IGnss.hal
126     private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
127     private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
128 
129     // these need to match GnssStatusValue enum in IGnssCallback.hal
130     private static final int GPS_STATUS_NONE = 0;
131     private static final int GPS_STATUS_SESSION_BEGIN = 1;
132     private static final int GPS_STATUS_SESSION_END = 2;
133     private static final int GPS_STATUS_ENGINE_ON = 3;
134     private static final int GPS_STATUS_ENGINE_OFF = 4;
135 
136     // these need to match GnssLocationFlags enum in types.hal
137     private static final int LOCATION_INVALID = 0;
138     private static final int LOCATION_HAS_LAT_LONG = 1;
139     private static final int LOCATION_HAS_ALTITUDE = 2;
140     private static final int LOCATION_HAS_SPEED = 4;
141     private static final int LOCATION_HAS_BEARING = 8;
142     private static final int LOCATION_HAS_HORIZONTAL_ACCURACY = 16;
143     private static final int LOCATION_HAS_VERTICAL_ACCURACY = 32;
144     private static final int LOCATION_HAS_SPEED_ACCURACY = 64;
145     private static final int LOCATION_HAS_BEARING_ACCURACY = 128;
146 
147     // these need to match ElapsedRealtimeFlags enum in types.hal
148     private static final int ELAPSED_REALTIME_HAS_TIMESTAMP_NS = 1;
149     private static final int ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS = 2;
150 
151     // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal
152     private static final int GPS_DELETE_EPHEMERIS = 0x0001;
153     private static final int GPS_DELETE_ALMANAC = 0x0002;
154     private static final int GPS_DELETE_POSITION = 0x0004;
155     private static final int GPS_DELETE_TIME = 0x0008;
156     private static final int GPS_DELETE_IONO = 0x0010;
157     private static final int GPS_DELETE_UTC = 0x0020;
158     private static final int GPS_DELETE_HEALTH = 0x0040;
159     private static final int GPS_DELETE_SVDIR = 0x0080;
160     private static final int GPS_DELETE_SVSTEER = 0x0100;
161     private static final int GPS_DELETE_SADATA = 0x0200;
162     private static final int GPS_DELETE_RTI = 0x0400;
163     private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
164     private static final int GPS_DELETE_ALL = 0xFFFF;
165 
166     // The GPS_CAPABILITY_* flags must match Capabilities enum in IGnssCallback.hal
167     private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
168     private static final int GPS_CAPABILITY_MSB = 0x0000002;
169     private static final int GPS_CAPABILITY_MSA = 0x0000004;
170     private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
171     private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
172     public static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
173     public static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
174     public static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
175     public static final int GPS_CAPABILITY_LOW_POWER_MODE = 0x0000100;
176     public static final int GPS_CAPABILITY_SATELLITE_BLACKLIST = 0x0000200;
177     public static final int GPS_CAPABILITY_MEASUREMENT_CORRECTIONS = 0x0000400;
178 
179     // The AGPS SUPL mode
180     private static final int AGPS_SUPL_MODE_MSA = 0x02;
181     private static final int AGPS_SUPL_MODE_MSB = 0x01;
182 
183     private static final int UPDATE_LOW_POWER_MODE = 1;
184     private static final int SET_REQUEST = 3;
185     private static final int INJECT_NTP_TIME = 5;
186     // PSDS stands for Predicted Satellite Data Service
187     private static final int DOWNLOAD_PSDS_DATA = 6;
188     private static final int UPDATE_LOCATION = 7;  // Handle external location from network listener
189     private static final int DOWNLOAD_PSDS_DATA_FINISHED = 11;
190     private static final int INITIALIZE_HANDLER = 13;
191     private static final int REQUEST_LOCATION = 16;
192     private static final int REPORT_LOCATION = 17; // HAL reports location
193     private static final int REPORT_SV_STATUS = 18; // HAL reports SV status
194 
195     // Request setid
196     private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
197     private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
198 
199     // ref. location info
200     private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
201     private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
202 
203     // set id info
204     private static final int AGPS_SETID_TYPE_NONE = 0;
205     private static final int AGPS_SETID_TYPE_IMSI = 1;
206     private static final int AGPS_SETID_TYPE_MSISDN = 2;
207 
208     private static final int GPS_GEOFENCE_UNAVAILABLE = 1 << 0L;
209     private static final int GPS_GEOFENCE_AVAILABLE = 1 << 1L;
210 
211     // GPS Geofence errors. Should match GeofenceStatus enum in IGnssGeofenceCallback.hal.
212     private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
213     private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
214     private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
215     private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
216     private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
217     private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
218 
219     // TCP/IP constants.
220     // Valid TCP/UDP port range is (0, 65535].
221     private static final int TCP_MIN_PORT = 0;
222     private static final int TCP_MAX_PORT = 0xffff;
223 
224     // 1 second, or 1 Hz frequency.
225     private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
226     // Default update duration in milliseconds for REQUEST_LOCATION.
227     private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000;
228     // Update duration extension multiplier for emergency REQUEST_LOCATION.
229     private static final int EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER = 3;
230 
231     /** simpler wrapper for ProviderRequest + Worksource */
232     private static class GpsRequest {
233         public ProviderRequest request;
234         public WorkSource source;
235 
GpsRequest(ProviderRequest request, WorkSource source)236         public GpsRequest(ProviderRequest request, WorkSource source) {
237             this.request = request;
238             this.source = source;
239         }
240     }
241 
242     // Threadsafe class to hold stats reported in the Extras Bundle
243     private static class LocationExtras {
244         private int mSvCount;
245         private int mMeanCn0;
246         private int mMaxCn0;
247         private final Bundle mBundle;
248 
LocationExtras()249         public LocationExtras() {
250             mBundle = new Bundle();
251         }
252 
set(int svCount, int meanCn0, int maxCn0)253         public void set(int svCount, int meanCn0, int maxCn0) {
254             synchronized (this) {
255                 mSvCount = svCount;
256                 mMeanCn0 = meanCn0;
257                 mMaxCn0 = maxCn0;
258             }
259             setBundle(mBundle);
260         }
261 
reset()262         public void reset() {
263             set(0, 0, 0);
264         }
265 
266         // Also used by outside methods to add to other bundles
setBundle(Bundle extras)267         public void setBundle(Bundle extras) {
268             if (extras != null) {
269                 synchronized (this) {
270                     extras.putInt("satellites", mSvCount);
271                     extras.putInt("meanCn0", mMeanCn0);
272                     extras.putInt("maxCn0", mMaxCn0);
273                 }
274             }
275         }
276 
getBundle()277         public Bundle getBundle() {
278             synchronized (this) {
279                 return new Bundle(mBundle);
280             }
281         }
282     }
283 
284     private final Object mLock = new Object();
285 
286     // current status
287     private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
288 
289     // time for last status update
290     private long mStatusUpdateTime = SystemClock.elapsedRealtime();
291 
292     // turn off GPS fix icon if we haven't received a fix in 10 seconds
293     private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
294 
295     // stop trying if we do not receive a fix within 60 seconds
296     private static final int NO_FIX_TIMEOUT = 60 * 1000;
297 
298     // if the fix interval is below this we leave GPS on,
299     // if above then we cycle the GPS driver.
300     // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
301     private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
302 
303     // how long to wait if we have a network error in NTP or PSDS downloading
304     // the initial value of the exponential backoff
305     // current setting - 5 minutes
306     private static final long RETRY_INTERVAL = 5 * 60 * 1000;
307     // how long to wait if we have a network error in NTP or PSDS downloading
308     // the max value of the exponential backoff
309     // current setting - 4 hours
310     private static final long MAX_RETRY_INTERVAL = 4 * 60 * 60 * 1000;
311 
312     // Timeout when holding wakelocks for downloading PSDS data.
313     private static final long DOWNLOAD_PSDS_DATA_TIMEOUT_MS = 60 * 1000;
314 
315     private final ExponentialBackOff mPsdsBackOff = new ExponentialBackOff(RETRY_INTERVAL,
316             MAX_RETRY_INTERVAL);
317 
318     // True if we are enabled
319     @GuardedBy("mLock")
320     private boolean mGpsEnabled;
321 
322     private boolean mShutdown;
323 
324     // states for injecting ntp and downloading psds data
325     private static final int STATE_PENDING_NETWORK = 0;
326     private static final int STATE_DOWNLOADING = 1;
327     private static final int STATE_IDLE = 2;
328 
329     // flags to trigger NTP or PSDS data download when network becomes available
330     // initialized to true so we do NTP and PSDS when the network comes up after booting
331     private int mDownloadPsdsDataPending = STATE_PENDING_NETWORK;
332 
333     // true if GPS is navigating
334     private boolean mNavigating;
335 
336     // requested frequency of fixes, in milliseconds
337     private int mFixInterval = 1000;
338 
339     // true if low power mode for the GNSS chipset is part of the latest request.
340     private boolean mLowPowerMode = false;
341 
342     // true if we started navigation in the HAL, only change value of this in setStarted
343     private boolean mStarted;
344 
345     // for logging of latest change, and warning of ongoing location after a stop
346     private long mStartedChangedElapsedRealtime;
347 
348     // threshold for delay in GNSS engine turning off before warning & error
349     private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000;
350     private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000;
351 
352     // capabilities reported through the top level IGnssCallback.hal
353     private volatile int mTopHalCapabilities;
354 
355     // true if PSDS is supported
356     private boolean mSupportsPsds;
357 
358     // for calculating time to first fix
359     private long mFixRequestTime = 0;
360     // time to first fix for most recent session
361     private int mTimeToFirstFix = 0;
362     // time we received our last fix
363     private long mLastFixTime;
364 
365     private int mPositionMode;
366     private GnssPositionMode mLastPositionMode;
367 
368     // Current request from underlying location clients.
369     private ProviderRequest mProviderRequest;
370     // The WorkSource associated with the most recent client request (i.e, most recent call to
371     // setRequest).
372     private WorkSource mWorkSource = null;
373     // True if gps should be disabled because of PowerManager controls
374     private boolean mDisableGpsForPowerManager = false;
375 
376     /**
377      * True if the device idle controller has determined that the device is stationary. This is only
378      * updated when the device enters idle mode.
379      */
380     private volatile boolean mIsDeviceStationary = false;
381 
382     /**
383      * Properties loaded from PROPERTIES_FILE.
384      * It must be accessed only inside {@link #mHandler}.
385      */
386     private GnssConfiguration mGnssConfiguration;
387 
388     private String mSuplServerHost;
389     private int mSuplServerPort = TCP_MIN_PORT;
390     private String mC2KServerHost;
391     private int mC2KServerPort;
392     private boolean mSuplEsEnabled = false;
393 
394     private final Looper mLooper;
395     private final LocationExtras mLocationExtras = new LocationExtras();
396     private final GnssStatusListenerHelper mGnssStatusListenerHelper;
397     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
398     private final GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
399     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
400     private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
401     private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
402     private final NtpTimeHelper mNtpTimeHelper;
403     private final GnssBatchingProvider mGnssBatchingProvider;
404     private final GnssGeofenceProvider mGnssGeofenceProvider;
405     private final GnssCapabilitiesProvider mGnssCapabilitiesProvider;
406 
407     // Available only on GNSS HAL 2.0 implementations and later.
408     private GnssVisibilityControl mGnssVisibilityControl;
409 
410     // Handler for processing events
411     private Handler mHandler;
412 
413     private final GnssNetworkConnectivityHandler mNetworkConnectivityHandler;
414     private final GpsNetInitiatedHandler mNIHandler;
415 
416     // Wakelocks
417     private final static String WAKELOCK_KEY = "GnssLocationProvider";
418     private final PowerManager.WakeLock mWakeLock;
419     private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderPsdsDownload";
420     @GuardedBy("mLock")
421     private final PowerManager.WakeLock mDownloadPsdsWakeLock;
422 
423     // Alarms
424     private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
425     private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
426 
427     private final PowerManager mPowerManager;
428     private final AlarmManager mAlarmManager;
429     private final PendingIntent mWakeupIntent;
430     private final PendingIntent mTimeoutIntent;
431 
432     private final AppOpsManager mAppOps;
433     private final IBatteryStats mBatteryStats;
434 
435     // Current list of underlying location clients.
436     // only modified on handler thread
437     private WorkSource mClientSource = new WorkSource();
438 
439     private GeofenceHardwareImpl mGeofenceHardwareImpl;
440 
441     // Volatile for simple inter-thread sync on these values.
442     private volatile int mHardwareYear = 0;
443     private volatile String mHardwareModelName;
444 
445     // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
446     // stops output right at 600m/s, depriving this of the information of a device that reaches
447     // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
448     private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
449 
450     private volatile boolean mItarSpeedLimitExceeded = false;
451 
452     // GNSS Metrics
453     private GnssMetrics mGnssMetrics;
454 
getGnssStatusProvider()455     public GnssStatusListenerHelper getGnssStatusProvider() {
456         return mGnssStatusListenerHelper;
457     }
458 
getGpsGeofenceProxy()459     public IGpsGeofenceHardware getGpsGeofenceProxy() {
460         return mGnssGeofenceProvider;
461     }
462 
getGnssMeasurementsProvider()463     public GnssMeasurementsProvider getGnssMeasurementsProvider() {
464         return mGnssMeasurementsProvider;
465     }
466 
getGnssMeasurementCorrectionsProvider()467     public GnssMeasurementCorrectionsProvider getGnssMeasurementCorrectionsProvider() {
468         return mGnssMeasurementCorrectionsProvider;
469     }
470 
getGnssNavigationMessageProvider()471     public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
472         return mGnssNavigationMessageProvider;
473     }
474 
475     private final DeviceIdleController.StationaryListener mDeviceIdleStationaryListener =
476             isStationary -> {
477                 mIsDeviceStationary = isStationary;
478                 // Call updateLowPowerMode on handler thread so it's always called from the same
479                 // thread.
480                 mHandler.sendEmptyMessage(UPDATE_LOW_POWER_MODE);
481             };
482 
483     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
484         @Override
485         public void onReceive(Context context, Intent intent) {
486             String action = intent.getAction();
487             if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
488             if (action == null) {
489                 return;
490             }
491 
492             switch (action) {
493                 case ALARM_WAKEUP:
494                     startNavigating();
495                     break;
496                 case ALARM_TIMEOUT:
497                     hibernate();
498                     break;
499                 case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
500                     DeviceIdleController.LocalService deviceIdleService = LocalServices.getService(
501                             DeviceIdleController.LocalService.class);
502                     if (mPowerManager.isDeviceIdleMode()) {
503                         deviceIdleService.registerStationaryListener(mDeviceIdleStationaryListener);
504                     } else {
505                         deviceIdleService.unregisterStationaryListener(
506                                 mDeviceIdleStationaryListener);
507                     }
508                     // Intentional fall-through.
509                 case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
510                 case Intent.ACTION_SCREEN_OFF:
511                 case Intent.ACTION_SCREEN_ON:
512                     // Call updateLowPowerMode on handler thread so it's always called from the
513                     // same thread.
514                     mHandler.sendEmptyMessage(UPDATE_LOW_POWER_MODE);
515                     break;
516                 case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
517                 case TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
518                     subscriptionOrCarrierConfigChanged(context);
519                     break;
520             }
521         }
522     };
523 
524     /**
525      * Implements {@link GnssSatelliteBlacklistCallback#onUpdateSatelliteBlacklist}.
526      */
527     @Override
onUpdateSatelliteBlacklist(int[] constellations, int[] svids)528     public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
529         mHandler.post(() -> mGnssConfiguration.setSatelliteBlacklist(constellations, svids));
530         mGnssMetrics.resetConstellationTypes();
531     }
532 
subscriptionOrCarrierConfigChanged(Context context)533     private void subscriptionOrCarrierConfigChanged(Context context) {
534         if (DEBUG) Log.d(TAG, "received SIM related action: ");
535         TelephonyManager phone = (TelephonyManager)
536                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
537         CarrierConfigManager configManager = (CarrierConfigManager)
538                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
539         int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
540         if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
541             phone = phone.createForSubscriptionId(ddSubId);
542         }
543         String mccMnc = phone.getSimOperator();
544         boolean isKeepLppProfile = false;
545         if (!TextUtils.isEmpty(mccMnc)) {
546             if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
547             if (configManager != null) {
548                 PersistableBundle b = SubscriptionManager.isValidSubscriptionId(ddSubId)
549                         ? configManager.getConfigForSubId(ddSubId) : null;
550                 if (b != null) {
551                     isKeepLppProfile =
552                             b.getBoolean(CarrierConfigManager.Gps.KEY_PERSIST_LPP_MODE_BOOL);
553                 }
554             }
555             if (isKeepLppProfile) {
556                 // load current properties for the carrier
557                 mGnssConfiguration.loadPropertiesFromCarrierConfig();
558                 String lpp_profile = mGnssConfiguration.getLppProfile();
559                 // set the persist property LPP_PROFILE for the value
560                 if (lpp_profile != null) {
561                     SystemProperties.set(GnssConfiguration.LPP_PROFILE, lpp_profile);
562                 }
563             } else {
564                 // reset the persist property
565                 SystemProperties.set(GnssConfiguration.LPP_PROFILE, "");
566             }
567             reloadGpsProperties();
568         } else {
569             if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
570         }
571     }
572 
updateLowPowerMode()573     private void updateLowPowerMode() {
574         // Disable GPS if we are in device idle mode and the device is stationary.
575         boolean disableGpsForPowerManager = mPowerManager.isDeviceIdleMode() && mIsDeviceStationary;
576         final PowerSaveState result = mPowerManager.getPowerSaveState(ServiceType.LOCATION);
577         switch (result.locationMode) {
578             case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
579             case PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
580                 // If we are in battery saver mode and the screen is off, disable GPS.
581                 disableGpsForPowerManager |=
582                         result.batterySaverEnabled && !mPowerManager.isInteractive();
583                 break;
584         }
585         if (disableGpsForPowerManager != mDisableGpsForPowerManager) {
586             mDisableGpsForPowerManager = disableGpsForPowerManager;
587             updateEnabled();
588             updateRequirements();
589         }
590     }
591 
isSupported()592     public static boolean isSupported() {
593         return native_is_supported();
594     }
595 
reloadGpsProperties()596     private void reloadGpsProperties() {
597         mGnssConfiguration.reloadGpsProperties();
598         setSuplHostPort();
599         // TODO: we should get rid of C2K specific setting.
600         mC2KServerHost = mGnssConfiguration.getC2KHost();
601         mC2KServerPort = mGnssConfiguration.getC2KPort(TCP_MIN_PORT);
602         mNIHandler.setEmergencyExtensionSeconds(mGnssConfiguration.getEsExtensionSec());
603         mSuplEsEnabled = mGnssConfiguration.getSuplEs(0) == 1;
604         mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
605         if (mGnssVisibilityControl != null) {
606             mGnssVisibilityControl.onConfigurationUpdated(mGnssConfiguration);
607         }
608     }
609 
GnssLocationProvider(Context context, LocationProviderManager locationProviderManager, Looper looper)610     public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
611             Looper looper) {
612         super(context, locationProviderManager);
613 
614         mLooper = looper;
615 
616         // Create a wake lock
617         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
618         mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
619         mWakeLock.setReferenceCounted(true);
620 
621         // Create a separate wake lock for psds downloader as it may be released due to timeout.
622         mDownloadPsdsWakeLock = mPowerManager.newWakeLock(
623                 PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY);
624         mDownloadPsdsWakeLock.setReferenceCounted(true);
625 
626         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
627         mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
628         mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
629 
630         mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(context,
631                 GnssLocationProvider.this::onNetworkAvailable, looper);
632 
633         // App ops service to keep track of who is accessing the GPS
634         mAppOps = mContext.getSystemService(AppOpsManager.class);
635 
636         // Battery statistics service to be notified when GPS turns on or off
637         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
638                 BatteryStats.SERVICE_NAME));
639 
640         // Construct internal handler
641         mHandler = new ProviderHandler(looper);
642 
643         // Load GPS configuration and register listeners in the background:
644         // some operations, such as opening files and registering broadcast receivers, can take a
645         // relative long time, so the ctor() is kept to create objects needed by this instance,
646         // while IO initialization and registration is delegated to our internal handler
647         // this approach is just fine because events are posted to our handler anyway
648         mGnssConfiguration = new GnssConfiguration(mContext);
649         mGnssCapabilitiesProvider = new GnssCapabilitiesProvider();
650         // Create a GPS net-initiated handler (also needed by handleInitialize)
651         mNIHandler = new GpsNetInitiatedHandler(context,
652                 mNetInitiatedListener,
653                 mSuplEsEnabled);
654         sendMessage(INITIALIZE_HANDLER, 0, null);
655 
656         mGnssStatusListenerHelper = new GnssStatusListenerHelper(mContext, mHandler) {
657             @Override
658             protected boolean isAvailableInPlatform() {
659                 return isSupported();
660             }
661 
662             @Override
663             protected boolean isGpsEnabled() {
664                 return GnssLocationProvider.this.isGpsEnabled();
665             }
666         };
667 
668         mGnssMeasurementsProvider = new GnssMeasurementsProvider(mContext, mHandler) {
669             @Override
670             protected boolean isGpsEnabled() {
671                 return GnssLocationProvider.this.isGpsEnabled();
672             }
673         };
674 
675         mGnssMeasurementCorrectionsProvider = new GnssMeasurementCorrectionsProvider(mHandler);
676 
677         mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mContext, mHandler) {
678             @Override
679             protected boolean isGpsEnabled() {
680                 return GnssLocationProvider.this.isGpsEnabled();
681             }
682         };
683 
684         mGnssMetrics = new GnssMetrics(mBatteryStats);
685         mNtpTimeHelper = new NtpTimeHelper(mContext, looper, this);
686         GnssSatelliteBlacklistHelper gnssSatelliteBlacklistHelper =
687                 new GnssSatelliteBlacklistHelper(mContext,
688                         looper, this);
689         mHandler.post(gnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
690         mGnssBatchingProvider = new GnssBatchingProvider();
691         mGnssGeofenceProvider = new GnssGeofenceProvider();
692 
693         mContext.registerReceiverAsUser(new BroadcastReceiver() {
694             @Override
695             public void onReceive(Context context, Intent intent) {
696                 if (getSendingUserId() == UserHandle.USER_ALL) {
697                     mShutdown = true;
698                     updateEnabled();
699                 }
700             }
701         }, UserHandle.ALL, new IntentFilter(Intent.ACTION_SHUTDOWN), null, mHandler);
702 
703         mContext.getContentResolver().registerContentObserver(
704                 Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE),
705                 true,
706                 new ContentObserver(mHandler) {
707                     @Override
708                     public void onChange(boolean selfChange) {
709                         updateEnabled();
710                     }
711                 }, UserHandle.USER_ALL);
712 
713         setProperties(PROPERTIES);
714         setEnabled(true);
715     }
716 
717     /**
718      * Implements {@link InjectNtpTimeCallback#injectTime}
719      */
720     @Override
injectTime(long time, long timeReference, int uncertainty)721     public void injectTime(long time, long timeReference, int uncertainty) {
722         native_inject_time(time, timeReference, uncertainty);
723     }
724 
725     /**
726      * Implements {@link GnssNetworkConnectivityHandler.GnssNetworkListener#onNetworkAvailable()}
727      */
onNetworkAvailable()728     private void onNetworkAvailable() {
729         mNtpTimeHelper.onNetworkAvailable();
730         if (mDownloadPsdsDataPending == STATE_PENDING_NETWORK) {
731             if (mSupportsPsds) {
732                 // Download only if supported, (prevents an unnecessary on-boot download)
733                 psdsDownloadRequest();
734             }
735         }
736     }
737 
handleRequestLocation(boolean independentFromGnss, boolean isUserEmergency)738     private void handleRequestLocation(boolean independentFromGnss, boolean isUserEmergency) {
739         if (isRequestLocationRateLimited()) {
740             if (DEBUG) {
741                 Log.d(TAG, "RequestLocation is denied due to too frequent requests.");
742             }
743             return;
744         }
745         ContentResolver resolver = mContext.getContentResolver();
746         long durationMillis = Settings.Global.getLong(
747                 resolver,
748                 Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
749                 LOCATION_UPDATE_DURATION_MILLIS);
750         if (durationMillis == 0) {
751             Log.i(TAG, "GNSS HAL location request is disabled by Settings.");
752             return;
753         }
754 
755         LocationManager locationManager = (LocationManager) mContext.getSystemService(
756                 Context.LOCATION_SERVICE);
757         String provider;
758         LocationChangeListener locationListener;
759         LocationRequest locationRequest = new LocationRequest()
760                 .setInterval(LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS)
761                 .setFastestInterval(LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS);
762 
763         if (independentFromGnss) {
764             // For fast GNSS TTFF
765             provider = LocationManager.NETWORK_PROVIDER;
766             locationListener = mNetworkLocationListener;
767             locationRequest.setQuality(LocationRequest.POWER_LOW);
768         } else {
769             // For Device-Based Hybrid (E911)
770             provider = LocationManager.FUSED_PROVIDER;
771             locationListener = mFusedLocationListener;
772             locationRequest.setQuality(LocationRequest.ACCURACY_FINE);
773         }
774 
775         locationRequest.setProvider(provider);
776 
777         // Ignore location settings if in emergency mode. This is only allowed for
778         // isUserEmergency request (introduced in HAL v2.0), or DBH request in HAL v1.1.
779         if (mNIHandler.getInEmergency()) {
780             GnssConfiguration.HalInterfaceVersion halVersion =
781                     mGnssConfiguration.getHalInterfaceVersion();
782             if (isUserEmergency || (halVersion.mMajor < 2 && !independentFromGnss)) {
783                 locationRequest.setLocationSettingsIgnored(true);
784                 durationMillis *= EMERGENCY_LOCATION_UPDATE_DURATION_MULTIPLIER;
785             }
786         }
787 
788         Log.i(TAG,
789                 String.format(
790                         "GNSS HAL Requesting location updates from %s provider for %d millis.",
791                         provider, durationMillis));
792 
793         try {
794             locationManager.requestLocationUpdates(locationRequest,
795                     locationListener, mHandler.getLooper());
796             locationListener.mNumLocationUpdateRequest++;
797             mHandler.postDelayed(() -> {
798                 if (--locationListener.mNumLocationUpdateRequest == 0) {
799                     Log.i(TAG,
800                             String.format("Removing location updates from %s provider.", provider));
801                     locationManager.removeUpdates(locationListener);
802                 }
803             }, durationMillis);
804         } catch (IllegalArgumentException e) {
805             Log.w(TAG, "Unable to request location.", e);
806         }
807     }
808 
injectBestLocation(Location location)809     private void injectBestLocation(Location location) {
810         if (DEBUG) {
811             Log.d(TAG, "injectBestLocation: " + location);
812         }
813         int gnssLocationFlags = LOCATION_HAS_LAT_LONG |
814                 (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) |
815                 (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) |
816                 (location.hasBearing() ? LOCATION_HAS_BEARING : 0) |
817                 (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0) |
818                 (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0) |
819                 (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0) |
820                 (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0);
821 
822         double latitudeDegrees = location.getLatitude();
823         double longitudeDegrees = location.getLongitude();
824         double altitudeMeters = location.getAltitude();
825         float speedMetersPerSec = location.getSpeed();
826         float bearingDegrees = location.getBearing();
827         float horizontalAccuracyMeters = location.getAccuracy();
828         float verticalAccuracyMeters = location.getVerticalAccuracyMeters();
829         float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond();
830         float bearingAccuracyDegrees = location.getBearingAccuracyDegrees();
831         long timestamp = location.getTime();
832 
833         int elapsedRealtimeFlags = ELAPSED_REALTIME_HAS_TIMESTAMP_NS
834                 | (location.hasElapsedRealtimeUncertaintyNanos()
835                         ? ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0);
836         long elapsedRealtimeNanos = location.getElapsedRealtimeNanos();
837         double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos();
838 
839         native_inject_best_location(
840                 gnssLocationFlags, latitudeDegrees, longitudeDegrees,
841                 altitudeMeters, speedMetersPerSec, bearingDegrees,
842                 horizontalAccuracyMeters, verticalAccuracyMeters,
843                 speedAccuracyMetersPerSecond, bearingAccuracyDegrees, timestamp,
844                 elapsedRealtimeFlags, elapsedRealtimeNanos, elapsedRealtimeUncertaintyNanos);
845     }
846 
847     /** Returns true if the location request is too frequent. */
isRequestLocationRateLimited()848     private boolean isRequestLocationRateLimited() {
849         // TODO: implement exponential backoff.
850         return false;
851     }
852 
handleDownloadPsdsData()853     private void handleDownloadPsdsData() {
854         if (!mSupportsPsds) {
855             // native code reports psds not supported, don't try
856             Log.d(TAG, "handleDownloadPsdsData() called when PSDS not supported");
857             return;
858         }
859         if (mDownloadPsdsDataPending == STATE_DOWNLOADING) {
860             // already downloading data
861             return;
862         }
863         if (!mNetworkConnectivityHandler.isDataNetworkConnected()) {
864             // try again when network is up
865             mDownloadPsdsDataPending = STATE_PENDING_NETWORK;
866             return;
867         }
868         mDownloadPsdsDataPending = STATE_DOWNLOADING;
869 
870         synchronized (mLock) {
871             // hold wake lock while task runs
872             mDownloadPsdsWakeLock.acquire(DOWNLOAD_PSDS_DATA_TIMEOUT_MS);
873         }
874         Log.i(TAG, "WakeLock acquired by handleDownloadPsdsData()");
875         AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
876             GpsPsdsDownloader psdsDownloader = new GpsPsdsDownloader(
877                     mGnssConfiguration.getProperties());
878             byte[] data = psdsDownloader.downloadPsdsData();
879             if (data != null) {
880                 if (DEBUG) Log.d(TAG, "calling native_inject_psds_data");
881                 native_inject_psds_data(data, data.length);
882                 mPsdsBackOff.reset();
883             }
884 
885             sendMessage(DOWNLOAD_PSDS_DATA_FINISHED, 0, null);
886 
887             if (data == null) {
888                 // try again later
889                 // since this is delayed and not urgent we do not hold a wake lock here
890                 mHandler.sendEmptyMessageDelayed(DOWNLOAD_PSDS_DATA,
891                         mPsdsBackOff.nextBackoffMillis());
892             }
893 
894             // Release wake lock held by task, synchronize on mLock in case multiple
895             // download tasks overrun.
896             synchronized (mLock) {
897                 if (mDownloadPsdsWakeLock.isHeld()) {
898                     // This wakelock may have time-out, if a timeout was specified.
899                     // Catch (and ignore) any timeout exceptions.
900                     try {
901                         mDownloadPsdsWakeLock.release();
902                         if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadPsdsData()");
903                     } catch (Exception e) {
904                         Log.i(TAG, "Wakelock timeout & release race exception in "
905                                 + "handleDownloadPsdsData()", e);
906                     }
907                 } else {
908                     Log.e(TAG, "WakeLock expired before release in "
909                             + "handleDownloadPsdsData()");
910                 }
911             }
912         });
913     }
914 
handleUpdateLocation(Location location)915     private void handleUpdateLocation(Location location) {
916         if (location.hasAccuracy()) {
917             if (DEBUG) {
918                 Log.d(TAG, "injectLocation: " + location);
919             }
920             native_inject_location(location.getLatitude(), location.getLongitude(),
921                     location.getAccuracy());
922         }
923     }
924 
setSuplHostPort()925     private void setSuplHostPort() {
926         mSuplServerHost = mGnssConfiguration.getSuplHost();
927         mSuplServerPort = mGnssConfiguration.getSuplPort(TCP_MIN_PORT);
928         if (mSuplServerHost != null
929                 && mSuplServerPort > TCP_MIN_PORT
930                 && mSuplServerPort <= TCP_MAX_PORT) {
931             native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL,
932                     mSuplServerHost, mSuplServerPort);
933         }
934     }
935 
936     /**
937      * Checks what SUPL mode to use, according to the AGPS mode as well as the
938      * allowed mode from properties.
939      *
940      * @param agpsEnabled whether AGPS is enabled by settings value
941      * @return SUPL mode (MSA vs MSB vs STANDALONE)
942      */
getSuplMode(boolean agpsEnabled)943     private int getSuplMode(boolean agpsEnabled) {
944         if (agpsEnabled) {
945             int suplMode = mGnssConfiguration.getSuplMode(0);
946             if (suplMode == 0) {
947                 return GPS_POSITION_MODE_STANDALONE;
948             }
949 
950             // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
951             // such mode when it is available
952             if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
953                 return GPS_POSITION_MODE_MS_BASED;
954             }
955         }
956         return GPS_POSITION_MODE_STANDALONE;
957     }
958 
setGpsEnabled(boolean enabled)959     private void setGpsEnabled(boolean enabled) {
960         synchronized (mLock) {
961             mGpsEnabled = enabled;
962         }
963     }
964 
handleEnable()965     private void handleEnable() {
966         if (DEBUG) Log.d(TAG, "handleEnable");
967 
968         boolean inited = native_init();
969 
970         if (inited) {
971             setGpsEnabled(true);
972             mSupportsPsds = native_supports_psds();
973 
974             // TODO: remove the following native calls if we can make sure they are redundant.
975             if (mSuplServerHost != null) {
976                 native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_SUPL,
977                         mSuplServerHost, mSuplServerPort);
978             }
979             if (mC2KServerHost != null) {
980                 native_set_agps_server(GnssNetworkConnectivityHandler.AGPS_TYPE_C2K,
981                         mC2KServerHost, mC2KServerPort);
982             }
983 
984             mGnssMeasurementsProvider.onGpsEnabledChanged();
985             mGnssNavigationMessageProvider.onGpsEnabledChanged();
986             mGnssBatchingProvider.enable();
987             if (mGnssVisibilityControl != null) {
988                 mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ true);
989             }
990         } else {
991             setGpsEnabled(false);
992             Log.w(TAG, "Failed to enable location provider");
993         }
994     }
995 
handleDisable()996     private void handleDisable() {
997         if (DEBUG) Log.d(TAG, "handleDisable");
998 
999         setGpsEnabled(false);
1000         updateClientUids(new WorkSource());
1001         stopNavigating();
1002         mAlarmManager.cancel(mWakeupIntent);
1003         mAlarmManager.cancel(mTimeoutIntent);
1004 
1005         if (mGnssVisibilityControl != null) {
1006             mGnssVisibilityControl.onGpsEnabledChanged(/* isEnabled= */ false);
1007         }
1008         mGnssBatchingProvider.disable();
1009         // do this before releasing wakelock
1010         native_cleanup();
1011 
1012         mGnssMeasurementsProvider.onGpsEnabledChanged();
1013         mGnssNavigationMessageProvider.onGpsEnabledChanged();
1014     }
1015 
updateEnabled()1016     private void updateEnabled() {
1017         // Generally follow location setting for current user
1018         boolean enabled = mContext.getSystemService(LocationManager.class)
1019                 .isLocationEnabledForUser(UserHandle.CURRENT);
1020 
1021         // ... but disable if PowerManager overrides
1022         enabled &= !mDisableGpsForPowerManager;
1023 
1024         // .. but enable anyway, if there's an active settings-ignored request (e.g. ELS)
1025         enabled |= (mProviderRequest != null && mProviderRequest.reportLocation
1026                         && mProviderRequest.locationSettingsIgnored);
1027 
1028         // ... and, finally, disable anyway, if device is being shut down
1029         enabled &= !mShutdown;
1030 
1031         if (enabled == isGpsEnabled()) {
1032             return;
1033         }
1034 
1035         if (enabled) {
1036             handleEnable();
1037         } else {
1038             handleDisable();
1039         }
1040     }
1041 
isGpsEnabled()1042     private boolean isGpsEnabled() {
1043         synchronized (mLock) {
1044             return mGpsEnabled;
1045         }
1046     }
1047 
1048     @Override
getStatus(Bundle extras)1049     public int getStatus(Bundle extras) {
1050         mLocationExtras.setBundle(extras);
1051         return mStatus;
1052     }
1053 
updateStatus(int status)1054     private void updateStatus(int status) {
1055         if (status != mStatus) {
1056             mStatus = status;
1057             mStatusUpdateTime = SystemClock.elapsedRealtime();
1058         }
1059     }
1060 
1061     @Override
getStatusUpdateTime()1062     public long getStatusUpdateTime() {
1063         return mStatusUpdateTime;
1064     }
1065 
1066     @Override
setRequest(ProviderRequest request, WorkSource source)1067     public void setRequest(ProviderRequest request, WorkSource source) {
1068         sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1069     }
1070 
handleSetRequest(ProviderRequest request, WorkSource source)1071     private void handleSetRequest(ProviderRequest request, WorkSource source) {
1072         mProviderRequest = request;
1073         mWorkSource = source;
1074         updateEnabled();
1075         updateRequirements();
1076     }
1077 
1078     // Called when the requirements for GPS may have changed
updateRequirements()1079     private void updateRequirements() {
1080         if (mProviderRequest == null || mWorkSource == null) {
1081             return;
1082         }
1083 
1084         if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1085         if (mProviderRequest.reportLocation && isGpsEnabled()) {
1086             // update client uids
1087             updateClientUids(mWorkSource);
1088 
1089             mFixInterval = (int) mProviderRequest.interval;
1090             mLowPowerMode = mProviderRequest.lowPowerMode;
1091             // check for overflow
1092             if (mFixInterval != mProviderRequest.interval) {
1093                 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1094                 mFixInterval = Integer.MAX_VALUE;
1095             }
1096 
1097             // apply request to GPS engine
1098             if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1099                 // change period and/or lowPowerMode
1100                 if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1101                         mFixInterval, 0, 0, mLowPowerMode)) {
1102                     Log.e(TAG, "set_position_mode failed in updateRequirements");
1103                 }
1104             } else if (!mStarted) {
1105                 // start GPS
1106                 startNavigating();
1107             } else {
1108                 // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING
1109                 mAlarmManager.cancel(mTimeoutIntent);
1110                 if (mFixInterval >= NO_FIX_TIMEOUT) {
1111                     // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1112                     // and our fix interval is not short
1113                     mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1114                             SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1115                 }
1116             }
1117         } else {
1118             updateClientUids(new WorkSource());
1119 
1120             stopNavigating();
1121             mAlarmManager.cancel(mWakeupIntent);
1122             mAlarmManager.cancel(mTimeoutIntent);
1123         }
1124     }
1125 
setPositionMode(int mode, int recurrence, int minInterval, int preferredAccuracy, int preferredTime, boolean lowPowerMode)1126     private boolean setPositionMode(int mode, int recurrence, int minInterval,
1127             int preferredAccuracy, int preferredTime, boolean lowPowerMode) {
1128         GnssPositionMode positionMode = new GnssPositionMode(mode, recurrence, minInterval,
1129                 preferredAccuracy, preferredTime, lowPowerMode);
1130         if (mLastPositionMode != null && mLastPositionMode.equals(positionMode)) {
1131             return true;
1132         }
1133 
1134         boolean result = native_set_position_mode(mode, recurrence, minInterval,
1135                 preferredAccuracy, preferredTime, lowPowerMode);
1136         if (result) {
1137             mLastPositionMode = positionMode;
1138         } else {
1139             mLastPositionMode = null;
1140         }
1141         return result;
1142     }
1143 
updateClientUids(WorkSource source)1144     private void updateClientUids(WorkSource source) {
1145         if (source.equals(mClientSource)) {
1146             return;
1147         }
1148 
1149         // (1) Inform BatteryStats that the list of IDs we're tracking changed.
1150         try {
1151             mBatteryStats.noteGpsChanged(mClientSource, source);
1152         } catch (RemoteException e) {
1153             Log.w(TAG, "RemoteException", e);
1154         }
1155 
1156         // (2) Inform AppOps service about the list of changes to UIDs.
1157 
1158         List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source);
1159         if (diffs != null) {
1160             List<WorkChain> newChains = diffs[0];
1161             List<WorkChain> goneChains = diffs[1];
1162 
1163             if (newChains != null) {
1164                 for (WorkChain newChain : newChains) {
1165                     mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(),
1166                             newChain.getAttributionTag());
1167                 }
1168             }
1169 
1170             if (goneChains != null) {
1171                 for (WorkChain goneChain : goneChains) {
1172                     mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(),
1173                             goneChain.getAttributionTag());
1174                 }
1175             }
1176 
1177             mClientSource.transferWorkChains(source);
1178         }
1179 
1180         // Update the flat UIDs and names list and inform app-ops of all changes.
1181         WorkSource[] changes = mClientSource.setReturningDiffs(source);
1182         if (changes != null) {
1183             WorkSource newWork = changes[0];
1184             WorkSource goneWork = changes[1];
1185 
1186             // Update sources that were not previously tracked.
1187             if (newWork != null) {
1188                 for (int i = 0; i < newWork.size(); i++) {
1189                     mAppOps.startOpNoThrow(AppOpsManager.OP_GPS,
1190                             newWork.get(i), newWork.getName(i));
1191                 }
1192             }
1193 
1194             // Update sources that are no longer tracked.
1195             if (goneWork != null) {
1196                 for (int i = 0; i < goneWork.size(); i++) {
1197                     mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i));
1198                 }
1199             }
1200         }
1201     }
1202 
1203     @Override
sendExtraCommand(String command, Bundle extras)1204     public void sendExtraCommand(String command, Bundle extras) {
1205 
1206         long identity = Binder.clearCallingIdentity();
1207         try {
1208             if ("delete_aiding_data".equals(command)) {
1209                 deleteAidingData(extras);
1210             } else if ("force_time_injection".equals(command)) {
1211                 requestUtcTime();
1212             } else if ("force_psds_injection".equals(command)) {
1213                 if (mSupportsPsds) {
1214                     psdsDownloadRequest();
1215                 }
1216             } else {
1217                 Log.w(TAG, "sendExtraCommand: unknown command " + command);
1218             }
1219         } finally {
1220             Binder.restoreCallingIdentity(identity);
1221         }
1222     }
1223 
deleteAidingData(Bundle extras)1224     private void deleteAidingData(Bundle extras) {
1225         int flags;
1226 
1227         if (extras == null) {
1228             flags = GPS_DELETE_ALL;
1229         } else {
1230             flags = 0;
1231             if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1232             if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1233             if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1234             if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1235             if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1236             if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1237             if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1238             if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1239             if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1240             if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1241             if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1242             if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1243             if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1244         }
1245 
1246         if (flags != 0) {
1247             native_delete_aiding_data(flags);
1248         }
1249     }
1250 
startNavigating()1251     private void startNavigating() {
1252         if (!mStarted) {
1253             if (DEBUG) Log.d(TAG, "startNavigating");
1254             mTimeToFirstFix = 0;
1255             mLastFixTime = 0;
1256             setStarted(true);
1257             mPositionMode = GPS_POSITION_MODE_STANDALONE;
1258             // Notify about suppressed output, if speed limit was previously exceeded.
1259             // Elsewhere, we check again with every speed output reported.
1260             if (mItarSpeedLimitExceeded) {
1261                 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited  " +
1262                         "until slow enough speed reported.");
1263             }
1264 
1265             boolean agpsEnabled =
1266                     (Settings.Global.getInt(mContext.getContentResolver(),
1267                             Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1268             mPositionMode = getSuplMode(agpsEnabled);
1269 
1270             if (DEBUG) {
1271                 String mode;
1272 
1273                 switch (mPositionMode) {
1274                     case GPS_POSITION_MODE_STANDALONE:
1275                         mode = "standalone";
1276                         break;
1277                     case GPS_POSITION_MODE_MS_ASSISTED:
1278                         mode = "MS_ASSISTED";
1279                         break;
1280                     case GPS_POSITION_MODE_MS_BASED:
1281                         mode = "MS_BASED";
1282                         break;
1283                     default:
1284                         mode = "unknown";
1285                         break;
1286                 }
1287                 Log.d(TAG, "setting position_mode to " + mode);
1288             }
1289 
1290             int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1291             mLowPowerMode = mProviderRequest.lowPowerMode;
1292             if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1293                     interval, 0, 0, mLowPowerMode)) {
1294                 setStarted(false);
1295                 Log.e(TAG, "set_position_mode failed in startNavigating()");
1296                 return;
1297             }
1298             if (!native_start()) {
1299                 setStarted(false);
1300                 Log.e(TAG, "native_start failed in startNavigating()");
1301                 return;
1302             }
1303 
1304             // reset SV count to zero
1305             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
1306             mLocationExtras.reset();
1307             mFixRequestTime = SystemClock.elapsedRealtime();
1308             if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1309                 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1310                 // and our fix interval is not short
1311                 if (mFixInterval >= NO_FIX_TIMEOUT) {
1312                     mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1313                             SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1314                 }
1315             }
1316         }
1317     }
1318 
stopNavigating()1319     private void stopNavigating() {
1320         if (DEBUG) Log.d(TAG, "stopNavigating");
1321         if (mStarted) {
1322             setStarted(false);
1323             native_stop();
1324             mLastFixTime = 0;
1325             // native_stop() may reset the position mode in hardware.
1326             mLastPositionMode = null;
1327 
1328             // reset SV count to zero
1329             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
1330             mLocationExtras.reset();
1331         }
1332     }
1333 
setStarted(boolean started)1334     private void setStarted(boolean started) {
1335         if (mStarted != started) {
1336             mStarted = started;
1337             mStartedChangedElapsedRealtime = SystemClock.elapsedRealtime();
1338         }
1339     }
1340 
hibernate()1341     private void hibernate() {
1342         // stop GPS until our next fix interval arrives
1343         stopNavigating();
1344         mAlarmManager.cancel(mTimeoutIntent);
1345         mAlarmManager.cancel(mWakeupIntent);
1346         long now = SystemClock.elapsedRealtime();
1347         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1348     }
1349 
hasCapability(int capability)1350     private boolean hasCapability(int capability) {
1351         return (mTopHalCapabilities & capability) != 0;
1352     }
1353 
1354     @NativeEntryPoint
reportLocation(boolean hasLatLong, Location location)1355     private void reportLocation(boolean hasLatLong, Location location) {
1356         sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location);
1357     }
1358 
handleReportLocation(boolean hasLatLong, Location location)1359     private void handleReportLocation(boolean hasLatLong, Location location) {
1360         if (location.hasSpeed()) {
1361             mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
1362         }
1363 
1364         if (mItarSpeedLimitExceeded) {
1365             Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
1366                     "  GPS/GNSS Navigation output blocked.");
1367             if (mStarted) {
1368                 mGnssMetrics.logReceivedLocationStatus(false);
1369             }
1370             return;  // No output of location allowed
1371         }
1372 
1373         if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString());
1374 
1375         location.setExtras(mLocationExtras.getBundle());
1376 
1377         reportLocation(location);
1378 
1379         if (mStarted) {
1380             mGnssMetrics.logReceivedLocationStatus(hasLatLong);
1381             if (hasLatLong) {
1382                 if (location.hasAccuracy()) {
1383                     mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy());
1384                 }
1385                 if (mTimeToFirstFix > 0) {
1386                     int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime);
1387                     mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
1388                 }
1389             }
1390         } else {
1391             // Warn or error about long delayed GNSS engine shutdown as this generally wastes
1392             // power and sends location when not expected.
1393             long locationAfterStartedFalseMillis =
1394                     SystemClock.elapsedRealtime() - mStartedChangedElapsedRealtime;
1395             if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS) {
1396                 String logMessage = "Unexpected GNSS Location report "
1397                         + TimeUtils.formatDuration(locationAfterStartedFalseMillis)
1398                         + " after location turned off";
1399                 if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS) {
1400                     Log.e(TAG, logMessage);
1401                 } else {
1402                     Log.w(TAG, logMessage);
1403                 }
1404             }
1405         }
1406 
1407         mLastFixTime = SystemClock.elapsedRealtime();
1408         // report time to first fix
1409         if (mTimeToFirstFix == 0 && hasLatLong) {
1410             mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime);
1411             if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1412             if (mStarted) {
1413                 mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
1414             }
1415 
1416             // notify status listeners
1417             mGnssStatusListenerHelper.onFirstFix(mTimeToFirstFix);
1418         }
1419 
1420         if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1421             // For devices that use framework scheduling, a timer may be set to ensure we don't
1422             // spend too much power searching for a location, when the requested update rate is
1423             // slow.
1424             // As we just recievied a location, we'll cancel that timer.
1425             if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1426                 mAlarmManager.cancel(mTimeoutIntent);
1427             }
1428 
1429             updateStatus(LocationProvider.AVAILABLE);
1430         }
1431 
1432         if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1433                 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1434             if (DEBUG) Log.d(TAG, "got fix, hibernating");
1435             hibernate();
1436         }
1437     }
1438 
1439     @NativeEntryPoint
reportStatus(int status)1440     private void reportStatus(int status) {
1441         if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1442 
1443         boolean wasNavigating = mNavigating;
1444         switch (status) {
1445             case GPS_STATUS_SESSION_BEGIN:
1446                 mNavigating = true;
1447                 break;
1448             case GPS_STATUS_SESSION_END:
1449                 mNavigating = false;
1450                 break;
1451             case GPS_STATUS_ENGINE_ON:
1452                 break;
1453             case GPS_STATUS_ENGINE_OFF:
1454                 mNavigating = false;
1455                 break;
1456         }
1457 
1458         if (wasNavigating != mNavigating) {
1459             mGnssStatusListenerHelper.onStatusChanged(mNavigating);
1460         }
1461     }
1462 
1463     // Helper class to carry data to handler for reportSvStatus
1464     private static class SvStatusInfo {
1465         private int mSvCount;
1466         private int[] mSvidWithFlags;
1467         private float[] mCn0s;
1468         private float[] mSvElevations;
1469         private float[] mSvAzimuths;
1470         private float[] mSvCarrierFreqs;
1471     }
1472 
1473     @NativeEntryPoint
reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs)1474     private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s,
1475             float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) {
1476         SvStatusInfo svStatusInfo = new SvStatusInfo();
1477         svStatusInfo.mSvCount = svCount;
1478         svStatusInfo.mSvidWithFlags = svidWithFlags;
1479         svStatusInfo.mCn0s = cn0s;
1480         svStatusInfo.mSvElevations = svElevations;
1481         svStatusInfo.mSvAzimuths = svAzimuths;
1482         svStatusInfo.mSvCarrierFreqs = svCarrierFreqs;
1483 
1484         sendMessage(REPORT_SV_STATUS, 0, svStatusInfo);
1485     }
1486 
handleReportSvStatus(SvStatusInfo info)1487     private void handleReportSvStatus(SvStatusInfo info) {
1488         mGnssStatusListenerHelper.onSvStatusChanged(
1489                 info.mSvCount,
1490                 info.mSvidWithFlags,
1491                 info.mCn0s,
1492                 info.mSvElevations,
1493                 info.mSvAzimuths,
1494                 info.mSvCarrierFreqs);
1495 
1496         // Log CN0 as part of GNSS metrics
1497         mGnssMetrics.logCn0(info.mCn0s, info.mSvCount, info.mSvCarrierFreqs);
1498 
1499         if (VERBOSE) {
1500             Log.v(TAG, "SV count: " + info.mSvCount);
1501         }
1502         // Calculate number of satellites used in fix.
1503         int usedInFixCount = 0;
1504         int maxCn0 = 0;
1505         int meanCn0 = 0;
1506         for (int i = 0; i < info.mSvCount; i++) {
1507             if ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1508                 ++usedInFixCount;
1509                 if (info.mCn0s[i] > maxCn0) {
1510                     maxCn0 = (int) info.mCn0s[i];
1511                 }
1512                 meanCn0 += info.mCn0s[i];
1513             }
1514             if (VERBOSE) {
1515                 Log.v(TAG, "svid: " + (info.mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1516                         " cn0: " + info.mCn0s[i] +
1517                         " elev: " + info.mSvElevations[i] +
1518                         " azimuth: " + info.mSvAzimuths[i] +
1519                         " carrier frequency: " + info.mSvCarrierFreqs[i] +
1520                         ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1521                                 ? "  " : " E") +
1522                         ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1523                                 ? "  " : " A") +
1524                         ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1525                                 ? "" : "U") +
1526                         ((info.mSvidWithFlags[i] &
1527                                 GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0
1528                                 ? "" : "F"));
1529             }
1530 
1531             if ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1532                 int constellationType =
1533                         (info.mSvidWithFlags[i] >> GnssStatus.CONSTELLATION_TYPE_SHIFT_WIDTH)
1534                                 & GnssStatus.CONSTELLATION_TYPE_MASK;
1535                 mGnssMetrics.logConstellationType(constellationType);
1536             }
1537         }
1538         if (usedInFixCount > 0) {
1539             meanCn0 /= usedInFixCount;
1540         }
1541         // return number of sats used in fix instead of total reported
1542         mLocationExtras.set(usedInFixCount, meanCn0, maxCn0);
1543 
1544         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1545                 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1546             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
1547         }
1548 
1549         mGnssMetrics.logSvStatus(info.mSvCount, info.mSvidWithFlags, info.mSvCarrierFreqs);
1550     }
1551 
1552     @NativeEntryPoint
reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr)1553     private void reportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
1554         mNetworkConnectivityHandler.onReportAGpsStatus(agpsType, agpsStatus, suplIpAddr);
1555     }
1556 
1557     @NativeEntryPoint
reportNmea(long timestamp)1558     private void reportNmea(long timestamp) {
1559         if (!mItarSpeedLimitExceeded) {
1560             int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1561             String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1562             mGnssStatusListenerHelper.onNmeaReceived(timestamp, nmea);
1563         }
1564     }
1565 
1566     @NativeEntryPoint
reportMeasurementData(GnssMeasurementsEvent event)1567     private void reportMeasurementData(GnssMeasurementsEvent event) {
1568         if (!mItarSpeedLimitExceeded) {
1569             // send to handler to allow native to return quickly
1570             mHandler.post(() -> mGnssMeasurementsProvider.onMeasurementsAvailable(event));
1571         }
1572     }
1573 
1574     @NativeEntryPoint
reportNavigationMessage(GnssNavigationMessage event)1575     private void reportNavigationMessage(GnssNavigationMessage event) {
1576         if (!mItarSpeedLimitExceeded) {
1577             // send to handler to allow native to return quickly
1578             mHandler.post(() -> mGnssNavigationMessageProvider.onNavigationMessageAvailable(event));
1579         }
1580     }
1581 
1582     @NativeEntryPoint
setTopHalCapabilities(int topHalCapabilities)1583     private void setTopHalCapabilities(int topHalCapabilities) {
1584         mHandler.post(() -> {
1585             mTopHalCapabilities = topHalCapabilities;
1586 
1587             if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1588                 mNtpTimeHelper.enablePeriodicTimeInjection();
1589                 requestUtcTime();
1590             }
1591 
1592             mGnssMeasurementsProvider.onCapabilitiesUpdated(
1593                     hasCapability(GPS_CAPABILITY_MEASUREMENTS));
1594             mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1595                     hasCapability(GPS_CAPABILITY_NAV_MESSAGES));
1596             restartRequests();
1597 
1598             mGnssCapabilitiesProvider.setTopHalCapabilities(mTopHalCapabilities);
1599         });
1600     }
1601 
1602     @NativeEntryPoint
setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities)1603     private void setSubHalMeasurementCorrectionsCapabilities(int subHalCapabilities) {
1604         mHandler.post(() -> {
1605             if (!mGnssMeasurementCorrectionsProvider.onCapabilitiesUpdated(subHalCapabilities)) {
1606                 return;
1607             }
1608 
1609             mGnssCapabilitiesProvider.setSubHalMeasurementCorrectionsCapabilities(
1610                     subHalCapabilities);
1611         });
1612     }
1613 
restartRequests()1614     private void restartRequests() {
1615         Log.i(TAG, "restartRequests");
1616 
1617         restartLocationRequest();
1618         mGnssMeasurementsProvider.resumeIfStarted();
1619         mGnssNavigationMessageProvider.resumeIfStarted();
1620         mGnssBatchingProvider.resumeIfStarted();
1621         mGnssGeofenceProvider.resumeIfStarted();
1622     }
1623 
restartLocationRequest()1624     private void restartLocationRequest() {
1625         if (DEBUG) Log.d(TAG, "restartLocationRequest");
1626         setStarted(false);
1627         updateRequirements();
1628     }
1629 
1630     @NativeEntryPoint
setGnssYearOfHardware(final int yearOfHardware)1631     private void setGnssYearOfHardware(final int yearOfHardware) {
1632         // mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync
1633         if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1634         mHardwareYear = yearOfHardware;
1635     }
1636 
1637     @NativeEntryPoint
setGnssHardwareModelName(final String modelName)1638     private void setGnssHardwareModelName(final String modelName) {
1639         // mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync
1640         if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName);
1641         mHardwareModelName = modelName;
1642     }
1643 
1644     @NativeEntryPoint
reportGnssServiceDied()1645     private void reportGnssServiceDied() {
1646         if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
1647         mHandler.post(() -> {
1648             setupNativeGnssService(/* reinitializeGnssServiceHandle = */ true);
1649             if (isGpsEnabled()) {
1650                 setGpsEnabled(false);
1651 
1652                 updateEnabled();
1653 
1654                 // resend configuration into the restarted HAL service.
1655                 reloadGpsProperties();
1656             }
1657         });
1658     }
1659 
1660     public interface GnssSystemInfoProvider {
1661         /**
1662          * Returns the year of underlying GPS hardware.
1663          */
getGnssYearOfHardware()1664         int getGnssYearOfHardware();
1665 
1666         /**
1667          * Returns the model name of underlying GPS hardware.
1668          */
getGnssHardwareModelName()1669         String getGnssHardwareModelName();
1670     }
1671 
1672     /**
1673      * @hide
1674      */
getGnssSystemInfoProvider()1675     public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1676         return new GnssSystemInfoProvider() {
1677             @Override
1678             public int getGnssYearOfHardware() {
1679                 return mHardwareYear;
1680             }
1681 
1682             @Override
1683             public String getGnssHardwareModelName() {
1684                 return mHardwareModelName;
1685             }
1686         };
1687     }
1688 
1689     /**
1690      * @hide
1691      */
1692     public GnssBatchingProvider getGnssBatchingProvider() {
1693         return mGnssBatchingProvider;
1694     }
1695 
1696     public interface GnssMetricsProvider {
1697         /**
1698          * Returns GNSS metrics as proto string
1699          */
1700         String getGnssMetricsAsProtoString();
1701     }
1702 
1703     /**
1704      * @hide
1705      */
1706     public GnssMetricsProvider getGnssMetricsProvider() {
1707         return () -> mGnssMetrics.dumpGnssMetricsAsProtoString();
1708     }
1709 
1710     /**
1711      * @hide
1712      */
1713     public GnssCapabilitiesProvider getGnssCapabilitiesProvider() {
1714         return mGnssCapabilitiesProvider;
1715     }
1716 
1717     @NativeEntryPoint
1718     private void reportLocationBatch(Location[] locationArray) {
1719         List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
1720         if (DEBUG) {
1721             Log.d(TAG, "Location batch of size " + locationArray.length + " reported");
1722         }
1723         reportLocation(locations);
1724     }
1725 
1726     @NativeEntryPoint
1727     private void psdsDownloadRequest() {
1728         if (DEBUG) Log.d(TAG, "psdsDownloadRequest");
1729         sendMessage(DOWNLOAD_PSDS_DATA, 0, null);
1730     }
1731 
1732     /**
1733      * Converts the GPS HAL status to the internal Geofence Hardware status.
1734      */
1735     private static int getGeofenceStatus(int status) {
1736         switch (status) {
1737             case GPS_GEOFENCE_OPERATION_SUCCESS:
1738                 return GeofenceHardware.GEOFENCE_SUCCESS;
1739             case GPS_GEOFENCE_ERROR_GENERIC:
1740                 return GeofenceHardware.GEOFENCE_FAILURE;
1741             case GPS_GEOFENCE_ERROR_ID_EXISTS:
1742                 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1743             case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1744                 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1745             case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1746                 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1747             case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1748                 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1749             default:
1750                 return -1;
1751         }
1752     }
1753 
1754     @NativeEntryPoint
1755     private void reportGeofenceTransition(int geofenceId, Location location, int transition,
1756             long transitionTimestamp) {
1757         mHandler.post(() -> {
1758             if (mGeofenceHardwareImpl == null) {
1759                 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1760             }
1761 
1762             mGeofenceHardwareImpl.reportGeofenceTransition(
1763                     geofenceId,
1764                     location,
1765                     transition,
1766                     transitionTimestamp,
1767                     GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1768                     FusedBatchOptions.SourceTechnologies.GNSS);
1769         });
1770     }
1771 
1772     @NativeEntryPoint
1773     private void reportGeofenceStatus(int status, Location location) {
1774         mHandler.post(() -> {
1775             if (mGeofenceHardwareImpl == null) {
1776                 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1777             }
1778             int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1779             if (status == GPS_GEOFENCE_AVAILABLE) {
1780                 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1781             }
1782             mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1783                     GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1784                     monitorStatus,
1785                     location,
1786                     FusedBatchOptions.SourceTechnologies.GNSS);
1787         });
1788     }
1789 
1790     @NativeEntryPoint
1791     private void reportGeofenceAddStatus(int geofenceId, int status) {
1792         mHandler.post(() -> {
1793             if (mGeofenceHardwareImpl == null) {
1794                 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1795             }
1796             mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
1797         });
1798     }
1799 
1800     @NativeEntryPoint
1801     private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1802         mHandler.post(() -> {
1803             if (mGeofenceHardwareImpl == null) {
1804                 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1805             }
1806             mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
1807         });
1808     }
1809 
1810     @NativeEntryPoint
1811     private void reportGeofencePauseStatus(int geofenceId, int status) {
1812         mHandler.post(() -> {
1813             if (mGeofenceHardwareImpl == null) {
1814                 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1815             }
1816             mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
1817         });
1818     }
1819 
1820     @NativeEntryPoint
1821     private void reportGeofenceResumeStatus(int geofenceId, int status) {
1822         mHandler.post(() -> {
1823             if (mGeofenceHardwareImpl == null) {
1824                 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1825             }
1826             mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
1827         });
1828     }
1829 
1830     //=============================================================
1831     // NI Client support
1832     //=============================================================
1833     private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1834         // Sends a response for an NI request to HAL.
1835         @Override
1836         public boolean sendNiResponse(int notificationId, int userResponse) {
1837             // TODO Add Permission check
1838 
1839             if (DEBUG) {
1840                 Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1841                         ", response: " + userResponse);
1842             }
1843             native_send_ni_response(notificationId, userResponse);
1844 
1845             StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED,
1846                     StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_RESPONSE,
1847                     notificationId,
1848                     /* niType= */ 0,
1849                     /* needNotify= */ false,
1850                     /* needVerify= */ false,
1851                     /* privacyOverride= */ false,
1852                     /* timeout= */ 0,
1853                     /* defaultResponse= */ 0,
1854                     /* requestorId= */ null,
1855                     /* text= */ null,
1856                     /* requestorIdEncoding= */ 0,
1857                     /* textEncoding= */ 0,
1858                     mSuplEsEnabled,
1859                     isGpsEnabled(),
1860                     userResponse);
1861 
1862             return true;
1863         }
1864     };
1865 
1866     public INetInitiatedListener getNetInitiatedListener() {
1867         return mNetInitiatedListener;
1868     }
1869 
1870     /** Reports a NI notification. */
1871     @NativeEntryPoint
1872     public void reportNiNotification(
1873             int notificationId,
1874             int niType,
1875             int notifyFlags,
1876             int timeout,
1877             int defaultResponse,
1878             String requestorId,
1879             String text,
1880             int requestorIdEncoding,
1881             int textEncoding
1882     ) {
1883         Log.i(TAG, "reportNiNotification: entered");
1884         Log.i(TAG, "notificationId: " + notificationId +
1885                 ", niType: " + niType +
1886                 ", notifyFlags: " + notifyFlags +
1887                 ", timeout: " + timeout +
1888                 ", defaultResponse: " + defaultResponse);
1889 
1890         Log.i(TAG, "requestorId: " + requestorId +
1891                 ", text: " + text +
1892                 ", requestorIdEncoding: " + requestorIdEncoding +
1893                 ", textEncoding: " + textEncoding);
1894 
1895         GpsNiNotification notification = new GpsNiNotification();
1896 
1897         notification.notificationId = notificationId;
1898         notification.niType = niType;
1899         notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1900         notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1901         notification.privacyOverride =
1902                 (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1903         notification.timeout = timeout;
1904         notification.defaultResponse = defaultResponse;
1905         notification.requestorId = requestorId;
1906         notification.text = text;
1907         notification.requestorIdEncoding = requestorIdEncoding;
1908         notification.textEncoding = textEncoding;
1909 
1910         mNIHandler.handleNiNotification(notification);
1911         StatsLog.write(StatsLog.GNSS_NI_EVENT_REPORTED,
1912                 StatsLog.GNSS_NI_EVENT_REPORTED__EVENT_TYPE__NI_REQUEST,
1913                 notification.notificationId,
1914                 notification.niType,
1915                 notification.needNotify,
1916                 notification.needVerify,
1917                 notification.privacyOverride,
1918                 notification.timeout,
1919                 notification.defaultResponse,
1920                 notification.requestorId,
1921                 notification.text,
1922                 notification.requestorIdEncoding,
1923                 notification.textEncoding,
1924                 mSuplEsEnabled,
1925                 isGpsEnabled(),
1926                 /* userResponse= */ 0);
1927     }
1928 
1929     /**
1930      * We should be careful about receiving null string from the TelephonyManager,
1931      * because sending null String to JNI function would cause a crash.
1932      */
1933     @NativeEntryPoint
1934     private void requestSetID(int flags) {
1935         TelephonyManager phone = (TelephonyManager)
1936                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1937         int type = AGPS_SETID_TYPE_NONE;
1938         String setId = null;
1939 
1940         int ddSubId = SubscriptionManager.getDefaultDataSubscriptionId();
1941         if (SubscriptionManager.isValidSubscriptionId(ddSubId)) {
1942             phone = phone.createForSubscriptionId(ddSubId);
1943         }
1944         if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
1945             setId = phone.getSubscriberId();
1946             if (setId != null) {
1947                 // This means the framework has the SIM card.
1948                 type = AGPS_SETID_TYPE_IMSI;
1949             }
1950         } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
1951             setId = phone.getLine1Number();
1952             if (setId != null) {
1953                 // This means the framework has the SIM card.
1954                 type = AGPS_SETID_TYPE_MSISDN;
1955             }
1956         }
1957 
1958         native_agps_set_id(type, (setId == null) ? "" : setId);
1959     }
1960 
1961     @NativeEntryPoint
1962     private void requestLocation(boolean independentFromGnss, boolean isUserEmergency) {
1963         if (DEBUG) {
1964             Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss
1965                     + ", isUserEmergency: "
1966                     + isUserEmergency);
1967         }
1968         sendMessage(REQUEST_LOCATION, independentFromGnss ? 1 : 0, isUserEmergency);
1969     }
1970 
1971     @NativeEntryPoint
1972     private void requestUtcTime() {
1973         if (DEBUG) Log.d(TAG, "utcTimeRequest");
1974         sendMessage(INJECT_NTP_TIME, 0, null);
1975     }
1976 
1977     @NativeEntryPoint
1978     private void requestRefLocation() {
1979         TelephonyManager phone = (TelephonyManager)
1980                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1981         final int phoneType = phone.getPhoneType();
1982         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
1983             GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
1984             if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
1985                     && (phone.getNetworkOperator().length() > 3)) {
1986                 int type;
1987                 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0, 3));
1988                 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
1989                 int networkType = phone.getNetworkType();
1990                 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
1991                         || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
1992                         || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
1993                         || networkType == TelephonyManager.NETWORK_TYPE_HSPA
1994                         || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
1995                     type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
1996                 } else {
1997                     type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
1998                 }
1999                 native_agps_set_ref_location_cellid(type, mcc, mnc,
2000                         gsm_cell.getLac(), gsm_cell.getCid());
2001             } else {
2002                 Log.e(TAG, "Error getting cell location info.");
2003             }
2004         } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2005             Log.e(TAG, "CDMA not supported.");
2006         }
2007     }
2008 
2009     // Implements method nfwNotifyCb() in IGnssVisibilityControlCallback.hal.
2010     @NativeEntryPoint
2011     private void reportNfwNotification(String proxyAppPackageName, byte protocolStack,
2012             String otherProtocolStackName, byte requestor, String requestorId, byte responseType,
2013             boolean inEmergencyMode, boolean isCachedLocation) {
2014         if (mGnssVisibilityControl == null) {
2015             Log.e(TAG, "reportNfwNotification: mGnssVisibilityControl is not initialized.");
2016             return;
2017         }
2018 
2019         mGnssVisibilityControl.reportNfwNotification(proxyAppPackageName, protocolStack,
2020                 otherProtocolStackName, requestor, requestorId, responseType, inEmergencyMode,
2021                 isCachedLocation);
2022     }
2023 
2024     // Implements method isInEmergencySession() in IGnssVisibilityControlCallback.hal.
2025     @NativeEntryPoint
2026     boolean isInEmergencySession() {
2027         return mNIHandler.getInEmergency();
2028     }
2029 
2030     private void sendMessage(int message, int arg, Object obj) {
2031         // hold a wake lock until this message is delivered
2032         // note that this assumes the message will not be removed from the queue before
2033         // it is handled (otherwise the wake lock would be leaked).
2034         mWakeLock.acquire();
2035         if (DEBUG) {
2036             Log.d(TAG, "WakeLock acquired by sendMessage(" + messageIdAsString(message) + ", " + arg
2037                     + ", " + obj + ")");
2038         }
2039         mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2040     }
2041 
2042     private final class ProviderHandler extends Handler {
2043         public ProviderHandler(Looper looper) {
2044             super(looper, null, true /*async*/);
2045         }
2046 
2047         @Override
2048         public void handleMessage(Message msg) {
2049             int message = msg.what;
2050             switch (message) {
2051                 case SET_REQUEST:
2052                     GpsRequest gpsRequest = (GpsRequest) msg.obj;
2053                     handleSetRequest(gpsRequest.request, gpsRequest.source);
2054                     break;
2055                 case INJECT_NTP_TIME:
2056                     mNtpTimeHelper.retrieveAndInjectNtpTime();
2057                     break;
2058                 case REQUEST_LOCATION:
2059                     handleRequestLocation(msg.arg1 == 1, (boolean) msg.obj);
2060                     break;
2061                 case DOWNLOAD_PSDS_DATA:
2062                     handleDownloadPsdsData();
2063                     break;
2064                 case DOWNLOAD_PSDS_DATA_FINISHED:
2065                     mDownloadPsdsDataPending = STATE_IDLE;
2066                     break;
2067                 case UPDATE_LOCATION:
2068                     handleUpdateLocation((Location) msg.obj);
2069                     break;
2070                 case INITIALIZE_HANDLER:
2071                     handleInitialize();
2072                     break;
2073                 case REPORT_LOCATION:
2074                     handleReportLocation(msg.arg1 == 1, (Location) msg.obj);
2075                     break;
2076                 case REPORT_SV_STATUS:
2077                     handleReportSvStatus((SvStatusInfo) msg.obj);
2078                     break;
2079                 case UPDATE_LOW_POWER_MODE:
2080                     updateLowPowerMode();
2081                     break;
2082             }
2083             if (msg.arg2 == 1) {
2084                 // wakelock was taken for this message, release it
2085                 mWakeLock.release();
2086                 if (DEBUG) {
2087                     Log.d(TAG, "WakeLock released by handleMessage(" + messageIdAsString(message)
2088                             + ", " + msg.arg1 + ", " + msg.obj + ")");
2089                 }
2090             }
2091         }
2092 
2093         /**
2094          * This method is bound to {@link #GnssLocationProvider(Context, LocationProviderManager,
2095          * Looper)}.
2096          * It is in charge of loading properties and registering for events that will be posted to
2097          * this handler.
2098          */
2099         private void handleInitialize() {
2100             // class_init_native() already initializes the GNSS service handle during class loading.
2101             setupNativeGnssService(/* reinitializeGnssServiceHandle = */ false);
2102 
2103             if (native_is_gnss_visibility_control_supported()) {
2104                 mGnssVisibilityControl = new GnssVisibilityControl(mContext, mLooper, mNIHandler);
2105             }
2106 
2107             // load default GPS configuration
2108             // (this configuration might change in the future based on SIM changes)
2109             reloadGpsProperties();
2110 
2111             // listen for events
2112             IntentFilter intentFilter = new IntentFilter();
2113             intentFilter.addAction(ALARM_WAKEUP);
2114             intentFilter.addAction(ALARM_TIMEOUT);
2115             intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2116             intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2117             intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2118             intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2119             intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
2120             intentFilter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
2121             mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2122 
2123             mNetworkConnectivityHandler.registerNetworkCallbacks();
2124 
2125             // listen for PASSIVE_PROVIDER updates
2126             LocationManager locManager =
2127                     (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2128             long minTime = 0;
2129             float minDistance = 0;
2130             LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2131                     LocationManager.PASSIVE_PROVIDER,
2132                     minTime,
2133                     minDistance,
2134                     false);
2135             // Don't keep track of this request since it's done on behalf of other clients
2136             // (which are kept track of separately).
2137             request.setHideFromAppOps(true);
2138             locManager.requestLocationUpdates(
2139                     request,
2140                     new NetworkLocationListener(),
2141                     getLooper());
2142 
2143             updateEnabled();
2144         }
2145     }
2146 
2147     private abstract class LocationChangeListener implements LocationListener {
2148         private int mNumLocationUpdateRequest;
2149 
2150         @Override
2151         public void onStatusChanged(String provider, int status, Bundle extras) {
2152         }
2153 
2154         @Override
2155         public void onProviderEnabled(String provider) {
2156         }
2157 
2158         @Override
2159         public void onProviderDisabled(String provider) {
2160         }
2161     }
2162 
2163     private final class NetworkLocationListener extends LocationChangeListener {
2164         @Override
2165         public void onLocationChanged(Location location) {
2166             // this callback happens on mHandler looper
2167             if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2168                 handleUpdateLocation(location);
2169             }
2170         }
2171     }
2172 
2173     private final class FusedLocationListener extends LocationChangeListener {
2174         @Override
2175         public void onLocationChanged(Location location) {
2176             if (LocationManager.FUSED_PROVIDER.equals(location.getProvider())) {
2177                 injectBestLocation(location);
2178             }
2179         }
2180     }
2181 
2182     /**
2183      * @return A string representing the given message ID.
2184      */
2185     private String messageIdAsString(int message) {
2186         switch (message) {
2187             case SET_REQUEST:
2188                 return "SET_REQUEST";
2189             case INJECT_NTP_TIME:
2190                 return "INJECT_NTP_TIME";
2191             case REQUEST_LOCATION:
2192                 return "REQUEST_LOCATION";
2193             case DOWNLOAD_PSDS_DATA:
2194                 return "DOWNLOAD_PSDS_DATA";
2195             case DOWNLOAD_PSDS_DATA_FINISHED:
2196                 return "DOWNLOAD_PSDS_DATA_FINISHED";
2197             case UPDATE_LOCATION:
2198                 return "UPDATE_LOCATION";
2199             case INITIALIZE_HANDLER:
2200                 return "INITIALIZE_HANDLER";
2201             case REPORT_LOCATION:
2202                 return "REPORT_LOCATION";
2203             case REPORT_SV_STATUS:
2204                 return "REPORT_SV_STATUS";
2205             default:
2206                 return "<Unknown>";
2207         }
2208     }
2209 
2210     @Override
2211     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2212         StringBuilder s = new StringBuilder();
2213         s.append("  mStarted=").append(mStarted).append("   (changed ");
2214         TimeUtils.formatDuration(SystemClock.elapsedRealtime()
2215                 - mStartedChangedElapsedRealtime, s);
2216         s.append(" ago)").append('\n');
2217         s.append("  mFixInterval=").append(mFixInterval).append('\n');
2218         s.append("  mLowPowerMode=").append(mLowPowerMode).append('\n');
2219         s.append("  mGnssMeasurementsProvider.isRegistered()=")
2220                 .append(mGnssMeasurementsProvider.isRegistered()).append('\n');
2221         s.append("  mGnssNavigationMessageProvider.isRegistered()=")
2222                 .append(mGnssNavigationMessageProvider.isRegistered()).append('\n');
2223         s.append("  mDisableGpsForPowerManager=").append(mDisableGpsForPowerManager).append('\n');
2224         s.append("  mTopHalCapabilities=0x").append(Integer.toHexString(mTopHalCapabilities));
2225         s.append(" ( ");
2226         if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2227         if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2228         if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2229         if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2230         if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2231         if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2232         if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2233         if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2234         if (hasCapability(GPS_CAPABILITY_LOW_POWER_MODE)) s.append("LOW_POWER_MODE ");
2235         if (hasCapability(GPS_CAPABILITY_SATELLITE_BLACKLIST)) s.append("SATELLITE_BLACKLIST ");
2236         if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) {
2237             s.append("MEASUREMENT_CORRECTIONS ");
2238         }
2239         s.append(")\n");
2240         if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) {
2241             s.append("  SubHal=MEASUREMENT_CORRECTIONS[");
2242             s.append(mGnssMeasurementCorrectionsProvider.toStringCapabilities());
2243             s.append("]\n");
2244         }
2245         s.append(mGnssMetrics.dumpGnssMetricsAsText());
2246         s.append("  native internal state: ").append(native_get_internal_state());
2247         s.append("\n");
2248         pw.append(s);
2249     }
2250 
2251     private void setupNativeGnssService(boolean reinitializeGnssServiceHandle) {
2252         native_init_once(reinitializeGnssServiceHandle);
2253 
2254         /*
2255          * A cycle of native_init() and native_cleanup() is needed so that callbacks are
2256          * registered after bootup even when location is disabled.
2257          * This will allow Emergency SUPL to work even when location is disabled before device
2258          * restart.
2259          */
2260         boolean isInitialized = native_init();
2261         if (!isInitialized) {
2262             Log.w(TAG, "Native initialization failed.");
2263         } else {
2264             native_cleanup();
2265         }
2266     }
2267 
2268     // preallocated to avoid memory allocation in reportNmea()
2269     private byte[] mNmeaBuffer = new byte[120];
2270 
2271     static {
2272         class_init_native();
2273     }
2274 
2275     private static native void class_init_native();
2276 
2277     private static native boolean native_is_supported();
2278 
2279     private static native boolean native_is_gnss_visibility_control_supported();
2280 
2281     private static native void native_init_once(boolean reinitializeGnssServiceHandle);
2282 
2283     private native boolean native_init();
2284 
2285     private native void native_cleanup();
2286 
2287     private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2288             int preferred_accuracy, int preferred_time, boolean lowPowerMode);
2289 
2290     private native boolean native_start();
2291 
2292     private native boolean native_stop();
2293 
2294     private native void native_delete_aiding_data(int flags);
2295 
2296     private native int native_read_nmea(byte[] buffer, int bufferSize);
2297 
2298     private native void native_inject_best_location(
2299             int gnssLocationFlags, double latitudeDegrees, double longitudeDegrees,
2300             double altitudeMeters, float speedMetersPerSec, float bearingDegrees,
2301             float horizontalAccuracyMeters, float verticalAccuracyMeters,
2302             float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees,
2303             long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos,
2304             double elapsedRealtimeUncertaintyNanos);
2305 
2306     private native void native_inject_location(double latitude, double longitude, float accuracy);
2307 
2308     // PSDS Support
2309     private native void native_inject_time(long time, long timeReference, int uncertainty);
2310 
2311     private native boolean native_supports_psds();
2312 
2313     private native void native_inject_psds_data(byte[] data, int length);
2314 
2315     // DEBUG Support
2316     private native String native_get_internal_state();
2317 
2318     // AGPS Support
2319     private native void native_agps_ni_message(byte[] msg, int length);
2320 
2321     private native void native_set_agps_server(int type, String hostname, int port);
2322 
2323     // Network-initiated (NI) Support
2324     private native void native_send_ni_response(int notificationId, int userResponse);
2325 
2326     // AGPS ril support
2327     private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2328             int lac, int cid);
2329 
2330     private native void native_agps_set_id(int type, String setid);
2331 }
2332