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