• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Cursor;
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.IGnssStatusListener;
36 import android.location.IGnssStatusProvider;
37 import android.location.IGpsGeofenceHardware;
38 import android.location.ILocationManager;
39 import android.location.INetInitiatedListener;
40 import android.location.Location;
41 import android.location.LocationListener;
42 import android.location.LocationManager;
43 import android.location.LocationProvider;
44 import android.location.LocationRequest;
45 import android.net.ConnectivityManager;
46 import android.net.Network;
47 import android.net.NetworkCapabilities;
48 import android.net.NetworkInfo;
49 import android.net.NetworkRequest;
50 import android.net.Uri;
51 import android.os.AsyncTask;
52 import android.os.BatteryStats;
53 import android.os.Binder;
54 import android.os.Bundle;
55 import android.os.Handler;
56 import android.os.Looper;
57 import android.os.Message;
58 import android.os.PersistableBundle;
59 import android.os.PowerManager;
60 import android.os.PowerManager.ServiceType;
61 import android.os.PowerSaveState;
62 import android.os.RemoteException;
63 import android.os.ServiceManager;
64 import android.os.SystemClock;
65 import android.os.SystemProperties;
66 import android.os.UserHandle;
67 import android.os.WorkSource;
68 import android.os.WorkSource.WorkChain;
69 import android.provider.Settings;
70 import android.provider.Telephony.Carriers;
71 import android.provider.Telephony.Sms.Intents;
72 import android.telephony.CarrierConfigManager;
73 import android.telephony.SubscriptionManager;
74 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
75 import android.telephony.TelephonyManager;
76 import android.telephony.gsm.GsmCellLocation;
77 import android.text.TextUtils;
78 import android.util.Log;
79 
80 import com.android.internal.app.IBatteryStats;
81 import com.android.internal.location.GpsNetInitiatedHandler;
82 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
83 import com.android.internal.location.ProviderProperties;
84 import com.android.internal.location.ProviderRequest;
85 import com.android.internal.location.gnssmetrics.GnssMetrics;
86 import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback;
87 import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback;
88 
89 import libcore.io.IoUtils;
90 
91 import java.io.File;
92 import java.io.FileDescriptor;
93 import java.io.FileInputStream;
94 import java.io.IOException;
95 import java.io.PrintWriter;
96 import java.net.InetAddress;
97 import java.net.UnknownHostException;
98 import java.util.ArrayList;
99 import java.util.Arrays;
100 import java.util.HashMap;
101 import java.util.List;
102 import java.util.Map;
103 import java.util.Map.Entry;
104 import java.util.Properties;
105 
106 /**
107  * A GNSS implementation of LocationProvider used by LocationManager.
108  *
109  * {@hide}
110  */
111 public class GnssLocationProvider implements LocationProviderInterface, InjectNtpTimeCallback,
112         GnssSatelliteBlacklistCallback {
113 
114     private static final String TAG = "GnssLocationProvider";
115 
116     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
117     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
118 
119     private static final ProviderProperties PROPERTIES = new ProviderProperties(
120             true, true, false, false, true, true, true,
121             Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
122 
123     // these need to match GnssPositionMode enum in IGnss.hal
124     private static final int GPS_POSITION_MODE_STANDALONE = 0;
125     private static final int GPS_POSITION_MODE_MS_BASED = 1;
126     private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
127 
128     // these need to match GnssPositionRecurrence enum in IGnss.hal
129     private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
130     private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
131 
132     // these need to match GnssStatusValue enum in IGnssCallback.hal
133     private static final int GPS_STATUS_NONE = 0;
134     private static final int GPS_STATUS_SESSION_BEGIN = 1;
135     private static final int GPS_STATUS_SESSION_END = 2;
136     private static final int GPS_STATUS_ENGINE_ON = 3;
137     private static final int GPS_STATUS_ENGINE_OFF = 4;
138 
139     // these need to match AGnssStatusValue enum in IAGnssCallback.hal
140     /** AGPS status event values. */
141     private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
142     private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
143     private static final int GPS_AGPS_DATA_CONNECTED = 3;
144     private static final int GPS_AGPS_DATA_CONN_DONE = 4;
145     private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
146 
147     // these need to match GnssLocationFlags enum in types.hal
148     private static final int LOCATION_INVALID = 0;
149     private static final int LOCATION_HAS_LAT_LONG = 1;
150     private static final int LOCATION_HAS_ALTITUDE = 2;
151     private static final int LOCATION_HAS_SPEED = 4;
152     private static final int LOCATION_HAS_BEARING = 8;
153     private static final int LOCATION_HAS_HORIZONTAL_ACCURACY = 16;
154     private static final int LOCATION_HAS_VERTICAL_ACCURACY = 32;
155     private static final int LOCATION_HAS_SPEED_ACCURACY = 64;
156     private static final int LOCATION_HAS_BEARING_ACCURACY = 128;
157 
158 
159     // IMPORTANT - the GPS_DELETE_* symbols here must match GnssAidingData enum in IGnss.hal
160     private static final int GPS_DELETE_EPHEMERIS = 0x0001;
161     private static final int GPS_DELETE_ALMANAC = 0x0002;
162     private static final int GPS_DELETE_POSITION = 0x0004;
163     private static final int GPS_DELETE_TIME = 0x0008;
164     private static final int GPS_DELETE_IONO = 0x0010;
165     private static final int GPS_DELETE_UTC = 0x0020;
166     private static final int GPS_DELETE_HEALTH = 0x0040;
167     private static final int GPS_DELETE_SVDIR = 0x0080;
168     private static final int GPS_DELETE_SVSTEER = 0x0100;
169     private static final int GPS_DELETE_SADATA = 0x0200;
170     private static final int GPS_DELETE_RTI = 0x0400;
171     private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
172     private static final int GPS_DELETE_ALL = 0xFFFF;
173 
174     // The GPS_CAPABILITY_* flags must match Capabilities enum in IGnssCallback.hal
175     private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
176     private static final int GPS_CAPABILITY_MSB = 0x0000002;
177     private static final int GPS_CAPABILITY_MSA = 0x0000004;
178     private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
179     private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
180     private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
181     private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
182     private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
183 
184     // The AGPS SUPL mode
185     private static final int AGPS_SUPL_MODE_MSA = 0x02;
186     private static final int AGPS_SUPL_MODE_MSB = 0x01;
187 
188     // these need to match AGnssType enum in IAGnssCallback.hal
189     private static final int AGPS_TYPE_SUPL = 1;
190     private static final int AGPS_TYPE_C2K = 2;
191 
192     // these must match the ApnIpType enum in IAGnss.hal
193     private static final int APN_INVALID = 0;
194     private static final int APN_IPV4 = 1;
195     private static final int APN_IPV6 = 2;
196     private static final int APN_IPV4V6 = 3;
197 
198     // for mAGpsDataConnectionState
199     private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
200     private static final int AGPS_DATA_CONNECTION_OPENING = 1;
201     private static final int AGPS_DATA_CONNECTION_OPEN = 2;
202 
203     // Handler messages
204     private static final int CHECK_LOCATION = 1;
205     private static final int ENABLE = 2;
206     private static final int SET_REQUEST = 3;
207     private static final int UPDATE_NETWORK_STATE = 4;
208     private static final int INJECT_NTP_TIME = 5;
209     private static final int DOWNLOAD_XTRA_DATA = 6;
210     private static final int UPDATE_LOCATION = 7;  // Handle external location from network listener
211     private static final int ADD_LISTENER = 8;
212     private static final int REMOVE_LISTENER = 9;
213     private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
214     private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
215     private static final int INITIALIZE_HANDLER = 13;
216     private static final int REQUEST_SUPL_CONNECTION = 14;
217     private static final int RELEASE_SUPL_CONNECTION = 15;
218     private static final int REQUEST_LOCATION = 16;
219     private static final int REPORT_LOCATION = 17; // HAL reports location
220     private static final int REPORT_SV_STATUS = 18; // HAL reports SV status
221 
222     // Request setid
223     private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
224     private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
225 
226     //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
227     private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
228 
229     // ref. location info
230     private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
231     private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
232 
233     // set id info
234     private static final int AGPS_SETID_TYPE_NONE = 0;
235     private static final int AGPS_SETID_TYPE_IMSI = 1;
236     private static final int AGPS_SETID_TYPE_MSISDN = 2;
237 
238     private static final int GPS_GEOFENCE_UNAVAILABLE = 1 << 0L;
239     private static final int GPS_GEOFENCE_AVAILABLE = 1 << 1L;
240 
241     // GPS Geofence errors. Should match GeofenceStatus enum in IGnssGeofenceCallback.hal.
242     private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
243     private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
244     private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
245     private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
246     private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
247     private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
248 
249     // TCP/IP constants.
250     // Valid TCP/UDP port range is (0, 65535].
251     private static final int TCP_MIN_PORT = 0;
252     private static final int TCP_MAX_PORT = 0xffff;
253 
254     // 1 second, or 1 Hz frequency.
255     private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
256     // Default update duration in milliseconds for REQUEST_LOCATION.
257     private static final long LOCATION_UPDATE_DURATION_MILLIS = 0;
258 
259     /** simpler wrapper for ProviderRequest + Worksource */
260     private static class GpsRequest {
261         public ProviderRequest request;
262         public WorkSource source;
263 
GpsRequest(ProviderRequest request, WorkSource source)264         public GpsRequest(ProviderRequest request, WorkSource source) {
265             this.request = request;
266             this.source = source;
267         }
268     }
269 
270     // Threadsafe class to hold stats reported in the Extras Bundle
271     private static class LocationExtras {
272         private int mSvCount;
273         private int mMeanCn0;
274         private int mMaxCn0;
275         private final Bundle mBundle;
276 
LocationExtras()277         public LocationExtras() {
278             mBundle = new Bundle();
279         }
280 
set(int svCount, int meanCn0, int maxCn0)281         public void set(int svCount, int meanCn0, int maxCn0) {
282             synchronized(this) {
283                 mSvCount = svCount;
284                 mMeanCn0 = meanCn0;
285                 mMaxCn0 = maxCn0;
286             }
287             setBundle(mBundle);
288         }
289 
reset()290         public void reset() {
291             set(0,0,0);
292         }
293 
294         // Also used by outside methods to add to other bundles
setBundle(Bundle extras)295         public void setBundle(Bundle extras) {
296             if (extras != null) {
297                 synchronized (this) {
298                     extras.putInt("satellites", mSvCount);
299                     extras.putInt("meanCn0", mMeanCn0);
300                     extras.putInt("maxCn0", mMaxCn0);
301                 }
302             }
303         }
304 
getBundle()305         public Bundle getBundle() {
306             synchronized (this) {
307                 return new Bundle(mBundle);
308             }
309         }
310     }
311 
312     private final Object mLock = new Object();
313 
314     // current status
315     private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
316 
317     // time for last status update
318     private long mStatusUpdateTime = SystemClock.elapsedRealtime();
319 
320     // turn off GPS fix icon if we haven't received a fix in 10 seconds
321     private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
322 
323     // stop trying if we do not receive a fix within 60 seconds
324     private static final int NO_FIX_TIMEOUT = 60 * 1000;
325 
326     // if the fix interval is below this we leave GPS on,
327     // if above then we cycle the GPS driver.
328     // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
329     private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
330 
331     // how long to wait if we have a network error in NTP or XTRA downloading
332     // the initial value of the exponential backoff
333     // current setting - 5 minutes
334     private static final long RETRY_INTERVAL = 5 * 60 * 1000;
335     // how long to wait if we have a network error in NTP or XTRA downloading
336     // the max value of the exponential backoff
337     // current setting - 4 hours
338     private static final long MAX_RETRY_INTERVAL = 4 * 60 * 60 * 1000;
339 
340     // Timeout when holding wakelocks for downloading XTRA data.
341     private static final long DOWNLOAD_XTRA_DATA_TIMEOUT_MS = 60 * 1000;
342 
343     private final ExponentialBackOff mXtraBackOff = new ExponentialBackOff(RETRY_INTERVAL,
344             MAX_RETRY_INTERVAL);
345 
346     // true if we are enabled, protected by this
347     private boolean mEnabled;
348 
349     // states for injecting ntp and downloading xtra data
350     private static final int STATE_PENDING_NETWORK = 0;
351     private static final int STATE_DOWNLOADING = 1;
352     private static final int STATE_IDLE = 2;
353 
354     // flags to trigger NTP or XTRA data download when network becomes available
355     // initialized to true so we do NTP and XTRA when the network comes up after booting
356     private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
357 
358     // true if GPS is navigating
359     private boolean mNavigating;
360 
361     // true if GPS engine is on
362     private boolean mEngineOn;
363 
364     // requested frequency of fixes, in milliseconds
365     private int mFixInterval = 1000;
366 
367     // true if low power mode for the GNSS chipset is part of the latest request.
368     private boolean mLowPowerMode = false;
369 
370     // true if we started navigation
371     private boolean mStarted;
372 
373     // true if single shot request is in progress
374     private boolean mSingleShot;
375 
376     // capabilities of the GPS engine
377     private int mEngineCapabilities;
378 
379     // true if XTRA is supported
380     private boolean mSupportsXtra;
381 
382     // for calculating time to first fix
383     private long mFixRequestTime = 0;
384     // time to first fix for most recent session
385     private int mTimeToFirstFix = 0;
386     // time we received our last fix
387     private long mLastFixTime;
388 
389     private int mPositionMode;
390 
391     // Current request from underlying location clients.
392     private ProviderRequest mProviderRequest = null;
393     // The WorkSource associated with the most recent client request (i.e, most recent call to
394     // setRequest).
395     private WorkSource mWorkSource = null;
396     // True if gps should be disabled (used to support battery saver mode in settings).
397     private boolean mDisableGps = false;
398 
399     /**
400      * Properties loaded from PROPERTIES_FILE.
401      * It must be accessed only inside {@link #mHandler}.
402      */
403     private Properties mProperties;
404 
405     private String mSuplServerHost;
406     private int mSuplServerPort = TCP_MIN_PORT;
407     private String mC2KServerHost;
408     private int mC2KServerPort;
409     private boolean mSuplEsEnabled = false;
410 
411     private final Context mContext;
412     private final ILocationManager mILocationManager;
413     private final LocationExtras mLocationExtras = new LocationExtras();
414     private final GnssStatusListenerHelper mListenerHelper;
415     private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
416     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
417     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
418     private final LocationChangeListener mNetworkLocationListener = new NetworkLocationListener();
419     private final LocationChangeListener mFusedLocationListener = new FusedLocationListener();
420     private final NtpTimeHelper mNtpTimeHelper;
421     private final GnssBatchingProvider mGnssBatchingProvider;
422     private final GnssGeofenceProvider mGnssGeofenceProvider;
423 
424     // Handler for processing events
425     private Handler mHandler;
426 
427     /** It must be accessed only inside {@link #mHandler}. */
428     private int mAGpsDataConnectionState;
429     /** It must be accessed only inside {@link #mHandler}. */
430     private InetAddress mAGpsDataConnectionIpAddr;
431 
432     private final ConnectivityManager mConnMgr;
433     private final GpsNetInitiatedHandler mNIHandler;
434 
435     // Wakelocks
436     private final static String WAKELOCK_KEY = "GnssLocationProvider";
437     private final PowerManager.WakeLock mWakeLock;
438     private static final String DOWNLOAD_EXTRA_WAKELOCK_KEY = "GnssLocationProviderXtraDownload";
439     private final PowerManager.WakeLock mDownloadXtraWakeLock;
440 
441     // Alarms
442     private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
443     private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
444 
445     // SIM/Carrier info.
446     private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
447 
448     // Persist property for LPP_PROFILE
449     private final static String LPP_PROFILE = "persist.sys.gps.lpp";
450 
451 
452     private final PowerManager mPowerManager;
453     private final AlarmManager mAlarmManager;
454     private final PendingIntent mWakeupIntent;
455     private final PendingIntent mTimeoutIntent;
456 
457     private final AppOpsManager mAppOps;
458     private final IBatteryStats mBatteryStats;
459 
460     // Current list of underlying location clients.
461     // only modified on handler thread
462     private WorkSource mClientSource = new WorkSource();
463 
464     private GeofenceHardwareImpl mGeofenceHardwareImpl;
465 
466     // Volatile for simple inter-thread sync on these values.
467     private volatile int mHardwareYear = 0;
468     private volatile String mHardwareModelName;
469 
470     // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
471     // stops output right at 600m/s, depriving this of the information of a device that reaches
472     // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
473     private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
474 
475     private volatile boolean mItarSpeedLimitExceeded = false;
476 
477     // GNSS Metrics
478     private GnssMetrics mGnssMetrics;
479 
480     private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
481         @Override
482         public void registerGnssStatusCallback(IGnssStatusListener callback) {
483             mListenerHelper.addListener(callback);
484         }
485 
486         @Override
487         public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
488             mListenerHelper.removeListener(callback);
489         }
490     };
491 
getGnssStatusProvider()492     public IGnssStatusProvider getGnssStatusProvider() {
493         return mGnssStatusProvider;
494     }
495 
getGpsGeofenceProxy()496     public IGpsGeofenceHardware getGpsGeofenceProxy() {
497         return mGnssGeofenceProvider;
498     }
499 
getGnssMeasurementsProvider()500     public GnssMeasurementsProvider getGnssMeasurementsProvider() {
501         return mGnssMeasurementsProvider;
502     }
503 
getGnssNavigationMessageProvider()504     public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
505         return mGnssNavigationMessageProvider;
506     }
507 
508     /**
509      * Callback used to listen for data connectivity changes.
510      */
511     private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
512             new ConnectivityManager.NetworkCallback() {
513                 @Override
514                 public void onAvailable(Network network) {
515                     mNtpTimeHelper.onNetworkAvailable();
516                     if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
517                         if (mSupportsXtra) {
518                             // Download only if supported, (prevents an unneccesary on-boot
519                             // download)
520                             xtraDownloadRequest();
521                         }
522                     }
523                     // Always on, notify HAL so it can get data it needs
524                     sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
525                 }
526 
527                 @Override
528                 public void onLost(Network network) {
529                     sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
530                 }
531             };
532 
533     /**
534      * Callback used to listen for availability of a requested SUPL connection.
535      * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
536      * manage the registration/un-registration lifetimes separate.
537      */
538     private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
539             new ConnectivityManager.NetworkCallback() {
540                 @Override
541                 public void onAvailable(Network network) {
542                     // Specific to a change to a SUPL enabled network becoming ready
543                     sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
544                 }
545 
546                 @Override
547                 public void onLost(Network network) {
548                     releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
549                 }
550             };
551 
552     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
553         @Override
554         public void onReceive(Context context, Intent intent) {
555             String action = intent.getAction();
556             if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
557             if (action == null) {
558                 return;
559             }
560 
561             if (action.equals(ALARM_WAKEUP)) {
562                 startNavigating(false);
563             } else if (action.equals(ALARM_TIMEOUT)) {
564                 hibernate();
565             } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
566                     || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
567                     || Intent.ACTION_SCREEN_OFF.equals(action)
568                     || Intent.ACTION_SCREEN_ON.equals(action)) {
569                 updateLowPowerMode();
570             } else if (action.equals(SIM_STATE_CHANGED)) {
571                 subscriptionOrSimChanged(context);
572             }
573         }
574     };
575 
576     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
577             new OnSubscriptionsChangedListener() {
578                 @Override
579                 public void onSubscriptionsChanged() {
580                     sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
581                 }
582             };
583 
584     /**
585      * Implements {@link GnssSatelliteBlacklistCallback#onUpdateSatelliteBlacklist}.
586      */
587     @Override
onUpdateSatelliteBlacklist(int[] constellations, int[] svids)588     public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
589         mHandler.post(()->{
590             native_set_satellite_blacklist(constellations, svids);
591         });
592     }
593 
subscriptionOrSimChanged(Context context)594     private void subscriptionOrSimChanged(Context context) {
595         if (DEBUG) Log.d(TAG, "received SIM related action: ");
596         TelephonyManager phone = (TelephonyManager)
597                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
598         CarrierConfigManager configManager = (CarrierConfigManager)
599                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
600         String mccMnc = phone.getSimOperator();
601         boolean isKeepLppProfile = false;
602         if (!TextUtils.isEmpty(mccMnc)) {
603             if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
604             synchronized (mLock) {
605                 if (configManager != null) {
606                     PersistableBundle b = configManager.getConfig();
607                     if (b != null) {
608                         isKeepLppProfile =
609                                 b.getBoolean(CarrierConfigManager.KEY_PERSIST_LPP_MODE_BOOL);
610                     }
611                 }
612                 if (isKeepLppProfile) {
613                     // load current properties for the carrier
614                     loadPropertiesFromResource(context, mProperties);
615                     String lpp_profile = mProperties.getProperty("LPP_PROFILE");
616                     // set the persist property LPP_PROFILE for the value
617                     if (lpp_profile != null) {
618                         SystemProperties.set(LPP_PROFILE, lpp_profile);
619                     }
620                 } else {
621                     // reset the persist property
622                     SystemProperties.set(LPP_PROFILE, "");
623                 }
624                 reloadGpsProperties(context, mProperties);
625                 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
626             }
627         } else {
628             if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
629         }
630     }
631 
updateLowPowerMode()632     private void updateLowPowerMode() {
633         // Disable GPS if we are in device idle mode.
634         boolean disableGps = mPowerManager.isDeviceIdleMode();
635         final PowerSaveState result =
636                 mPowerManager.getPowerSaveState(ServiceType.GPS);
637         switch (result.gpsMode) {
638             case PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
639                 // If we are in battery saver mode and the screen is off, disable GPS.
640                 disableGps |= result.batterySaverEnabled && !mPowerManager.isInteractive();
641                 break;
642         }
643         if (disableGps != mDisableGps) {
644             mDisableGps = disableGps;
645             updateRequirements();
646         }
647     }
648 
isSupported()649     public static boolean isSupported() {
650         return native_is_supported();
651     }
652 
653     interface SetCarrierProperty {
set(int value)654         public boolean set(int value);
655     }
656 
reloadGpsProperties(Context context, Properties properties)657     private void reloadGpsProperties(Context context, Properties properties) {
658         if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
659         loadPropertiesFromResource(context, properties);
660 
661         String lpp_prof = SystemProperties.get(LPP_PROFILE);
662         if (!TextUtils.isEmpty(lpp_prof)) {
663             // override default value of this if lpp_prof is not empty
664             properties.setProperty("LPP_PROFILE", lpp_prof);
665         }
666         /*
667          * Overlay carrier properties from a debug configuration file.
668          */
669         loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
670         // TODO: we should get rid of C2K specific setting.
671         setSuplHostPort(properties.getProperty("SUPL_HOST"),
672                 properties.getProperty("SUPL_PORT"));
673         mC2KServerHost = properties.getProperty("C2K_HOST");
674         String portString = properties.getProperty("C2K_PORT");
675         if (mC2KServerHost != null && portString != null) {
676             try {
677                 mC2KServerPort = Integer.parseInt(portString);
678             } catch (NumberFormatException e) {
679                 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
680             }
681         }
682         if (native_is_gnss_configuration_supported()) {
683             Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
684                 {
685                     put("SUPL_VER", (val) -> native_set_supl_version(val));
686                     put("SUPL_MODE", (val) -> native_set_supl_mode(val));
687                     put("SUPL_ES", (val) -> native_set_supl_es(val));
688                     put("LPP_PROFILE", (val) -> native_set_lpp_profile(val));
689                     put("A_GLONASS_POS_PROTOCOL_SELECT",
690                             (val) -> native_set_gnss_pos_protocol_select(val));
691                     put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL",
692                             (val) -> native_set_emergency_supl_pdn(val));
693                     put("GPS_LOCK", (val) -> native_set_gps_lock(val));
694                 }
695             };
696 
697             for (Entry<String, SetCarrierProperty> entry : map.entrySet()) {
698                 String propertyName = entry.getKey();
699                 String propertyValueString = properties.getProperty(propertyName);
700                 if (propertyValueString != null) {
701                     try {
702                         int propertyValueInt = Integer.decode(propertyValueString);
703                         boolean result = entry.getValue().set(propertyValueInt);
704                         if (result == false) {
705                             Log.e(TAG, "Unable to set " + propertyName);
706                         }
707                     } catch (NumberFormatException e) {
708                         Log.e(TAG, "unable to parse propertyName: " + propertyValueString);
709                     }
710                 }
711             }
712         } else if (DEBUG) {
713             Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
714                     + " supported");
715         }
716 
717         // SUPL_ES configuration.
718         String suplESProperty = mProperties.getProperty("SUPL_ES");
719         if (suplESProperty != null) {
720             try {
721                 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
722             } catch (NumberFormatException e) {
723                 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
724             }
725         }
726 
727         String emergencyExtensionSecondsString
728                 = properties.getProperty("ES_EXTENSION_SEC", "0");
729         try {
730             int emergencyExtensionSeconds =
731                     Integer.parseInt(emergencyExtensionSecondsString);
732             mNIHandler.setEmergencyExtensionSeconds(emergencyExtensionSeconds);
733         } catch (NumberFormatException e) {
734             Log.e(TAG, "unable to parse ES_EXTENSION_SEC: "
735                     + emergencyExtensionSecondsString);
736         }
737     }
738 
loadPropertiesFromResource(Context context, Properties properties)739     private void loadPropertiesFromResource(Context context,
740             Properties properties) {
741         String[] configValues = context.getResources().getStringArray(
742                 com.android.internal.R.array.config_gpsParameters);
743         for (String item : configValues) {
744             if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
745             // We need to support "KEY =", but not "=VALUE".
746             int index = item.indexOf("=");
747             if (index > 0 && index + 1 < item.length()) {
748                 String key = item.substring(0, index);
749                 String value = item.substring(index + 1);
750                 properties.setProperty(key.trim().toUpperCase(), value);
751             } else {
752                 Log.w(TAG, "malformed contents: " + item);
753             }
754         }
755     }
756 
loadPropertiesFromFile(String filename, Properties properties)757     private boolean loadPropertiesFromFile(String filename,
758             Properties properties) {
759         try {
760             File file = new File(filename);
761             FileInputStream stream = null;
762             try {
763                 stream = new FileInputStream(file);
764                 properties.load(stream);
765             } finally {
766                 IoUtils.closeQuietly(stream);
767             }
768 
769         } catch (IOException e) {
770             if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename);
771             return false;
772         }
773         return true;
774     }
775 
GnssLocationProvider(Context context, ILocationManager ilocationManager, Looper looper)776     public GnssLocationProvider(Context context, ILocationManager ilocationManager,
777             Looper looper) {
778         mContext = context;
779         mILocationManager = ilocationManager;
780 
781         // Create a wake lock
782         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
783         mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
784         mWakeLock.setReferenceCounted(true);
785 
786         // Create a separate wake lock for xtra downloader as it may be released due to timeout.
787         mDownloadXtraWakeLock = mPowerManager.newWakeLock(
788                 PowerManager.PARTIAL_WAKE_LOCK, DOWNLOAD_EXTRA_WAKELOCK_KEY);
789         mDownloadXtraWakeLock.setReferenceCounted(true);
790 
791         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
792         mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
793         mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
794 
795         mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
796 
797         // App ops service to keep track of who is accessing the GPS
798         mAppOps = mContext.getSystemService(AppOpsManager.class);
799 
800         // Battery statistics service to be notified when GPS turns on or off
801         mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
802                 BatteryStats.SERVICE_NAME));
803 
804         // Construct internal handler
805         mHandler = new ProviderHandler(looper);
806 
807         // Load GPS configuration and register listeners in the background:
808         // some operations, such as opening files and registering broadcast receivers, can take a
809         // relative long time, so the ctor() is kept to create objects needed by this instance,
810         // while IO initialization and registration is delegated to our internal handler
811         // this approach is just fine because events are posted to our handler anyway
812         mProperties = new Properties();
813         // Create a GPS net-initiated handler (also needed by handleInitialize)
814         mNIHandler = new GpsNetInitiatedHandler(context,
815                 mNetInitiatedListener,
816                 mSuplEsEnabled);
817         sendMessage(INITIALIZE_HANDLER, 0, null);
818 
819         mListenerHelper = new GnssStatusListenerHelper(mHandler) {
820             @Override
821             protected boolean isAvailableInPlatform() {
822                 return isSupported();
823             }
824 
825             @Override
826             protected boolean isGpsEnabled() {
827                 return isEnabled();
828             }
829         };
830 
831         mGnssMeasurementsProvider = new GnssMeasurementsProvider(mContext, mHandler) {
832             @Override
833             protected boolean isGpsEnabled() {
834                 return isEnabled();
835             }
836         };
837 
838         mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
839             @Override
840             protected boolean isGpsEnabled() {
841                 return isEnabled();
842             }
843         };
844         mGnssMetrics = new GnssMetrics(mBatteryStats);
845 
846         mNtpTimeHelper = new NtpTimeHelper(mContext, looper, this);
847         mGnssSatelliteBlacklistHelper = new GnssSatelliteBlacklistHelper(mContext,
848                 looper, this);
849         mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
850         mGnssBatchingProvider = new GnssBatchingProvider();
851         mGnssGeofenceProvider = new GnssGeofenceProvider(looper);
852     }
853 
854     /**
855      * Returns the name of this provider.
856      */
857     @Override
getName()858     public String getName() {
859         return LocationManager.GPS_PROVIDER;
860     }
861 
862     @Override
getProperties()863     public ProviderProperties getProperties() {
864         return PROPERTIES;
865     }
866 
867 
868     /**
869      * Implements {@link InjectNtpTimeCallback#injectTime}
870      */
871     @Override
injectTime(long time, long timeReference, int uncertainty)872     public void injectTime(long time, long timeReference, int uncertainty) {
873         native_inject_time(time, timeReference, uncertainty);
874     }
875 
handleUpdateNetworkState(Network network)876     private void handleUpdateNetworkState(Network network) {
877         // retrieve NetworkInfo for this UID
878         NetworkInfo info = mConnMgr.getNetworkInfo(network);
879 
880         boolean networkAvailable = false;
881         boolean isConnected = false;
882         int type = ConnectivityManager.TYPE_NONE;
883         boolean isRoaming = false;
884         String apnName = null;
885 
886         if (info != null) {
887             networkAvailable = info.isAvailable() && TelephonyManager.getDefault().getDataEnabled();
888             isConnected = info.isConnected();
889             type = info.getType();
890             isRoaming = info.isRoaming();
891             apnName = info.getExtraInfo();
892         }
893 
894         if (DEBUG) {
895             String message = String.format(
896                     "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
897                     agpsDataConnStateAsString(),
898                     isConnected,
899                     info,
900                     mConnMgr.getNetworkCapabilities(network));
901             Log.d(TAG, message);
902         }
903 
904         if (native_is_agps_ril_supported()) {
905             String defaultApn = getSelectedApn();
906             if (defaultApn == null) {
907                 defaultApn = "dummy-apn";
908             }
909 
910             native_update_network_state(
911                     isConnected,
912                     type,
913                     isRoaming,
914                     networkAvailable,
915                     apnName,
916                     defaultApn);
917         } else if (DEBUG) {
918             Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not  supported");
919         }
920 
921         if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
922             if (isConnected) {
923                 if (apnName == null) {
924                     // assign a dummy value in the case of C2K as otherwise we will have a runtime
925                     // exception in the following call to native_agps_data_conn_open
926                     apnName = "dummy-apn";
927                 }
928                 int apnIpType = getApnIpType(apnName);
929                 setRouting();
930                 if (DEBUG) {
931                     String message = String.format(
932                             "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
933                             apnName,
934                             apnIpType);
935                     Log.d(TAG, message);
936                 }
937                 native_agps_data_conn_open(apnName, apnIpType);
938                 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
939             } else {
940                 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
941             }
942         }
943     }
944 
handleRequestSuplConnection(InetAddress address)945     private void handleRequestSuplConnection(InetAddress address) {
946         if (DEBUG) {
947             String message = String.format(
948                     "requestSuplConnection, state=%s, address=%s",
949                     agpsDataConnStateAsString(),
950                     address);
951             Log.d(TAG, message);
952         }
953 
954         if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
955             return;
956         }
957         mAGpsDataConnectionIpAddr = address;
958         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
959 
960         NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
961         requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
962         requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
963         NetworkRequest request = requestBuilder.build();
964         mConnMgr.requestNetwork(
965                 request,
966                 mSuplConnectivityCallback);
967     }
968 
handleReleaseSuplConnection(int agpsDataConnStatus)969     private void handleReleaseSuplConnection(int agpsDataConnStatus) {
970         if (DEBUG) {
971             String message = String.format(
972                     "releaseSuplConnection, state=%s, status=%s",
973                     agpsDataConnStateAsString(),
974                     agpsDataConnStatusAsString(agpsDataConnStatus));
975             Log.d(TAG, message);
976         }
977 
978         if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
979             return;
980         }
981         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
982 
983         mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
984         switch (agpsDataConnStatus) {
985             case GPS_AGPS_DATA_CONN_FAILED:
986                 native_agps_data_conn_failed();
987                 break;
988             case GPS_RELEASE_AGPS_DATA_CONN:
989                 native_agps_data_conn_closed();
990                 break;
991             default:
992                 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
993         }
994     }
995 
handleRequestLocation(boolean independentFromGnss)996     private void handleRequestLocation(boolean independentFromGnss) {
997         if (isRequestLocationRateLimited()) {
998             if (DEBUG) {
999                 Log.d(TAG, "RequestLocation is denied due to too frequent requests.");
1000             }
1001             return;
1002         }
1003         ContentResolver resolver = mContext.getContentResolver();
1004         long durationMillis = Settings.Global.getLong(
1005                 resolver,
1006                 Settings.Global.GNSS_HAL_LOCATION_REQUEST_DURATION_MILLIS,
1007                 LOCATION_UPDATE_DURATION_MILLIS);
1008         if (durationMillis == 0) {
1009             Log.i(TAG, "GNSS HAL location request is disabled by Settings.");
1010             return;
1011         }
1012 
1013         LocationManager locationManager = (LocationManager) mContext.getSystemService(
1014                 Context.LOCATION_SERVICE);
1015         String provider;
1016         LocationChangeListener locationListener;
1017 
1018         if (independentFromGnss) {
1019             // For fast GNSS TTFF
1020             provider = LocationManager.NETWORK_PROVIDER;
1021             locationListener = mNetworkLocationListener;
1022         } else {
1023             // For Device-Based Hybrid (E911)
1024             provider = LocationManager.FUSED_PROVIDER;
1025             locationListener = mFusedLocationListener;
1026         }
1027 
1028         Log.i(TAG,
1029                 String.format(
1030                         "GNSS HAL Requesting location updates from %s provider for %d millis.",
1031                         provider, durationMillis));
1032         try {
1033             locationManager.requestLocationUpdates(provider,
1034                     LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
1035                     locationListener, mHandler.getLooper());
1036             locationListener.numLocationUpdateRequest++;
1037             mHandler.postDelayed(() -> {
1038                 if (--locationListener.numLocationUpdateRequest == 0) {
1039                     Log.i(TAG,
1040                             String.format("Removing location updates from %s provider.", provider));
1041                     locationManager.removeUpdates(locationListener);
1042                 }
1043             }, durationMillis);
1044         } catch (IllegalArgumentException e) {
1045             Log.w(TAG, "Unable to request location.", e);
1046         }
1047     }
1048 
injectBestLocation(Location location)1049     private void injectBestLocation(Location location) {
1050         int gnssLocationFlags = LOCATION_HAS_LAT_LONG |
1051                 (location.hasAltitude() ? LOCATION_HAS_ALTITUDE : 0) |
1052                 (location.hasSpeed() ? LOCATION_HAS_SPEED : 0) |
1053                 (location.hasBearing() ? LOCATION_HAS_BEARING : 0) |
1054                 (location.hasAccuracy() ? LOCATION_HAS_HORIZONTAL_ACCURACY : 0) |
1055                 (location.hasVerticalAccuracy() ? LOCATION_HAS_VERTICAL_ACCURACY : 0) |
1056                 (location.hasSpeedAccuracy() ? LOCATION_HAS_SPEED_ACCURACY : 0) |
1057                 (location.hasBearingAccuracy() ? LOCATION_HAS_BEARING_ACCURACY : 0);
1058 
1059         double latitudeDegrees = location.getLatitude();
1060         double longitudeDegrees = location.getLongitude();
1061         double altitudeMeters = location.getAltitude();
1062         float speedMetersPerSec = location.getSpeed();
1063         float bearingDegrees = location.getBearing();
1064         float horizontalAccuracyMeters = location.getAccuracy();
1065         float verticalAccuracyMeters = location.getVerticalAccuracyMeters();
1066         float speedAccuracyMetersPerSecond = location.getSpeedAccuracyMetersPerSecond();
1067         float bearingAccuracyDegrees = location.getBearingAccuracyDegrees();
1068         long timestamp = location.getTime();
1069         native_inject_best_location(gnssLocationFlags, latitudeDegrees, longitudeDegrees,
1070                 altitudeMeters, speedMetersPerSec, bearingDegrees, horizontalAccuracyMeters,
1071                 verticalAccuracyMeters, speedAccuracyMetersPerSecond, bearingAccuracyDegrees,
1072                 timestamp);
1073     }
1074 
1075     /** Returns true if the location request is too frequent. */
isRequestLocationRateLimited()1076     private boolean isRequestLocationRateLimited() {
1077         // TODO(b/73198123): implement exponential backoff.
1078         return false;
1079     }
1080 
handleDownloadXtraData()1081     private void handleDownloadXtraData() {
1082         if (!mSupportsXtra) {
1083             // native code reports xtra not supported, don't try
1084             Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
1085             return;
1086         }
1087         if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
1088             // already downloading data
1089             return;
1090         }
1091         if (!isDataNetworkConnected()) {
1092             // try again when network is up
1093             mDownloadXtraDataPending = STATE_PENDING_NETWORK;
1094             return;
1095         }
1096         mDownloadXtraDataPending = STATE_DOWNLOADING;
1097 
1098         // hold wake lock while task runs
1099         mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
1100         Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
1101         AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1102             @Override
1103             public void run() {
1104                 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
1105                 byte[] data = xtraDownloader.downloadXtraData();
1106                 if (data != null) {
1107                     if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
1108                     native_inject_xtra_data(data, data.length);
1109                     mXtraBackOff.reset();
1110                 }
1111 
1112                 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
1113 
1114                 if (data == null) {
1115                     // try again later
1116                     // since this is delayed and not urgent we do not hold a wake lock here
1117                     mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
1118                             mXtraBackOff.nextBackoffMillis());
1119                 }
1120 
1121                 // Release wake lock held by task, synchronize on mLock in case multiple
1122                 // download tasks overrun.
1123                 synchronized (mLock) {
1124                     if (mDownloadXtraWakeLock.isHeld()) {
1125                         // This wakelock may have time-out, if a timeout was specified.
1126                         // Catch (and ignore) any timeout exceptions.
1127                         try {
1128                             mDownloadXtraWakeLock.release();
1129                             if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
1130                         } catch (Exception e) {
1131                             Log.i(TAG, "Wakelock timeout & release race exception in "
1132                                     + "handleDownloadXtraData()", e);
1133                         }
1134                     } else {
1135                         Log.e(TAG, "WakeLock expired before release in "
1136                                 + "handleDownloadXtraData()");
1137                     }
1138                 }
1139             }
1140         });
1141     }
1142 
handleUpdateLocation(Location location)1143     private void handleUpdateLocation(Location location) {
1144         if (location.hasAccuracy()) {
1145             native_inject_location(location.getLatitude(), location.getLongitude(),
1146                     location.getAccuracy());
1147         }
1148     }
1149 
1150     /**
1151      * Enables this provider.  When enabled, calls to getStatus()
1152      * must be handled.  Hardware may be started up
1153      * when the provider is enabled.
1154      */
1155     @Override
enable()1156     public void enable() {
1157         synchronized (mLock) {
1158             if (mEnabled) return;
1159             mEnabled = true;
1160         }
1161 
1162         sendMessage(ENABLE, 1, null);
1163     }
1164 
setSuplHostPort(String hostString, String portString)1165     private void setSuplHostPort(String hostString, String portString) {
1166         if (hostString != null) {
1167             mSuplServerHost = hostString;
1168         }
1169         if (portString != null) {
1170             try {
1171                 mSuplServerPort = Integer.parseInt(portString);
1172             } catch (NumberFormatException e) {
1173                 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1174             }
1175         }
1176         if (mSuplServerHost != null
1177                 && mSuplServerPort > TCP_MIN_PORT
1178                 && mSuplServerPort <= TCP_MAX_PORT) {
1179             native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1180         }
1181     }
1182 
1183     /**
1184      * Checks what SUPL mode to use, according to the AGPS mode as well as the
1185      * allowed mode from properties.
1186      *
1187      * @param properties  GPS properties
1188      * @param agpsEnabled whether AGPS is enabled by settings value
1189      * @param singleShot  whether "singleshot" is needed
1190      * @return SUPL mode (MSA vs MSB vs STANDALONE)
1191      */
getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot)1192     private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1193         if (agpsEnabled) {
1194             String modeString = properties.getProperty("SUPL_MODE");
1195             int suplMode = 0;
1196             if (!TextUtils.isEmpty(modeString)) {
1197                 try {
1198                     suplMode = Integer.parseInt(modeString);
1199                 } catch (NumberFormatException e) {
1200                     Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1201                     return GPS_POSITION_MODE_STANDALONE;
1202                 }
1203             }
1204             // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1205             // such mode when it is available
1206             if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1207                 return GPS_POSITION_MODE_MS_BASED;
1208             }
1209             // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1210             // do fallback only for single-shot requests, because it is too expensive to do for
1211             // periodic requests as well
1212             if (singleShot
1213                     && hasCapability(GPS_CAPABILITY_MSA)
1214                     && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1215                 return GPS_POSITION_MODE_MS_ASSISTED;
1216             }
1217         }
1218         return GPS_POSITION_MODE_STANDALONE;
1219     }
1220 
handleEnable()1221     private void handleEnable() {
1222         if (DEBUG) Log.d(TAG, "handleEnable");
1223 
1224         boolean enabled = native_init();
1225 
1226         if (enabled) {
1227             mSupportsXtra = native_supports_xtra();
1228 
1229             // TODO: remove the following native calls if we can make sure they are redundant.
1230             if (mSuplServerHost != null) {
1231                 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1232             }
1233             if (mC2KServerHost != null) {
1234                 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1235             }
1236 
1237             mGnssMeasurementsProvider.onGpsEnabledChanged();
1238             mGnssNavigationMessageProvider.onGpsEnabledChanged();
1239             mGnssBatchingProvider.enable();
1240         } else {
1241             synchronized (mLock) {
1242                 mEnabled = false;
1243             }
1244             Log.w(TAG, "Failed to enable location provider");
1245         }
1246     }
1247 
1248     /**
1249      * Disables this provider.  When disabled, calls to getStatus()
1250      * need not be handled.  Hardware may be shut
1251      * down while the provider is disabled.
1252      */
1253     @Override
disable()1254     public void disable() {
1255         synchronized (mLock) {
1256             if (!mEnabled) return;
1257             mEnabled = false;
1258         }
1259 
1260         sendMessage(ENABLE, 0, null);
1261     }
1262 
handleDisable()1263     private void handleDisable() {
1264         if (DEBUG) Log.d(TAG, "handleDisable");
1265 
1266         updateClientUids(new WorkSource());
1267         stopNavigating();
1268         mAlarmManager.cancel(mWakeupIntent);
1269         mAlarmManager.cancel(mTimeoutIntent);
1270 
1271         mGnssBatchingProvider.disable();
1272         // do this before releasing wakelock
1273         native_cleanup();
1274 
1275         mGnssMeasurementsProvider.onGpsEnabledChanged();
1276         mGnssNavigationMessageProvider.onGpsEnabledChanged();
1277     }
1278 
1279     @Override
isEnabled()1280     public boolean isEnabled() {
1281         synchronized (mLock) {
1282             return mEnabled;
1283         }
1284     }
1285 
1286     @Override
getStatus(Bundle extras)1287     public int getStatus(Bundle extras) {
1288         mLocationExtras.setBundle(extras);
1289         return mStatus;
1290     }
1291 
updateStatus(int status)1292     private void updateStatus(int status) {
1293         if (status != mStatus) {
1294             mStatus = status;
1295             mStatusUpdateTime = SystemClock.elapsedRealtime();
1296         }
1297     }
1298 
1299     @Override
getStatusUpdateTime()1300     public long getStatusUpdateTime() {
1301         return mStatusUpdateTime;
1302     }
1303 
1304     @Override
setRequest(ProviderRequest request, WorkSource source)1305     public void setRequest(ProviderRequest request, WorkSource source) {
1306         sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1307     }
1308 
handleSetRequest(ProviderRequest request, WorkSource source)1309     private void handleSetRequest(ProviderRequest request, WorkSource source) {
1310         mProviderRequest = request;
1311         mWorkSource = source;
1312         updateRequirements();
1313     }
1314 
1315     // Called when the requirements for GPS may have changed
updateRequirements()1316     private void updateRequirements() {
1317         if (mProviderRequest == null || mWorkSource == null) {
1318             return;
1319         }
1320 
1321         boolean singleShot = false;
1322 
1323         // see if the request is for a single update
1324         if (mProviderRequest.locationRequests != null
1325                 && mProviderRequest.locationRequests.size() > 0) {
1326             // if any request has zero or more than one updates
1327             // requested, then this is not single-shot mode
1328             singleShot = true;
1329 
1330             for (LocationRequest lr : mProviderRequest.locationRequests) {
1331                 if (lr.getNumUpdates() != 1) {
1332                     singleShot = false;
1333                 }
1334             }
1335         }
1336 
1337         if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1338         if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1339             // update client uids
1340             updateClientUids(mWorkSource);
1341 
1342             mFixInterval = (int) mProviderRequest.interval;
1343             mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
1344             // check for overflow
1345             if (mFixInterval != mProviderRequest.interval) {
1346                 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1347                 mFixInterval = Integer.MAX_VALUE;
1348             }
1349 
1350             // apply request to GPS engine
1351             if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1352                 // change period and/or lowPowerMode
1353                 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1354                         mFixInterval, 0, 0, mLowPowerMode)) {
1355                     Log.e(TAG, "set_position_mode failed in updateRequirements");
1356                 }
1357             } else if (!mStarted) {
1358                 // start GPS
1359                 startNavigating(singleShot);
1360             } else {
1361                 // GNSS Engine is already ON, but no GPS_CAPABILITY_SCHEDULING
1362                 mAlarmManager.cancel(mTimeoutIntent);
1363                 if (mFixInterval >= NO_FIX_TIMEOUT) {
1364                     // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1365                     // and our fix interval is not short
1366                     mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1367                             SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);                }
1368             }
1369         } else {
1370             updateClientUids(new WorkSource());
1371 
1372             stopNavigating();
1373             mAlarmManager.cancel(mWakeupIntent);
1374             mAlarmManager.cancel(mTimeoutIntent);
1375         }
1376     }
1377 
updateClientUids(WorkSource source)1378     private void updateClientUids(WorkSource source) {
1379         if (source.equals(mClientSource)) {
1380             return;
1381         }
1382 
1383         // (1) Inform BatteryStats that the list of IDs we're tracking changed.
1384         try {
1385             mBatteryStats.noteGpsChanged(mClientSource, source);
1386         } catch (RemoteException e) {
1387             Log.w(TAG, "RemoteException", e);
1388         }
1389 
1390         // (2) Inform AppOps service about the list of changes to UIDs.
1391 
1392         List<WorkChain>[] diffs = WorkSource.diffChains(mClientSource, source);
1393         if (diffs != null) {
1394             List<WorkChain> newChains = diffs[0];
1395             List<WorkChain> goneChains = diffs[1];
1396 
1397             if (newChains != null) {
1398                 for (int i = 0; i < newChains.size(); ++i) {
1399                     final WorkChain newChain = newChains.get(i);
1400                     mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(),
1401                             newChain.getAttributionTag());
1402                 }
1403             }
1404 
1405             if (goneChains != null) {
1406                 for (int i = 0; i < goneChains.size(); i++) {
1407                     final WorkChain goneChain = goneChains.get(i);
1408                     mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(),
1409                             goneChain.getAttributionTag());
1410                 }
1411             }
1412 
1413             mClientSource.transferWorkChains(source);
1414         }
1415 
1416         // Update the flat UIDs and names list and inform app-ops of all changes.
1417         WorkSource[] changes = mClientSource.setReturningDiffs(source);
1418         if (changes != null) {
1419             WorkSource newWork = changes[0];
1420             WorkSource goneWork = changes[1];
1421 
1422             // Update sources that were not previously tracked.
1423             if (newWork != null) {
1424                 for (int i = 0; i < newWork.size(); i++) {
1425                     mAppOps.startOpNoThrow(AppOpsManager.OP_GPS,
1426                             newWork.get(i), newWork.getName(i));
1427                 }
1428             }
1429 
1430             // Update sources that are no longer tracked.
1431             if (goneWork != null) {
1432                 for (int i = 0; i < goneWork.size(); i++) {
1433                     mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i));
1434                 }
1435             }
1436         }
1437     }
1438 
1439     @Override
sendExtraCommand(String command, Bundle extras)1440     public boolean sendExtraCommand(String command, Bundle extras) {
1441 
1442         long identity = Binder.clearCallingIdentity();
1443         try {
1444             boolean result = false;
1445 
1446             if ("delete_aiding_data".equals(command)) {
1447                 result = deleteAidingData(extras);
1448             } else if ("force_time_injection".equals(command)) {
1449                 requestUtcTime();
1450                 result = true;
1451             } else if ("force_xtra_injection".equals(command)) {
1452                 if (mSupportsXtra) {
1453                     xtraDownloadRequest();
1454                     result = true;
1455                 }
1456             } else {
1457                 Log.w(TAG, "sendExtraCommand: unknown command " + command);
1458             }
1459             return result;
1460         } finally {
1461             Binder.restoreCallingIdentity(identity);
1462         }
1463     }
1464 
deleteAidingData(Bundle extras)1465     private boolean deleteAidingData(Bundle extras) {
1466         int flags;
1467 
1468         if (extras == null) {
1469             flags = GPS_DELETE_ALL;
1470         } else {
1471             flags = 0;
1472             if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1473             if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1474             if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1475             if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1476             if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1477             if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1478             if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1479             if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1480             if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1481             if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1482             if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1483             if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1484             if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1485         }
1486 
1487         if (flags != 0) {
1488             native_delete_aiding_data(flags);
1489             return true;
1490         }
1491 
1492         return false;
1493     }
1494 
startNavigating(boolean singleShot)1495     private void startNavigating(boolean singleShot) {
1496         if (!mStarted) {
1497             if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1498             mTimeToFirstFix = 0;
1499             mLastFixTime = 0;
1500             mStarted = true;
1501             mSingleShot = singleShot;
1502             mPositionMode = GPS_POSITION_MODE_STANDALONE;
1503             // Notify about suppressed output, if speed limit was previously exceeded.
1504             // Elsewhere, we check again with every speed output reported.
1505             if (mItarSpeedLimitExceeded) {
1506                 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited  " +
1507                         "until slow enough speed reported.");
1508             }
1509 
1510             boolean agpsEnabled =
1511                     (Settings.Global.getInt(mContext.getContentResolver(),
1512                             Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1513             mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1514 
1515             if (DEBUG) {
1516                 String mode;
1517 
1518                 switch (mPositionMode) {
1519                     case GPS_POSITION_MODE_STANDALONE:
1520                         mode = "standalone";
1521                         break;
1522                     case GPS_POSITION_MODE_MS_ASSISTED:
1523                         mode = "MS_ASSISTED";
1524                         break;
1525                     case GPS_POSITION_MODE_MS_BASED:
1526                         mode = "MS_BASED";
1527                         break;
1528                     default:
1529                         mode = "unknown";
1530                         break;
1531                 }
1532                 Log.d(TAG, "setting position_mode to " + mode);
1533             }
1534 
1535             int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1536             mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
1537             if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1538                     interval, 0, 0, mLowPowerMode)) {
1539                 mStarted = false;
1540                 Log.e(TAG, "set_position_mode failed in startNavigating()");
1541                 return;
1542             }
1543             if (!native_start()) {
1544                 mStarted = false;
1545                 Log.e(TAG, "native_start failed in startNavigating()");
1546                 return;
1547             }
1548 
1549             // reset SV count to zero
1550             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
1551             mLocationExtras.reset();
1552             mFixRequestTime = SystemClock.elapsedRealtime();
1553             if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1554                 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1555                 // and our fix interval is not short
1556                 if (mFixInterval >= NO_FIX_TIMEOUT) {
1557                     mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1558                             SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1559                 }
1560             }
1561         }
1562     }
1563 
stopNavigating()1564     private void stopNavigating() {
1565         if (DEBUG) Log.d(TAG, "stopNavigating");
1566         if (mStarted) {
1567             mStarted = false;
1568             mSingleShot = false;
1569             native_stop();
1570             mLastFixTime = 0;
1571 
1572             // reset SV count to zero
1573             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
1574             mLocationExtras.reset();
1575         }
1576     }
1577 
hibernate()1578     private void hibernate() {
1579         // stop GPS until our next fix interval arrives
1580         stopNavigating();
1581         mAlarmManager.cancel(mTimeoutIntent);
1582         mAlarmManager.cancel(mWakeupIntent);
1583         long now = SystemClock.elapsedRealtime();
1584         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1585     }
1586 
hasCapability(int capability)1587     private boolean hasCapability(int capability) {
1588         return ((mEngineCapabilities & capability) != 0);
1589     }
1590 
1591 
1592     /**
1593      * called from native code to update our position.
1594      */
reportLocation(boolean hasLatLong, Location location)1595     private void reportLocation(boolean hasLatLong, Location location) {
1596         sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location);
1597     }
1598 
handleReportLocation(boolean hasLatLong, Location location)1599     private void handleReportLocation(boolean hasLatLong, Location location) {
1600         if (location.hasSpeed()) {
1601             mItarSpeedLimitExceeded = location.getSpeed() > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
1602         }
1603 
1604         if (mItarSpeedLimitExceeded) {
1605             Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
1606                     "  GPS/GNSS Navigation output blocked.");
1607             if (mStarted) {
1608                 mGnssMetrics.logReceivedLocationStatus(false);
1609             }
1610             return;  // No output of location allowed
1611         }
1612 
1613         if (VERBOSE) Log.v(TAG, "reportLocation " + location.toString());
1614 
1615         // It would be nice to push the elapsed real-time timestamp
1616         // further down the stack, but this is still useful
1617         location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1618         location.setExtras(mLocationExtras.getBundle());
1619 
1620         try {
1621             mILocationManager.reportLocation(location, false);
1622         } catch (RemoteException e) {
1623             Log.e(TAG, "RemoteException calling reportLocation");
1624         }
1625 
1626         if (mStarted) {
1627             mGnssMetrics.logReceivedLocationStatus(hasLatLong);
1628             if (hasLatLong) {
1629                 if (location.hasAccuracy()) {
1630                     mGnssMetrics.logPositionAccuracyMeters(location.getAccuracy());
1631                 }
1632                 if (mTimeToFirstFix > 0) {
1633                     int timeBetweenFixes = (int) (SystemClock.elapsedRealtime() - mLastFixTime);
1634                     mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
1635                 }
1636             }
1637         }
1638 
1639         mLastFixTime = SystemClock.elapsedRealtime();
1640         // report time to first fix
1641         if (mTimeToFirstFix == 0 && hasLatLong) {
1642             mTimeToFirstFix = (int) (mLastFixTime - mFixRequestTime);
1643             if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1644             if (mStarted) {
1645                 mGnssMetrics.logTimeToFirstFixMilliSecs(mTimeToFirstFix);
1646             }
1647 
1648             // notify status listeners
1649             mListenerHelper.onFirstFix(mTimeToFirstFix);
1650         }
1651 
1652         if (mSingleShot) {
1653             stopNavigating();
1654         }
1655 
1656         if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1657             // For devices that use framework scheduling, a timer may be set to ensure we don't
1658             // spend too much power searching for a location, when the requested update rate is slow.
1659             // As we just recievied a location, we'll cancel that timer.
1660             if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1661                 mAlarmManager.cancel(mTimeoutIntent);
1662             }
1663 
1664             // send an intent to notify that the GPS is receiving fixes.
1665             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1666             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1667             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1668             updateStatus(LocationProvider.AVAILABLE);
1669         }
1670 
1671         if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1672                 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1673             if (DEBUG) Log.d(TAG, "got fix, hibernating");
1674             hibernate();
1675         }
1676     }
1677 
1678     /**
1679      * called from native code to update our status
1680      */
reportStatus(int status)1681     private void reportStatus(int status) {
1682         if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1683 
1684         boolean wasNavigating = mNavigating;
1685         switch (status) {
1686             case GPS_STATUS_SESSION_BEGIN:
1687                 mNavigating = true;
1688                 mEngineOn = true;
1689                 break;
1690             case GPS_STATUS_SESSION_END:
1691                 mNavigating = false;
1692                 break;
1693             case GPS_STATUS_ENGINE_ON:
1694                 mEngineOn = true;
1695                 break;
1696             case GPS_STATUS_ENGINE_OFF:
1697                 mEngineOn = false;
1698                 mNavigating = false;
1699                 break;
1700         }
1701 
1702         if (wasNavigating != mNavigating) {
1703             mListenerHelper.onStatusChanged(mNavigating);
1704 
1705             // send an intent to notify that the GPS has been enabled or disabled
1706             Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1707             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1708             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1709         }
1710     }
1711 
1712     // Helper class to carry data to handler for reportSvStatus
1713     private static class SvStatusInfo {
1714         public int mSvCount;
1715         public int[] mSvidWithFlags;
1716         public float[] mCn0s;
1717         public float[] mSvElevations;
1718         public float[] mSvAzimuths;
1719         public float[] mSvCarrierFreqs;
1720     }
1721 
1722     /**
1723      * called from native code to update SV info
1724      */
reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs)1725     private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s,
1726             float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) {
1727         SvStatusInfo svStatusInfo = new SvStatusInfo();
1728         svStatusInfo.mSvCount = svCount;
1729         svStatusInfo.mSvidWithFlags = svidWithFlags;
1730         svStatusInfo.mCn0s = cn0s;
1731         svStatusInfo.mSvElevations = svElevations;
1732         svStatusInfo.mSvAzimuths = svAzimuths;
1733         svStatusInfo.mSvCarrierFreqs = svCarrierFreqs;
1734 
1735         sendMessage(REPORT_SV_STATUS, 0, svStatusInfo);
1736     }
1737 
handleReportSvStatus(SvStatusInfo info)1738     private void handleReportSvStatus(SvStatusInfo info) {
1739         mListenerHelper.onSvStatusChanged(
1740                 info.mSvCount,
1741                 info.mSvidWithFlags,
1742                 info.mCn0s,
1743                 info.mSvElevations,
1744                 info.mSvAzimuths,
1745                 info.mSvCarrierFreqs);
1746 
1747         // Log CN0 as part of GNSS metrics
1748         mGnssMetrics.logCn0(info.mCn0s, info.mSvCount);
1749 
1750         if (VERBOSE) {
1751             Log.v(TAG, "SV count: " + info.mSvCount);
1752         }
1753         // Calculate number of satellites used in fix.
1754         int usedInFixCount = 0;
1755         int maxCn0 = 0;
1756         int meanCn0 = 0;
1757         for (int i = 0; i < info.mSvCount; i++) {
1758             if ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1759                 ++usedInFixCount;
1760                 if (info.mCn0s[i] > maxCn0) {
1761                     maxCn0 = (int) info.mCn0s[i];
1762                 }
1763                 meanCn0 += info.mCn0s[i];
1764             }
1765             if (VERBOSE) {
1766                 Log.v(TAG, "svid: " + (info.mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1767                         " cn0: " + info.mCn0s[i] +
1768                         " elev: " + info.mSvElevations[i] +
1769                         " azimuth: " + info.mSvAzimuths[i] +
1770                         " carrier frequency: " + info.mSvCarrierFreqs[i] +
1771                         ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1772                                 ? "  " : " E") +
1773                         ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1774                                 ? "  " : " A") +
1775                         ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1776                                 ? "" : "U") +
1777                         ((info.mSvidWithFlags[i] &
1778                                 GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0
1779                                 ? "" : "F"));
1780             }
1781         }
1782         if (usedInFixCount > 0) {
1783             meanCn0 /= usedInFixCount;
1784         }
1785         // return number of sats used in fix instead of total reported
1786         mLocationExtras.set(usedInFixCount, meanCn0, maxCn0);
1787 
1788         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1789                 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1790             // send an intent to notify that the GPS is no longer receiving fixes.
1791             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1792             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1793             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1794             updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
1795         }
1796     }
1797 
1798     /**
1799      * called from native code to update AGPS status
1800      */
reportAGpsStatus(int type, int status, byte[] ipaddr)1801     private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1802         switch (status) {
1803             case GPS_REQUEST_AGPS_DATA_CONN:
1804                 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1805                 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1806                 InetAddress connectionIpAddress = null;
1807                 if (ipaddr != null) {
1808                     try {
1809                         connectionIpAddress = InetAddress.getByAddress(ipaddr);
1810                         if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1811                     } catch (UnknownHostException e) {
1812                         Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1813                     }
1814                 }
1815                 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1816                 break;
1817             case GPS_RELEASE_AGPS_DATA_CONN:
1818                 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1819                 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1820                 break;
1821             case GPS_AGPS_DATA_CONNECTED:
1822                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1823                 break;
1824             case GPS_AGPS_DATA_CONN_DONE:
1825                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1826                 break;
1827             case GPS_AGPS_DATA_CONN_FAILED:
1828                 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1829                 break;
1830             default:
1831                 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1832         }
1833     }
1834 
releaseSuplConnection(int connStatus)1835     private void releaseSuplConnection(int connStatus) {
1836         sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1837     }
1838 
1839     /**
1840      * called from native code to report NMEA data received
1841      */
reportNmea(long timestamp)1842     private void reportNmea(long timestamp) {
1843         if (!mItarSpeedLimitExceeded) {
1844             int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1845             String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1846             mListenerHelper.onNmeaReceived(timestamp, nmea);
1847         }
1848     }
1849 
1850     /**
1851      * called from native code - GNSS measurements callback
1852      */
reportMeasurementData(GnssMeasurementsEvent event)1853     private void reportMeasurementData(GnssMeasurementsEvent event) {
1854         if (!mItarSpeedLimitExceeded) {
1855             // send to handler to allow native to return quickly
1856             mHandler.post(new Runnable() {
1857                 @Override
1858                 public void run() {
1859                     mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1860                 }
1861             });
1862         }
1863     }
1864 
1865     /**
1866      * called from native code - GNSS navigation message callback
1867      */
reportNavigationMessage(GnssNavigationMessage event)1868     private void reportNavigationMessage(GnssNavigationMessage event) {
1869         if (!mItarSpeedLimitExceeded) {
1870             // send to handler to allow native to return quickly
1871             mHandler.post(new Runnable() {
1872                 @Override
1873                 public void run() {
1874                     mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1875                 }
1876             });
1877         }
1878     }
1879 
1880     /**
1881      * called from native code to inform us what the GPS engine capabilities are
1882      */
setEngineCapabilities(final int capabilities)1883     private void setEngineCapabilities(final int capabilities) {
1884         // send to handler thread for fast native return, and in-order handling
1885         mHandler.post(new Runnable() {
1886             @Override
1887             public void run() {
1888                 mEngineCapabilities = capabilities;
1889 
1890                 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1891                     mNtpTimeHelper.enablePeriodicTimeInjection();
1892                     requestUtcTime();
1893                 }
1894 
1895                 mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability(
1896                         GPS_CAPABILITY_MEASUREMENTS));
1897                 mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability(
1898                         GPS_CAPABILITY_NAV_MESSAGES));
1899                 restartRequests();
1900             }
1901         });
1902     }
1903 
restartRequests()1904     private void restartRequests() {
1905         Log.i(TAG, "restartRequests");
1906 
1907         restartLocationRequest();
1908         mGnssMeasurementsProvider.resumeIfStarted();
1909         mGnssNavigationMessageProvider.resumeIfStarted();
1910         mGnssBatchingProvider.resumeIfStarted();
1911         mGnssGeofenceProvider.resumeIfStarted();
1912     }
1913 
restartLocationRequest()1914     private void restartLocationRequest() {
1915         if (DEBUG) Log.d(TAG, "restartLocationRequest");
1916         mStarted = false;
1917         updateRequirements();
1918     }
1919 
1920     /**
1921      * Called from native code to inform us the hardware year.
1922      */
setGnssYearOfHardware(final int yearOfHardware)1923     private void setGnssYearOfHardware(final int yearOfHardware) {
1924         // mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync
1925         if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1926         mHardwareYear = yearOfHardware;
1927     }
1928 
1929     /**
1930      * Called from native code to inform us the hardware model name.
1931      */
setGnssHardwareModelName(final String modelName)1932     private void setGnssHardwareModelName(final String modelName) {
1933         // mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync
1934         if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName);
1935         mHardwareModelName = modelName;
1936     }
1937 
1938     /**
1939      * Called from native code to inform us GNSS HAL service died.
1940      */
reportGnssServiceDied()1941     private void reportGnssServiceDied() {
1942         if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
1943         mHandler.post(() -> {
1944             class_init_native();
1945             native_init_once();
1946             if (isEnabled()) {
1947                 // re-calls native_init() and other setup.
1948                 handleEnable();
1949                 // resend configuration into the restarted HAL service.
1950                 reloadGpsProperties(mContext, mProperties);
1951             }
1952         });
1953     }
1954 
1955     public interface GnssSystemInfoProvider {
1956         /**
1957          * Returns the year of underlying GPS hardware.
1958          */
getGnssYearOfHardware()1959         int getGnssYearOfHardware();
1960         /**
1961          * Returns the model name of underlying GPS hardware.
1962          */
getGnssHardwareModelName()1963         String getGnssHardwareModelName();
1964     }
1965 
1966     /**
1967      * @hide
1968      */
getGnssSystemInfoProvider()1969     public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1970         return new GnssSystemInfoProvider() {
1971             @Override
1972             public int getGnssYearOfHardware() {
1973                 return mHardwareYear;
1974             }
1975             @Override
1976             public String getGnssHardwareModelName() {
1977                 return mHardwareModelName;
1978             }
1979         };
1980     }
1981 
1982     /**
1983      * @hide
1984      */
1985     public GnssBatchingProvider getGnssBatchingProvider() {
1986         return mGnssBatchingProvider;
1987     }
1988 
1989     public interface GnssMetricsProvider {
1990         /**
1991          * Returns GNSS metrics as proto string
1992          */
1993         String getGnssMetricsAsProtoString();
1994     }
1995 
1996     /**
1997      * @hide
1998      */
1999     public GnssMetricsProvider getGnssMetricsProvider() {
2000         return new GnssMetricsProvider() {
2001             @Override
2002             public String getGnssMetricsAsProtoString() {
2003                 return mGnssMetrics.dumpGnssMetricsAsProtoString();
2004             }
2005         };
2006     }
2007 
2008     /**
2009      * called from native code - GNSS location batch callback
2010      */
2011     private void reportLocationBatch(Location[] locationArray) {
2012         List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
2013         if (DEBUG) {
2014             Log.d(TAG, "Location batch of size " + locationArray.length + " reported");
2015         }
2016         try {
2017             mILocationManager.reportLocationBatch(locations);
2018         } catch (RemoteException e) {
2019             Log.e(TAG, "RemoteException calling reportLocationBatch");
2020         }
2021     }
2022 
2023     /**
2024      * called from native code to request XTRA data
2025      */
2026     private void xtraDownloadRequest() {
2027         if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
2028         sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
2029     }
2030 
2031     /**
2032      * Converts the GPS HAL status to the internal Geofence Hardware status.
2033      */
2034     private int getGeofenceStatus(int status) {
2035         switch (status) {
2036             case GPS_GEOFENCE_OPERATION_SUCCESS:
2037                 return GeofenceHardware.GEOFENCE_SUCCESS;
2038             case GPS_GEOFENCE_ERROR_GENERIC:
2039                 return GeofenceHardware.GEOFENCE_FAILURE;
2040             case GPS_GEOFENCE_ERROR_ID_EXISTS:
2041                 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
2042             case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
2043                 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
2044             case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
2045                 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
2046             case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
2047                 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
2048             default:
2049                 return -1;
2050         }
2051     }
2052 
2053     /**
2054      * Called from native to report GPS Geofence transition
2055      * All geofence callbacks are called on the same thread
2056      */
2057     private void reportGeofenceTransition(int geofenceId, Location location, int transition,
2058             long transitionTimestamp) {
2059         if (mGeofenceHardwareImpl == null) {
2060             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2061         }
2062 
2063         mGeofenceHardwareImpl.reportGeofenceTransition(
2064                 geofenceId,
2065                 location,
2066                 transition,
2067                 transitionTimestamp,
2068                 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
2069                 FusedBatchOptions.SourceTechnologies.GNSS);
2070     }
2071 
2072     /**
2073      * called from native code to report GPS status change.
2074      */
2075     private void reportGeofenceStatus(int status, Location location) {
2076         if (mGeofenceHardwareImpl == null) {
2077             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2078         }
2079         int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
2080         if (status == GPS_GEOFENCE_AVAILABLE) {
2081             monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
2082         }
2083         mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
2084                 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
2085                 monitorStatus,
2086                 location,
2087                 FusedBatchOptions.SourceTechnologies.GNSS);
2088     }
2089 
2090     /**
2091      * called from native code - Geofence Add callback
2092      */
2093     private void reportGeofenceAddStatus(int geofenceId, int status) {
2094         if (mGeofenceHardwareImpl == null) {
2095             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2096         }
2097         mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
2098     }
2099 
2100     /**
2101      * called from native code - Geofence Remove callback
2102      */
2103     private void reportGeofenceRemoveStatus(int geofenceId, int status) {
2104         if (mGeofenceHardwareImpl == null) {
2105             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2106         }
2107         mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
2108     }
2109 
2110     /**
2111      * called from native code - Geofence Pause callback
2112      */
2113     private void reportGeofencePauseStatus(int geofenceId, int status) {
2114         if (mGeofenceHardwareImpl == null) {
2115             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2116         }
2117         mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
2118     }
2119 
2120     /**
2121      * called from native code - Geofence Resume callback
2122      */
2123     private void reportGeofenceResumeStatus(int geofenceId, int status) {
2124         if (mGeofenceHardwareImpl == null) {
2125             mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
2126         }
2127         mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
2128     }
2129 
2130     //=============================================================
2131     // NI Client support
2132     //=============================================================
2133     private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
2134         // Sends a response for an NI request to HAL.
2135         @Override
2136         public boolean sendNiResponse(int notificationId, int userResponse) {
2137             // TODO Add Permission check
2138 
2139             if (DEBUG) {
2140                 Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
2141                         ", response: " + userResponse);
2142             }
2143             native_send_ni_response(notificationId, userResponse);
2144             return true;
2145         }
2146     };
2147 
2148     public INetInitiatedListener getNetInitiatedListener() {
2149         return mNetInitiatedListener;
2150     }
2151 
2152     // Called by JNI function to report an NI request.
2153     public void reportNiNotification(
2154             int notificationId,
2155             int niType,
2156             int notifyFlags,
2157             int timeout,
2158             int defaultResponse,
2159             String requestorId,
2160             String text,
2161             int requestorIdEncoding,
2162             int textEncoding
2163     ) {
2164         Log.i(TAG, "reportNiNotification: entered");
2165         Log.i(TAG, "notificationId: " + notificationId +
2166                 ", niType: " + niType +
2167                 ", notifyFlags: " + notifyFlags +
2168                 ", timeout: " + timeout +
2169                 ", defaultResponse: " + defaultResponse);
2170 
2171         Log.i(TAG, "requestorId: " + requestorId +
2172                 ", text: " + text +
2173                 ", requestorIdEncoding: " + requestorIdEncoding +
2174                 ", textEncoding: " + textEncoding);
2175 
2176         GpsNiNotification notification = new GpsNiNotification();
2177 
2178         notification.notificationId = notificationId;
2179         notification.niType = niType;
2180         notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
2181         notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
2182         notification.privacyOverride =
2183                 (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
2184         notification.timeout = timeout;
2185         notification.defaultResponse = defaultResponse;
2186         notification.requestorId = requestorId;
2187         notification.text = text;
2188         notification.requestorIdEncoding = requestorIdEncoding;
2189         notification.textEncoding = textEncoding;
2190 
2191         mNIHandler.handleNiNotification(notification);
2192     }
2193 
2194     /**
2195      * Called from native code to request set id info.
2196      * We should be careful about receiving null string from the TelephonyManager,
2197      * because sending null String to JNI function would cause a crash.
2198      */
2199 
2200     private void requestSetID(int flags) {
2201         TelephonyManager phone = (TelephonyManager)
2202                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2203         int type = AGPS_SETID_TYPE_NONE;
2204         String data = "";
2205 
2206         if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
2207             String data_temp = phone.getSubscriberId();
2208             if (data_temp == null) {
2209                 // This means the framework does not have the SIM card ready.
2210             } else {
2211                 // This means the framework has the SIM card.
2212                 data = data_temp;
2213                 type = AGPS_SETID_TYPE_IMSI;
2214             }
2215         } else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
2216             String data_temp = phone.getLine1Number();
2217             if (data_temp == null) {
2218                 // This means the framework does not have the SIM card ready.
2219             } else {
2220                 // This means the framework has the SIM card.
2221                 data = data_temp;
2222                 type = AGPS_SETID_TYPE_MSISDN;
2223             }
2224         }
2225         native_agps_set_id(type, data);
2226     }
2227 
2228     /**
2229      * Called from native code to request location info.
2230      */
2231     private void requestLocation(boolean independentFromGnss) {
2232         if (DEBUG) {
2233             Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss);
2234         }
2235         sendMessage(REQUEST_LOCATION, 0, independentFromGnss);
2236     }
2237 
2238     /**
2239      * Called from native code to request utc time info
2240      */
2241     private void requestUtcTime() {
2242         if (DEBUG) Log.d(TAG, "utcTimeRequest");
2243         sendMessage(INJECT_NTP_TIME, 0, null);
2244     }
2245 
2246     /**
2247      * Called from native code to request reference location info
2248      */
2249     private void requestRefLocation() {
2250         TelephonyManager phone = (TelephonyManager)
2251                 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2252         final int phoneType = phone.getPhoneType();
2253         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2254             GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2255             if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2256                     && (phone.getNetworkOperator().length() > 3)) {
2257                 int type;
2258                 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0, 3));
2259                 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2260                 int networkType = phone.getNetworkType();
2261                 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2262                         || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2263                         || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2264                         || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2265                         || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2266                     type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2267                 } else {
2268                     type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2269                 }
2270                 native_agps_set_ref_location_cellid(type, mcc, mnc,
2271                         gsm_cell.getLac(), gsm_cell.getCid());
2272             } else {
2273                 Log.e(TAG, "Error getting cell location info.");
2274             }
2275         } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2276             Log.e(TAG, "CDMA not supported.");
2277         }
2278     }
2279 
2280     private void sendMessage(int message, int arg, Object obj) {
2281         // hold a wake lock until this message is delivered
2282         // note that this assumes the message will not be removed from the queue before
2283         // it is handled (otherwise the wake lock would be leaked).
2284         mWakeLock.acquire();
2285         if (Log.isLoggable(TAG, Log.INFO)) {
2286             Log.i(TAG, "WakeLock acquired by sendMessage(" + messageIdAsString(message) + ", " + arg
2287                     + ", " + obj + ")");
2288         }
2289         mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2290     }
2291 
2292     private final class ProviderHandler extends Handler {
2293         public ProviderHandler(Looper looper) {
2294             super(looper, null, true /*async*/);
2295         }
2296 
2297         @Override
2298         public void handleMessage(Message msg) {
2299             int message = msg.what;
2300             switch (message) {
2301                 case ENABLE:
2302                     if (msg.arg1 == 1) {
2303                         handleEnable();
2304                     } else {
2305                         handleDisable();
2306                     }
2307                     break;
2308                 case SET_REQUEST:
2309                     GpsRequest gpsRequest = (GpsRequest) msg.obj;
2310                     handleSetRequest(gpsRequest.request, gpsRequest.source);
2311                     break;
2312                 case UPDATE_NETWORK_STATE:
2313                     handleUpdateNetworkState((Network) msg.obj);
2314                     break;
2315                 case REQUEST_SUPL_CONNECTION:
2316                     handleRequestSuplConnection((InetAddress) msg.obj);
2317                     break;
2318                 case RELEASE_SUPL_CONNECTION:
2319                     handleReleaseSuplConnection(msg.arg1);
2320                     break;
2321                 case INJECT_NTP_TIME:
2322                     mNtpTimeHelper.retrieveAndInjectNtpTime();
2323                     break;
2324                 case REQUEST_LOCATION:
2325                     handleRequestLocation((boolean) msg.obj);
2326                     break;
2327                 case DOWNLOAD_XTRA_DATA:
2328                     handleDownloadXtraData();
2329                     break;
2330                 case DOWNLOAD_XTRA_DATA_FINISHED:
2331                     mDownloadXtraDataPending = STATE_IDLE;
2332                     break;
2333                 case UPDATE_LOCATION:
2334                     handleUpdateLocation((Location) msg.obj);
2335                     break;
2336                 case SUBSCRIPTION_OR_SIM_CHANGED:
2337                     subscriptionOrSimChanged(mContext);
2338                     break;
2339                 case INITIALIZE_HANDLER:
2340                     handleInitialize();
2341                     break;
2342                 case REPORT_LOCATION:
2343                     handleReportLocation(msg.arg1 == 1, (Location) msg.obj);
2344                     break;
2345                 case REPORT_SV_STATUS:
2346                     handleReportSvStatus((SvStatusInfo) msg.obj);
2347                     break;
2348             }
2349             if (msg.arg2 == 1) {
2350                 // wakelock was taken for this message, release it
2351                 mWakeLock.release();
2352                 if (Log.isLoggable(TAG, Log.INFO)) {
2353                     Log.i(TAG, "WakeLock released by handleMessage(" + messageIdAsString(message)
2354                             + ", " + msg.arg1 + ", " + msg.obj + ")");
2355                 }
2356             }
2357         }
2358 
2359         /**
2360          * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2361          * It is in charge of loading properties and registering for events that will be posted to
2362          * this handler.
2363          */
2364         private void handleInitialize() {
2365             native_init_once();
2366 
2367             /*
2368              * A cycle of native_init() and native_cleanup() is needed so that callbacks are
2369              * registered after bootup even when location is disabled.
2370              * This will allow Emergency SUPL to work even when location is disabled before device
2371              * restart.
2372              */
2373             boolean isInitialized = native_init();
2374             if (!isInitialized) {
2375                 Log.w(TAG, "Native initialization failed at bootup");
2376             } else {
2377                 native_cleanup();
2378             }
2379 
2380             // load default GPS configuration
2381             // (this configuration might change in the future based on SIM changes)
2382             reloadGpsProperties(mContext, mProperties);
2383 
2384             // TODO: When this object "finishes" we should unregister by invoking
2385             // SubscriptionManager.getInstance(mContext).unregister
2386             // (mOnSubscriptionsChangedListener);
2387             // This is not strictly necessary because it will be unregistered if the
2388             // notification fails but it is good form.
2389 
2390             // Register for SubscriptionInfo list changes which is guaranteed
2391             // to invoke onSubscriptionsChanged the first time.
2392             SubscriptionManager.from(mContext)
2393                     .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2394 
2395             // listen for events
2396             IntentFilter intentFilter;
2397             if (native_is_agps_ril_supported()) {
2398                 intentFilter = new IntentFilter();
2399                 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2400                 intentFilter.addDataScheme("sms");
2401                 intentFilter.addDataAuthority("localhost", "7275");
2402                 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2403 
2404                 intentFilter = new IntentFilter();
2405                 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2406                 try {
2407                     intentFilter.addDataType("application/vnd.omaloc-supl-init");
2408                 } catch (IntentFilter.MalformedMimeTypeException e) {
2409                     Log.w(TAG, "Malformed SUPL init mime type");
2410                 }
2411                 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2412             } else if (DEBUG) {
2413                 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2414                         + " HAL is not supported");
2415             }
2416 
2417             intentFilter = new IntentFilter();
2418             intentFilter.addAction(ALARM_WAKEUP);
2419             intentFilter.addAction(ALARM_TIMEOUT);
2420             intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2421             intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2422             intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2423             intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2424             intentFilter.addAction(SIM_STATE_CHANGED);
2425             mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2426 
2427             // register for connectivity change events, this is equivalent to the deprecated way of
2428             // registering for CONNECTIVITY_ACTION broadcasts
2429             NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2430             networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
2431             networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
2432             networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
2433             NetworkRequest networkRequest = networkRequestBuilder.build();
2434             mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2435 
2436             // listen for PASSIVE_PROVIDER updates
2437             LocationManager locManager =
2438                     (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2439             long minTime = 0;
2440             float minDistance = 0;
2441             boolean oneShot = false;
2442             LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2443                     LocationManager.PASSIVE_PROVIDER,
2444                     minTime,
2445                     minDistance,
2446                     oneShot);
2447             // Don't keep track of this request since it's done on behalf of other clients
2448             // (which are kept track of separately).
2449             request.setHideFromAppOps(true);
2450             locManager.requestLocationUpdates(
2451                     request,
2452                     new NetworkLocationListener(),
2453                     getLooper());
2454         }
2455     }
2456 
2457     private abstract class LocationChangeListener implements LocationListener {
2458         int numLocationUpdateRequest;
2459 
2460         @Override
2461         public void onStatusChanged(String provider, int status, Bundle extras) {
2462         }
2463 
2464         @Override
2465         public void onProviderEnabled(String provider) {
2466         }
2467 
2468         @Override
2469         public void onProviderDisabled(String provider) {
2470         }
2471     }
2472 
2473     private final class NetworkLocationListener extends LocationChangeListener {
2474         @Override
2475         public void onLocationChanged(Location location) {
2476             // this callback happens on mHandler looper
2477             if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2478                 handleUpdateLocation(location);
2479             }
2480         }
2481     }
2482 
2483     private final class FusedLocationListener extends LocationChangeListener {
2484         @Override
2485         public void onLocationChanged(Location location) {
2486             if (LocationManager.FUSED_PROVIDER.equals(location.getProvider())) {
2487                 injectBestLocation(location);
2488             }
2489         }
2490     }
2491 
2492     private String getSelectedApn() {
2493         Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2494         Cursor cursor = null;
2495         try {
2496             cursor = mContext.getContentResolver().query(
2497                     uri,
2498                     new String[]{"apn"},
2499                     null /* selection */,
2500                     null /* selectionArgs */,
2501                     Carriers.DEFAULT_SORT_ORDER);
2502             if (cursor != null && cursor.moveToFirst()) {
2503                 return cursor.getString(0);
2504             } else {
2505                 Log.e(TAG, "No APN found to select.");
2506             }
2507         } catch (Exception e) {
2508             Log.e(TAG, "Error encountered on selecting the APN.", e);
2509         } finally {
2510             if (cursor != null) {
2511                 cursor.close();
2512             }
2513         }
2514 
2515         return null;
2516     }
2517 
2518     private int getApnIpType(String apn) {
2519         ensureInHandlerThread();
2520         if (apn == null) {
2521             return APN_INVALID;
2522         }
2523 
2524         String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2525         Cursor cursor = null;
2526         try {
2527             cursor = mContext.getContentResolver().query(
2528                     Carriers.CONTENT_URI,
2529                     new String[]{Carriers.PROTOCOL},
2530                     selection,
2531                     null,
2532                     Carriers.DEFAULT_SORT_ORDER);
2533 
2534             if (null != cursor && cursor.moveToFirst()) {
2535                 return translateToApnIpType(cursor.getString(0), apn);
2536             } else {
2537                 Log.e(TAG, "No entry found in query for APN: " + apn);
2538             }
2539         } catch (Exception e) {
2540             Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2541         } finally {
2542             if (cursor != null) {
2543                 cursor.close();
2544             }
2545         }
2546 
2547         return APN_INVALID;
2548     }
2549 
2550     private int translateToApnIpType(String ipProtocol, String apn) {
2551         if ("IP".equals(ipProtocol)) {
2552             return APN_IPV4;
2553         }
2554         if ("IPV6".equals(ipProtocol)) {
2555             return APN_IPV6;
2556         }
2557         if ("IPV4V6".equals(ipProtocol)) {
2558             return APN_IPV4V6;
2559         }
2560 
2561         // we hit the default case so the ipProtocol is not recognized
2562         String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2563         Log.e(TAG, message);
2564         return APN_INVALID;
2565     }
2566 
2567     private void setRouting() {
2568         if (mAGpsDataConnectionIpAddr == null) {
2569             return;
2570         }
2571 
2572         // TODO: replace the use of this deprecated API
2573         boolean result = mConnMgr.requestRouteToHostAddress(
2574                 ConnectivityManager.TYPE_MOBILE_SUPL,
2575                 mAGpsDataConnectionIpAddr);
2576 
2577         if (!result) {
2578             Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2579         } else if (DEBUG) {
2580             Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2581         }
2582     }
2583 
2584     /**
2585      * @return {@code true} if there is a data network available for outgoing connections,
2586      * {@code false} otherwise.
2587      */
2588     private boolean isDataNetworkConnected() {
2589         NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2590         return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2591     }
2592 
2593     /**
2594      * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2595      */
2596     private void ensureInHandlerThread() {
2597         if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2598             return;
2599         }
2600         throw new RuntimeException("This method must run on the Handler thread.");
2601     }
2602 
2603     /**
2604      * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2605      */
2606     private String agpsDataConnStateAsString() {
2607         switch (mAGpsDataConnectionState) {
2608             case AGPS_DATA_CONNECTION_CLOSED:
2609                 return "CLOSED";
2610             case AGPS_DATA_CONNECTION_OPEN:
2611                 return "OPEN";
2612             case AGPS_DATA_CONNECTION_OPENING:
2613                 return "OPENING";
2614             default:
2615                 return "<Unknown>";
2616         }
2617     }
2618 
2619     /**
2620      * @return A string representing the given GPS_AGPS_DATA status.
2621      */
2622     private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2623         switch (agpsDataConnStatus) {
2624             case GPS_AGPS_DATA_CONNECTED:
2625                 return "CONNECTED";
2626             case GPS_AGPS_DATA_CONN_DONE:
2627                 return "DONE";
2628             case GPS_AGPS_DATA_CONN_FAILED:
2629                 return "FAILED";
2630             case GPS_RELEASE_AGPS_DATA_CONN:
2631                 return "RELEASE";
2632             case GPS_REQUEST_AGPS_DATA_CONN:
2633                 return "REQUEST";
2634             default:
2635                 return "<Unknown>";
2636         }
2637     }
2638 
2639     /**
2640      * @return A string representing the given message ID.
2641      */
2642     private String messageIdAsString(int message) {
2643         switch (message) {
2644             case ENABLE:
2645                 return "ENABLE";
2646             case SET_REQUEST:
2647                 return "SET_REQUEST";
2648             case UPDATE_NETWORK_STATE:
2649                 return "UPDATE_NETWORK_STATE";
2650             case REQUEST_SUPL_CONNECTION:
2651                 return "REQUEST_SUPL_CONNECTION";
2652             case RELEASE_SUPL_CONNECTION:
2653                 return "RELEASE_SUPL_CONNECTION";
2654             case INJECT_NTP_TIME:
2655                 return "INJECT_NTP_TIME";
2656             case REQUEST_LOCATION:
2657                 return "REQUEST_LOCATION";
2658             case DOWNLOAD_XTRA_DATA:
2659                 return "DOWNLOAD_XTRA_DATA";
2660             case DOWNLOAD_XTRA_DATA_FINISHED:
2661                 return "DOWNLOAD_XTRA_DATA_FINISHED";
2662             case UPDATE_LOCATION:
2663                 return "UPDATE_LOCATION";
2664             case SUBSCRIPTION_OR_SIM_CHANGED:
2665                 return "SUBSCRIPTION_OR_SIM_CHANGED";
2666             case INITIALIZE_HANDLER:
2667                 return "INITIALIZE_HANDLER";
2668             case REPORT_LOCATION:
2669                 return "REPORT_LOCATION";
2670             case REPORT_SV_STATUS:
2671                 return "REPORT_SV_STATUS";
2672             default:
2673                 return "<Unknown>";
2674         }
2675     }
2676 
2677 
2678     @Override
2679     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2680         StringBuilder s = new StringBuilder();
2681         s.append("  mStarted=").append(mStarted).append('\n');
2682         s.append("  mFixInterval=").append(mFixInterval).append('\n');
2683         s.append("  mLowPowerMode=").append(mLowPowerMode).append('\n');
2684         s.append("  mGnssMeasurementsProvider.isRegistered()=")
2685                 .append(mGnssMeasurementsProvider.isRegistered()).append('\n');
2686         s.append("  mGnssNavigationMessageProvider.isRegistered()=")
2687                 .append(mGnssNavigationMessageProvider.isRegistered()).append('\n');
2688         s.append("  mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2689         s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2690         s.append(" ( ");
2691         if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2692         if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2693         if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2694         if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2695         if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2696         if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2697         if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2698         if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2699         s.append(")\n");
2700         s.append(mGnssMetrics.dumpGnssMetricsAsText());
2701         s.append("  native internal state: ").append(native_get_internal_state());
2702         s.append("\n");
2703         pw.append(s);
2704     }
2705 
2706     // preallocated to avoid memory allocation in reportNmea()
2707     private byte[] mNmeaBuffer = new byte[120];
2708 
2709     static {
2710         class_init_native();
2711     }
2712 
2713     private static native void class_init_native();
2714 
2715     private static native boolean native_is_supported();
2716 
2717     private static native boolean native_is_agps_ril_supported();
2718 
2719     private static native boolean native_is_gnss_configuration_supported();
2720 
2721     private static native void native_init_once();
2722 
2723     private native boolean native_init();
2724 
2725     private native void native_cleanup();
2726 
2727     private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2728             int preferred_accuracy, int preferred_time, boolean lowPowerMode);
2729 
2730     private native boolean native_start();
2731 
2732     private native boolean native_stop();
2733 
2734     private native void native_delete_aiding_data(int flags);
2735 
2736     private native int native_read_nmea(byte[] buffer, int bufferSize);
2737 
2738     private native void native_inject_best_location(
2739             int gnssLocationFlags,
2740             double latitudeDegrees,
2741             double longitudeDegrees,
2742             double altitudeMeters,
2743             float speedMetersPerSec,
2744             float bearingDegrees,
2745             float horizontalAccuracyMeters,
2746             float verticalAccuracyMeters,
2747             float speedAccuracyMetersPerSecond,
2748             float bearingAccuracyDegrees,
2749             long timestamp);
2750 
2751     private native void native_inject_location(double latitude, double longitude, float accuracy);
2752 
2753     // XTRA Support
2754     private native void native_inject_time(long time, long timeReference, int uncertainty);
2755 
2756     private native boolean native_supports_xtra();
2757 
2758     private native void native_inject_xtra_data(byte[] data, int length);
2759 
2760     // DEBUG Support
2761     private native String native_get_internal_state();
2762 
2763     // AGPS Support
2764     private native void native_agps_data_conn_open(String apn, int apnIpType);
2765 
2766     private native void native_agps_data_conn_closed();
2767 
2768     private native void native_agps_data_conn_failed();
2769 
2770     private native void native_agps_ni_message(byte[] msg, int length);
2771 
2772     private native void native_set_agps_server(int type, String hostname, int port);
2773 
2774     // Network-initiated (NI) Support
2775     private native void native_send_ni_response(int notificationId, int userResponse);
2776 
2777     // AGPS ril suport
2778     private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2779             int lac, int cid);
2780 
2781     private native void native_agps_set_id(int type, String setid);
2782 
2783     private native void native_update_network_state(boolean connected, int type,
2784             boolean roaming, boolean available, String extraInfo, String defaultAPN);
2785 
2786     // GNSS Configuration
2787     private static native boolean native_set_supl_version(int version);
2788 
2789     private static native boolean native_set_supl_mode(int mode);
2790 
2791     private static native boolean native_set_supl_es(int es);
2792 
2793     private static native boolean native_set_lpp_profile(int lppProfile);
2794 
2795     private static native boolean native_set_gnss_pos_protocol_select(int gnssPosProtocolSelect);
2796 
2797     private static native boolean native_set_gps_lock(int gpsLock);
2798 
2799     private static native boolean native_set_emergency_supl_pdn(int emergencySuplPdn);
2800 
2801     private static native boolean native_set_satellite_blacklist(int[] constellations, int[] svIds);
2802 }
2803 
2804