OSDN Git Service

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