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