OSDN Git Service

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