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