OSDN Git Service

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