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