Merge "GNSS HAL must be notified correctly when networks disconnect"
This commit is contained in:
@@ -24,7 +24,6 @@ import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.Cursor;
|
||||
import android.hardware.location.GeofenceHardware;
|
||||
import android.hardware.location.GeofenceHardwareImpl;
|
||||
import android.location.Criteria;
|
||||
@@ -42,12 +41,6 @@ import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationProvider;
|
||||
import android.location.LocationRequest;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.Binder;
|
||||
@@ -67,7 +60,6 @@ import android.os.UserHandle;
|
||||
import android.os.WorkSource;
|
||||
import android.os.WorkSource.WorkChain;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Telephony.Carriers;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
|
||||
@@ -92,8 +84,6 @@ import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -135,14 +125,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
private static final int GPS_STATUS_ENGINE_ON = 3;
|
||||
private static final int GPS_STATUS_ENGINE_OFF = 4;
|
||||
|
||||
// these need to match AGnssStatusValue enum in IAGnssCallback.hal
|
||||
/** AGPS status event values. */
|
||||
private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
|
||||
private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
|
||||
private static final int GPS_AGPS_DATA_CONNECTED = 3;
|
||||
private static final int GPS_AGPS_DATA_CONN_DONE = 4;
|
||||
private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
|
||||
|
||||
// these need to match GnssLocationFlags enum in types.hal
|
||||
private static final int LOCATION_INVALID = 0;
|
||||
private static final int LOCATION_HAS_LAT_LONG = 1;
|
||||
@@ -188,17 +170,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
private static final int AGPS_TYPE_SUPL = 1;
|
||||
private static final int AGPS_TYPE_C2K = 2;
|
||||
|
||||
// these must match the ApnIpType enum in IAGnss.hal
|
||||
private static final int APN_INVALID = 0;
|
||||
private static final int APN_IPV4 = 1;
|
||||
private static final int APN_IPV6 = 2;
|
||||
private static final int APN_IPV4V6 = 3;
|
||||
|
||||
// for mAGpsDataConnectionState
|
||||
private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
|
||||
private static final int AGPS_DATA_CONNECTION_OPENING = 1;
|
||||
private static final int AGPS_DATA_CONNECTION_OPEN = 2;
|
||||
|
||||
// Handler messages
|
||||
private static final int CHECK_LOCATION = 1;
|
||||
private static final int ENABLE = 2;
|
||||
@@ -254,9 +225,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
private static final long LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS = 1000;
|
||||
// Default update duration in milliseconds for REQUEST_LOCATION.
|
||||
private static final long LOCATION_UPDATE_DURATION_MILLIS = 10 * 1000;
|
||||
// Default time limit in milliseconds for the ConnectivityManager to find a suitable
|
||||
// network with SUPL connectivity or report an error.
|
||||
private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 10 * 1000;
|
||||
|
||||
/** simpler wrapper for ProviderRequest + Worksource */
|
||||
private static class GpsRequest {
|
||||
@@ -427,12 +395,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
// Handler for processing events
|
||||
private Handler mHandler;
|
||||
|
||||
/** It must be accessed only inside {@link #mHandler}. */
|
||||
private int mAGpsDataConnectionState;
|
||||
/** It must be accessed only inside {@link #mHandler}. */
|
||||
private InetAddress mAGpsDataConnectionIpAddr;
|
||||
|
||||
private final ConnectivityManager mConnMgr;
|
||||
private final GnssNetworkConnectivityHandler mNetworkConnectivityHandler;
|
||||
private final GpsNetInitiatedHandler mNIHandler;
|
||||
|
||||
// Wakelocks
|
||||
@@ -507,60 +470,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
|
||||
return mGnssNavigationMessageProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback used to listen for data connectivity changes.
|
||||
*/
|
||||
private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
|
||||
new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(Network network) {
|
||||
mNtpTimeHelper.onNetworkAvailable();
|
||||
if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
|
||||
if (mSupportsXtra) {
|
||||
// Download only if supported, (prevents an unneccesary on-boot
|
||||
// download)
|
||||
xtraDownloadRequest();
|
||||
}
|
||||
}
|
||||
// Always on, notify HAL so it can get data it needs
|
||||
sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback used to listen for availability of a requested SUPL connection.
|
||||
* It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
|
||||
* manage the registration/un-registration lifetimes separate.
|
||||
*/
|
||||
private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
|
||||
new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(Network network) {
|
||||
if (DEBUG) Log.d(TAG, "SUPL network connection available.");
|
||||
// Specific to a change to a SUPL enabled network becoming ready
|
||||
sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
Log.i(TAG, "SUPL network connection lost.");
|
||||
releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnavailable() {
|
||||
Log.i(TAG, "SUPL network connection request timed out.");
|
||||
// Could not setup the connection to the network in the specified time duration.
|
||||
releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
|
||||
}
|
||||
};
|
||||
|
||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
@@ -793,7 +702,10 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
|
||||
mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
|
||||
|
||||
mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
mNetworkConnectivityHandler = new GnssNetworkConnectivityHandler(
|
||||
context,
|
||||
GnssLocationProvider.this::onNetworkAvailable,
|
||||
looper);
|
||||
|
||||
// App ops service to keep track of who is accessing the GPS
|
||||
mAppOps = mContext.getSystemService(AppOpsManager.class);
|
||||
@@ -843,8 +755,8 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
return isEnabled();
|
||||
}
|
||||
};
|
||||
mGnssMetrics = new GnssMetrics(mBatteryStats);
|
||||
|
||||
mGnssMetrics = new GnssMetrics(mBatteryStats);
|
||||
mNtpTimeHelper = new NtpTimeHelper(mContext, looper, this);
|
||||
mGnssSatelliteBlacklistHelper = new GnssSatelliteBlacklistHelper(mContext,
|
||||
looper, this);
|
||||
@@ -866,7 +778,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
return PROPERTIES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements {@link InjectNtpTimeCallback#injectTime}
|
||||
*/
|
||||
@@ -875,124 +786,17 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
native_inject_time(time, timeReference, uncertainty);
|
||||
}
|
||||
|
||||
private void handleUpdateNetworkState(Network network) {
|
||||
// retrieve NetworkInfo for this UID
|
||||
NetworkInfo info = mConnMgr.getNetworkInfo(network);
|
||||
|
||||
boolean networkAvailable = false;
|
||||
boolean isConnected = false;
|
||||
int type = ConnectivityManager.TYPE_NONE;
|
||||
boolean isRoaming = false;
|
||||
String apnName = null;
|
||||
|
||||
if (info != null) {
|
||||
networkAvailable = info.isAvailable() && TelephonyManager.getDefault().getDataEnabled();
|
||||
isConnected = info.isConnected();
|
||||
type = info.getType();
|
||||
isRoaming = info.isRoaming();
|
||||
apnName = info.getExtraInfo();
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
String message = String.format(
|
||||
"UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
|
||||
agpsDataConnStateAsString(),
|
||||
isConnected,
|
||||
info,
|
||||
mConnMgr.getNetworkCapabilities(network));
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
|
||||
if (native_is_agps_ril_supported()) {
|
||||
String defaultApn = getSelectedApn();
|
||||
if (defaultApn == null) {
|
||||
defaultApn = "dummy-apn";
|
||||
/**
|
||||
* Implements {@link GnssNetworkConnectivityHandler.GnssNetworkListener#onNetworkAvailable()}
|
||||
*/
|
||||
private void onNetworkAvailable() {
|
||||
mNtpTimeHelper.onNetworkAvailable();
|
||||
if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
|
||||
if (mSupportsXtra) {
|
||||
// Download only if supported, (prevents an unneccesary on-boot
|
||||
// download)
|
||||
xtraDownloadRequest();
|
||||
}
|
||||
|
||||
native_update_network_state(
|
||||
isConnected,
|
||||
type,
|
||||
isRoaming,
|
||||
networkAvailable,
|
||||
apnName,
|
||||
defaultApn);
|
||||
} else if (DEBUG) {
|
||||
Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
|
||||
}
|
||||
|
||||
if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
|
||||
if (isConnected) {
|
||||
if (apnName == null) {
|
||||
// assign a dummy value in the case of C2K as otherwise we will have a runtime
|
||||
// exception in the following call to native_agps_data_conn_open
|
||||
apnName = "dummy-apn";
|
||||
}
|
||||
int apnIpType = getApnIpType(apnName);
|
||||
setRouting();
|
||||
if (DEBUG) {
|
||||
String message = String.format(
|
||||
"native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
|
||||
apnName,
|
||||
apnIpType);
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
native_agps_data_conn_open(apnName, apnIpType);
|
||||
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
|
||||
} else {
|
||||
handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRequestSuplConnection(InetAddress address) {
|
||||
if (DEBUG) {
|
||||
String message = String.format(
|
||||
"requestSuplConnection, state=%s, address=%s",
|
||||
agpsDataConnStateAsString(),
|
||||
address);
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
|
||||
if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
|
||||
return;
|
||||
}
|
||||
mAGpsDataConnectionIpAddr = address;
|
||||
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
|
||||
|
||||
NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
|
||||
requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
|
||||
requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
|
||||
NetworkRequest request = requestBuilder.build();
|
||||
mConnMgr.requestNetwork(
|
||||
request,
|
||||
mSuplConnectivityCallback,
|
||||
SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
|
||||
}
|
||||
|
||||
private void handleReleaseSuplConnection(int agpsDataConnStatus) {
|
||||
if (DEBUG) {
|
||||
String message = String.format(
|
||||
"releaseSuplConnection, state=%s, status=%s",
|
||||
agpsDataConnStateAsString(),
|
||||
agpsDataConnStatusAsString(agpsDataConnStatus));
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
|
||||
if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
|
||||
return;
|
||||
}
|
||||
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
|
||||
|
||||
mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
|
||||
switch (agpsDataConnStatus) {
|
||||
case GPS_AGPS_DATA_CONN_FAILED:
|
||||
native_agps_data_conn_failed();
|
||||
break;
|
||||
case GPS_RELEASE_AGPS_DATA_CONN:
|
||||
native_agps_data_conn_closed();
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1091,7 +895,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
// already downloading data
|
||||
return;
|
||||
}
|
||||
if (!isDataNetworkConnected()) {
|
||||
if (!mNetworkConnectivityHandler.isDataNetworkConnected()) {
|
||||
// try again when network is up
|
||||
mDownloadXtraDataPending = STATE_PENDING_NETWORK;
|
||||
return;
|
||||
@@ -1822,41 +1626,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
* called from native code to update AGPS status
|
||||
*/
|
||||
private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
|
||||
switch (status) {
|
||||
case GPS_REQUEST_AGPS_DATA_CONN:
|
||||
if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
|
||||
Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
|
||||
InetAddress connectionIpAddress = null;
|
||||
if (ipaddr != null) {
|
||||
try {
|
||||
connectionIpAddress = InetAddress.getByAddress(ipaddr);
|
||||
if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
|
||||
} catch (UnknownHostException e) {
|
||||
Log.e(TAG, "Bad IP Address: " + ipaddr, e);
|
||||
}
|
||||
}
|
||||
sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
|
||||
break;
|
||||
case GPS_RELEASE_AGPS_DATA_CONN:
|
||||
if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
|
||||
releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
|
||||
break;
|
||||
case GPS_AGPS_DATA_CONNECTED:
|
||||
if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
|
||||
break;
|
||||
case GPS_AGPS_DATA_CONN_DONE:
|
||||
if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
|
||||
break;
|
||||
case GPS_AGPS_DATA_CONN_FAILED:
|
||||
if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
|
||||
break;
|
||||
default:
|
||||
if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseSuplConnection(int connStatus) {
|
||||
sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
|
||||
mNetworkConnectivityHandler.onReportAGpsStatus(type, status, ipaddr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2332,15 +2102,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
GpsRequest gpsRequest = (GpsRequest) msg.obj;
|
||||
handleSetRequest(gpsRequest.request, gpsRequest.source);
|
||||
break;
|
||||
case UPDATE_NETWORK_STATE:
|
||||
handleUpdateNetworkState((Network) msg.obj);
|
||||
break;
|
||||
case REQUEST_SUPL_CONNECTION:
|
||||
handleRequestSuplConnection((InetAddress) msg.obj);
|
||||
break;
|
||||
case RELEASE_SUPL_CONNECTION:
|
||||
handleReleaseSuplConnection(msg.arg1);
|
||||
break;
|
||||
case INJECT_NTP_TIME:
|
||||
mNtpTimeHelper.retrieveAndInjectNtpTime();
|
||||
break;
|
||||
@@ -2426,14 +2187,7 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
intentFilter.addAction(SIM_STATE_CHANGED);
|
||||
mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
|
||||
|
||||
// register for connectivity change events, this is equivalent to the deprecated way of
|
||||
// registering for CONNECTIVITY_ACTION broadcasts
|
||||
NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
|
||||
networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
|
||||
networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
|
||||
networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
|
||||
NetworkRequest networkRequest = networkRequestBuilder.build();
|
||||
mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
|
||||
mNetworkConnectivityHandler.registerNetworkCallbacks();
|
||||
|
||||
// listen for PASSIVE_PROVIDER updates
|
||||
LocationManager locManager =
|
||||
@@ -2491,160 +2245,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
}
|
||||
}
|
||||
|
||||
private String getSelectedApn() {
|
||||
Uri uri = Uri.parse("content://telephony/carriers/preferapn");
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = mContext.getContentResolver().query(
|
||||
uri,
|
||||
new String[]{"apn"},
|
||||
null /* selection */,
|
||||
null /* selectionArgs */,
|
||||
Carriers.DEFAULT_SORT_ORDER);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getString(0);
|
||||
} else {
|
||||
Log.e(TAG, "No APN found to select.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error encountered on selecting the APN.", e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int getApnIpType(String apn) {
|
||||
ensureInHandlerThread();
|
||||
if (apn == null) {
|
||||
return APN_INVALID;
|
||||
}
|
||||
TelephonyManager phone = (TelephonyManager)
|
||||
mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
// Carrier configuration may override framework roaming state, we need to use the actual
|
||||
// modem roaming state instead of the framework roaming state.
|
||||
boolean isDataRoamingFromRegistration = phone.getServiceState().
|
||||
getDataRoamingFromRegistration();
|
||||
String projection = isDataRoamingFromRegistration ? Carriers.ROAMING_PROTOCOL :
|
||||
Carriers.PROTOCOL;
|
||||
String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = mContext.getContentResolver().query(
|
||||
Carriers.CONTENT_URI,
|
||||
new String[]{projection},
|
||||
selection,
|
||||
null,
|
||||
Carriers.DEFAULT_SORT_ORDER);
|
||||
|
||||
if (null != cursor && cursor.moveToFirst()) {
|
||||
return translateToApnIpType(cursor.getString(0), apn);
|
||||
} else {
|
||||
Log.e(TAG, "No entry found in query for APN: " + apn);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error encountered on APN query for: " + apn, e);
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
return APN_INVALID;
|
||||
}
|
||||
|
||||
private int translateToApnIpType(String ipProtocol, String apn) {
|
||||
if ("IP".equals(ipProtocol)) {
|
||||
return APN_IPV4;
|
||||
}
|
||||
if ("IPV6".equals(ipProtocol)) {
|
||||
return APN_IPV6;
|
||||
}
|
||||
if ("IPV4V6".equals(ipProtocol)) {
|
||||
return APN_IPV4V6;
|
||||
}
|
||||
|
||||
// we hit the default case so the ipProtocol is not recognized
|
||||
String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
|
||||
Log.e(TAG, message);
|
||||
return APN_INVALID;
|
||||
}
|
||||
|
||||
private void setRouting() {
|
||||
if (mAGpsDataConnectionIpAddr == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: replace the use of this deprecated API
|
||||
boolean result = mConnMgr.requestRouteToHostAddress(
|
||||
ConnectivityManager.TYPE_MOBILE_SUPL,
|
||||
mAGpsDataConnectionIpAddr);
|
||||
|
||||
if (!result) {
|
||||
Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
|
||||
} else if (DEBUG) {
|
||||
Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if there is a data network available for outgoing connections,
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
private boolean isDataNetworkConnected() {
|
||||
NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
|
||||
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the calling function is running in the thread associated with {@link #mHandler}.
|
||||
*/
|
||||
private void ensureInHandlerThread() {
|
||||
if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException("This method must run on the Handler thread.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
|
||||
*/
|
||||
private String agpsDataConnStateAsString() {
|
||||
switch (mAGpsDataConnectionState) {
|
||||
case AGPS_DATA_CONNECTION_CLOSED:
|
||||
return "CLOSED";
|
||||
case AGPS_DATA_CONNECTION_OPEN:
|
||||
return "OPEN";
|
||||
case AGPS_DATA_CONNECTION_OPENING:
|
||||
return "OPENING";
|
||||
default:
|
||||
return "<Unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A string representing the given GPS_AGPS_DATA status.
|
||||
*/
|
||||
private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
|
||||
switch (agpsDataConnStatus) {
|
||||
case GPS_AGPS_DATA_CONNECTED:
|
||||
return "CONNECTED";
|
||||
case GPS_AGPS_DATA_CONN_DONE:
|
||||
return "DONE";
|
||||
case GPS_AGPS_DATA_CONN_FAILED:
|
||||
return "FAILED";
|
||||
case GPS_RELEASE_AGPS_DATA_CONN:
|
||||
return "RELEASE";
|
||||
case GPS_REQUEST_AGPS_DATA_CONN:
|
||||
return "REQUEST";
|
||||
default:
|
||||
return "<Unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A string representing the given message ID.
|
||||
*/
|
||||
@@ -2654,12 +2254,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
return "ENABLE";
|
||||
case SET_REQUEST:
|
||||
return "SET_REQUEST";
|
||||
case UPDATE_NETWORK_STATE:
|
||||
return "UPDATE_NETWORK_STATE";
|
||||
case REQUEST_SUPL_CONNECTION:
|
||||
return "REQUEST_SUPL_CONNECTION";
|
||||
case RELEASE_SUPL_CONNECTION:
|
||||
return "RELEASE_SUPL_CONNECTION";
|
||||
case INJECT_NTP_TIME:
|
||||
return "INJECT_NTP_TIME";
|
||||
case REQUEST_LOCATION:
|
||||
@@ -2683,7 +2277,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
@@ -2723,8 +2316,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
|
||||
private static native boolean native_is_supported();
|
||||
|
||||
private static native boolean native_is_agps_ril_supported();
|
||||
|
||||
private static native boolean native_is_gnss_configuration_supported();
|
||||
|
||||
private static native void native_init_once();
|
||||
@@ -2770,12 +2361,6 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
private native String native_get_internal_state();
|
||||
|
||||
// AGPS Support
|
||||
private native void native_agps_data_conn_open(String apn, int apnIpType);
|
||||
|
||||
private native void native_agps_data_conn_closed();
|
||||
|
||||
private native void native_agps_data_conn_failed();
|
||||
|
||||
private native void native_agps_ni_message(byte[] msg, int length);
|
||||
|
||||
private native void native_set_agps_server(int type, String hostname, int port);
|
||||
@@ -2783,15 +2368,12 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt
|
||||
// Network-initiated (NI) Support
|
||||
private native void native_send_ni_response(int notificationId, int userResponse);
|
||||
|
||||
// AGPS ril suport
|
||||
// AGPS ril support
|
||||
private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
|
||||
int lac, int cid);
|
||||
|
||||
private native void native_agps_set_id(int type, String setid);
|
||||
|
||||
private native void native_update_network_state(boolean connected, int type,
|
||||
boolean roaming, boolean available, String extraInfo, String defaultAPN);
|
||||
|
||||
// GNSS Configuration
|
||||
private static native boolean native_set_supl_version(int version);
|
||||
|
||||
|
||||
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.location;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.Network;
|
||||
import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkRequest;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Telephony.Carriers;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Handles network connection requests and network state change updates for AGPS data download.
|
||||
*/
|
||||
class GnssNetworkConnectivityHandler {
|
||||
static final String TAG = "GnssNetworkConnectivityHandler";
|
||||
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
// for mAGpsDataConnectionState
|
||||
private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
|
||||
private static final int AGPS_DATA_CONNECTION_OPENING = 1;
|
||||
private static final int AGPS_DATA_CONNECTION_OPEN = 2;
|
||||
|
||||
// these need to match AGnssStatusValue enum in IAGnssCallback.hal
|
||||
/** AGPS status event values. */
|
||||
private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
|
||||
private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
|
||||
private static final int GPS_AGPS_DATA_CONNECTED = 3;
|
||||
private static final int GPS_AGPS_DATA_CONN_DONE = 4;
|
||||
private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
|
||||
|
||||
// these must match the ApnIpType enum in IAGnss.hal
|
||||
private static final int APN_INVALID = 0;
|
||||
private static final int APN_IPV4 = 1;
|
||||
private static final int APN_IPV6 = 2;
|
||||
private static final int APN_IPV4V6 = 3;
|
||||
|
||||
// Default time limit in milliseconds for the ConnectivityManager to find a suitable
|
||||
// network with SUPL connectivity or report an error.
|
||||
private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 10 * 1000;
|
||||
|
||||
private static final int HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS = 5;
|
||||
|
||||
// keeps track of networks and their state as notified by the network request callbacks.
|
||||
// Limit initial capacity to 5 as the number of connected networks will likely be small.
|
||||
private ConcurrentHashMap<Network, NetworkAttributes> mAvailableNetworkAttributes =
|
||||
new ConcurrentHashMap<>(HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS);
|
||||
|
||||
private final ConnectivityManager mConnMgr;
|
||||
|
||||
private final Handler mHandler;
|
||||
private final GnssNetworkListener mGnssNetworkListener;
|
||||
|
||||
private int mAGpsDataConnectionState;
|
||||
private InetAddress mAGpsDataConnectionIpAddr;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
// Wakelocks
|
||||
private static final String WAKELOCK_KEY = "GnssNetworkConnectivityHandler";
|
||||
private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
|
||||
private final PowerManager.WakeLock mWakeLock;
|
||||
|
||||
/**
|
||||
* Network attributes needed when updating HAL about network connectivity status changes.
|
||||
*/
|
||||
private static class NetworkAttributes {
|
||||
NetworkCapabilities mCapabilities;
|
||||
String mApn;
|
||||
int mType = ConnectivityManager.TYPE_NONE;
|
||||
|
||||
/**
|
||||
* Returns true if the capabilities that we pass on to HAL change between {@curCapabilities}
|
||||
* and {@code newCapabilities}.
|
||||
*/
|
||||
static boolean hasCapabilitiesChanged(NetworkCapabilities curCapabilities,
|
||||
NetworkCapabilities newCapabilities) {
|
||||
if (curCapabilities == null || newCapabilities == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return curCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
|
||||
!= newCapabilities.hasCapability(
|
||||
NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback used to listen for data connectivity changes.
|
||||
*/
|
||||
private ConnectivityManager.NetworkCallback mNetworkConnectivityCallback;
|
||||
|
||||
/**
|
||||
* Callback used to listen for availability of a requested SUPL connection.
|
||||
* It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
|
||||
* manage the registration/un-registration lifetimes separately.
|
||||
*/
|
||||
private ConnectivityManager.NetworkCallback mSuplConnectivityCallback;
|
||||
|
||||
/**
|
||||
* Interface to listen for network availability changes.
|
||||
*/
|
||||
public interface GnssNetworkListener {
|
||||
void onNetworkAvailable();
|
||||
}
|
||||
|
||||
GnssNetworkConnectivityHandler(Context context,
|
||||
GnssNetworkListener gnssNetworkListener,
|
||||
Looper looper) {
|
||||
mContext = context;
|
||||
mGnssNetworkListener = gnssNetworkListener;
|
||||
|
||||
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
|
||||
|
||||
mHandler = new Handler(looper);
|
||||
mConnMgr = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
mSuplConnectivityCallback = createSuplConnectivityCallback();
|
||||
}
|
||||
|
||||
public void registerNetworkCallbacks() {
|
||||
mAvailableNetworkAttributes.clear();
|
||||
if (mNetworkConnectivityCallback != null) {
|
||||
mConnMgr.unregisterNetworkCallback(mNetworkConnectivityCallback);
|
||||
}
|
||||
|
||||
// register for connectivity change events.
|
||||
NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
|
||||
networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
|
||||
networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
|
||||
networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
|
||||
NetworkRequest networkRequest = networkRequestBuilder.build();
|
||||
mNetworkConnectivityCallback = createNetworkConnectivityCallback();
|
||||
mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if there is a data network available for outgoing connections,
|
||||
* {@code false} otherwise.
|
||||
*/
|
||||
public boolean isDataNetworkConnected() {
|
||||
NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
|
||||
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to update AGPS status
|
||||
*/
|
||||
public void onReportAGpsStatus(int type, int status, byte[] ipaddr) {
|
||||
switch (status) {
|
||||
case GPS_REQUEST_AGPS_DATA_CONN:
|
||||
if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
|
||||
Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
|
||||
InetAddress connectionIpAddress = null;
|
||||
if (ipaddr != null) {
|
||||
try {
|
||||
connectionIpAddress = InetAddress.getByAddress(ipaddr);
|
||||
if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
|
||||
} catch (UnknownHostException e) {
|
||||
Log.e(TAG, "Bad IP Address: " + ipaddr, e);
|
||||
}
|
||||
}
|
||||
requestSuplConnection(connectionIpAddress);
|
||||
break;
|
||||
case GPS_RELEASE_AGPS_DATA_CONN:
|
||||
if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
|
||||
releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
|
||||
break;
|
||||
case GPS_AGPS_DATA_CONNECTED:
|
||||
if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
|
||||
break;
|
||||
case GPS_AGPS_DATA_CONN_DONE:
|
||||
if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
|
||||
break;
|
||||
case GPS_AGPS_DATA_CONN_FAILED:
|
||||
if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
|
||||
break;
|
||||
default:
|
||||
if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
|
||||
}
|
||||
}
|
||||
|
||||
private ConnectivityManager.NetworkCallback createNetworkConnectivityCallback() {
|
||||
return new ConnectivityManager.NetworkCallback() {
|
||||
// Used to filter out network capabilities changes that we are not interested in.
|
||||
// NOTE: Not using a ConcurrentHashMap and also not using locking around updates
|
||||
// and access to the map object because it is all done inside the same
|
||||
// handler thread invoking the callback methods.
|
||||
private HashMap<Network, NetworkCapabilities>
|
||||
mAvailableNetworkCapabilities = new HashMap<>(
|
||||
HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS);
|
||||
|
||||
@Override
|
||||
public void onCapabilitiesChanged(Network network,
|
||||
NetworkCapabilities capabilities) {
|
||||
// This callback is invoked for any change in the network capabilities including
|
||||
// initial availability, and changes while still available. Only process if the
|
||||
// capabilities that we pass on to HAL change.
|
||||
if (!NetworkAttributes.hasCapabilitiesChanged(
|
||||
mAvailableNetworkCapabilities.get(network), capabilities)) {
|
||||
if (VERBOSE) {
|
||||
Log.v(TAG, "Relevant network capabilities unchanged. Capabilities: "
|
||||
+ capabilities);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
mAvailableNetworkCapabilities.put(network, capabilities);
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Network connected/capabilities updated. Available networks count: "
|
||||
+ mAvailableNetworkCapabilities.size());
|
||||
}
|
||||
|
||||
mGnssNetworkListener.onNetworkAvailable();
|
||||
|
||||
// Always on, notify HAL so it can get data it needs
|
||||
updateNetworkState(network, true, capabilities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
if (mAvailableNetworkCapabilities.remove(network) == null) {
|
||||
Log.w(TAG, "Incorrectly received network callback onLost() before"
|
||||
+ " onCapabilitiesChanged() for network: " + network);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(TAG, "Network connection lost. Available networks count: "
|
||||
+ mAvailableNetworkCapabilities.size());
|
||||
updateNetworkState(network, false, null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private ConnectivityManager.NetworkCallback createSuplConnectivityCallback() {
|
||||
return new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(Network network) {
|
||||
if (DEBUG) Log.d(TAG, "SUPL network connection available.");
|
||||
// Specific to a change to a SUPL enabled network becoming ready
|
||||
suplConnectionAvailable(network);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
Log.i(TAG, "SUPL network connection lost.");
|
||||
releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnavailable() {
|
||||
Log.i(TAG, "SUPL network connection request timed out.");
|
||||
// Could not setup the connection to the network in the specified time duration.
|
||||
releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void requestSuplConnection(InetAddress inetAddress) {
|
||||
postEvent(() -> handleRequestSuplConnection(inetAddress));
|
||||
}
|
||||
|
||||
private void suplConnectionAvailable(Network network) {
|
||||
postEvent(() -> handleSuplConnectionAvailable(network));
|
||||
}
|
||||
|
||||
private void releaseSuplConnection(int connStatus) {
|
||||
postEvent(() -> handleReleaseSuplConnection(connStatus));
|
||||
}
|
||||
|
||||
private void updateNetworkState(Network network, boolean isConnected,
|
||||
NetworkCapabilities capabilities) {
|
||||
postEvent(() -> handleUpdateNetworkState(network, isConnected, capabilities));
|
||||
}
|
||||
|
||||
private void postEvent(Runnable event) {
|
||||
// hold a wake lock until this message is delivered
|
||||
// note that this assumes the message will not be removed from the queue before
|
||||
// it is handled (otherwise the wake lock would be leaked).
|
||||
mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
|
||||
if (!mHandler.post(runEventAndReleaseWakeLock(event))) {
|
||||
mWakeLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable runEventAndReleaseWakeLock(Runnable event) {
|
||||
return () -> {
|
||||
try {
|
||||
event.run();
|
||||
} finally {
|
||||
mWakeLock.release();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void handleUpdateNetworkState(Network network, boolean isConnected,
|
||||
NetworkCapabilities capabilities) {
|
||||
boolean networkAvailable = isConnected && TelephonyManager.getDefault().getDataEnabled();
|
||||
NetworkAttributes networkAttributes = updateTrackedNetworksState(isConnected, network,
|
||||
capabilities);
|
||||
String apnName = networkAttributes.mApn;
|
||||
int type = networkAttributes.mType;
|
||||
// When isConnected is false, capabilities argument is null. So, use last received
|
||||
// capabilities.
|
||||
capabilities = networkAttributes.mCapabilities;
|
||||
boolean isRoaming = !capabilities.hasTransport(
|
||||
NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
|
||||
|
||||
Log.i(TAG, String.format(
|
||||
"updateNetworkState, state=%s, connected=%s, network=%s, capabilities=%s"
|
||||
+ ", availableNetworkCount: %d",
|
||||
agpsDataConnStateAsString(),
|
||||
isConnected,
|
||||
network,
|
||||
capabilities,
|
||||
mAvailableNetworkAttributes.size()));
|
||||
|
||||
if (native_is_agps_ril_supported()) {
|
||||
String defaultApn = getSelectedApn();
|
||||
if (defaultApn == null) {
|
||||
defaultApn = "dummy-apn";
|
||||
}
|
||||
|
||||
native_update_network_state(
|
||||
isConnected,
|
||||
type,
|
||||
isRoaming,
|
||||
networkAvailable,
|
||||
apnName,
|
||||
defaultApn);
|
||||
} else if (DEBUG) {
|
||||
Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
private NetworkAttributes updateTrackedNetworksState(boolean isConnected, Network network,
|
||||
NetworkCapabilities capabilities) {
|
||||
if (!isConnected) {
|
||||
// Connection lost event. So, remove it from tracked networks.
|
||||
return mAvailableNetworkAttributes.remove(network);
|
||||
}
|
||||
|
||||
NetworkAttributes networkAttributes = mAvailableNetworkAttributes.get(network);
|
||||
if (networkAttributes != null) {
|
||||
// Capabilities updated event for the connected network.
|
||||
networkAttributes.mCapabilities = capabilities;
|
||||
return networkAttributes;
|
||||
}
|
||||
|
||||
// Initial capabilities event (equivalent to connection available event).
|
||||
networkAttributes = new NetworkAttributes();
|
||||
networkAttributes.mCapabilities = capabilities;
|
||||
|
||||
// TODO(b/119278134): The synchronous method ConnectivityManager.getNetworkInfo() must
|
||||
// not be called inside the asynchronous ConnectivityManager.NetworkCallback methods.
|
||||
NetworkInfo info = mConnMgr.getNetworkInfo(network);
|
||||
if (info != null) {
|
||||
networkAttributes.mApn = info.getExtraInfo();
|
||||
networkAttributes.mType = info.getType();
|
||||
}
|
||||
|
||||
// Start tracking this network for connection status updates.
|
||||
mAvailableNetworkAttributes.put(network, networkAttributes);
|
||||
return networkAttributes;
|
||||
}
|
||||
|
||||
private void handleSuplConnectionAvailable(Network network) {
|
||||
// TODO(b/119278134): The synchronous method ConnectivityManager.getNetworkInfo() must
|
||||
// not be called inside the asynchronous ConnectivityManager.NetworkCallback methods.
|
||||
NetworkInfo info = mConnMgr.getNetworkInfo(network);
|
||||
String apnName = null;
|
||||
if (info != null) {
|
||||
apnName = info.getExtraInfo();
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
String message = String.format(
|
||||
"handleSuplConnectionAvailable: state=%s, suplNetwork=%s, info=%s",
|
||||
agpsDataConnStateAsString(),
|
||||
network,
|
||||
info);
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
|
||||
if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
|
||||
if (apnName == null) {
|
||||
// assign a dummy value in the case of C2K as otherwise we will have a runtime
|
||||
// exception in the following call to native_agps_data_conn_open
|
||||
apnName = "dummy-apn";
|
||||
}
|
||||
int apnIpType = getApnIpType(apnName);
|
||||
setRouting();
|
||||
if (DEBUG) {
|
||||
String message = String.format(
|
||||
"native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
|
||||
apnName,
|
||||
apnIpType);
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
native_agps_data_conn_open(apnName, apnIpType);
|
||||
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRequestSuplConnection(InetAddress address) {
|
||||
if (DEBUG) {
|
||||
String message = String.format(
|
||||
"requestSuplConnection, state=%s, address=%s",
|
||||
agpsDataConnStateAsString(),
|
||||
address);
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
|
||||
if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
|
||||
return;
|
||||
}
|
||||
mAGpsDataConnectionIpAddr = address;
|
||||
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
|
||||
|
||||
NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
|
||||
requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
|
||||
requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
|
||||
NetworkRequest request = requestBuilder.build();
|
||||
mConnMgr.requestNetwork(
|
||||
request,
|
||||
mSuplConnectivityCallback,
|
||||
SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
|
||||
}
|
||||
|
||||
private void handleReleaseSuplConnection(int agpsDataConnStatus) {
|
||||
if (DEBUG) {
|
||||
String message = String.format(
|
||||
"releaseSuplConnection, state=%s, status=%s",
|
||||
agpsDataConnStateAsString(),
|
||||
agpsDataConnStatusAsString(agpsDataConnStatus));
|
||||
Log.d(TAG, message);
|
||||
}
|
||||
|
||||
if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
|
||||
return;
|
||||
}
|
||||
mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
|
||||
|
||||
mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
|
||||
switch (agpsDataConnStatus) {
|
||||
case GPS_AGPS_DATA_CONN_FAILED:
|
||||
native_agps_data_conn_failed();
|
||||
break;
|
||||
case GPS_RELEASE_AGPS_DATA_CONN:
|
||||
native_agps_data_conn_closed();
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private void setRouting() {
|
||||
if (mAGpsDataConnectionIpAddr == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(25876485): replace the use of this deprecated API
|
||||
boolean result = mConnMgr.requestRouteToHostAddress(
|
||||
ConnectivityManager.TYPE_MOBILE_SUPL,
|
||||
mAGpsDataConnectionIpAddr);
|
||||
|
||||
if (!result) {
|
||||
Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
|
||||
} else if (DEBUG) {
|
||||
Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the calling function is running in the thread associated with {@link #mHandler}.
|
||||
*/
|
||||
private void ensureInHandlerThread() {
|
||||
if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("This method must run on the Handler thread.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
|
||||
*/
|
||||
private String agpsDataConnStateAsString() {
|
||||
switch (mAGpsDataConnectionState) {
|
||||
case AGPS_DATA_CONNECTION_CLOSED:
|
||||
return "CLOSED";
|
||||
case AGPS_DATA_CONNECTION_OPEN:
|
||||
return "OPEN";
|
||||
case AGPS_DATA_CONNECTION_OPENING:
|
||||
return "OPENING";
|
||||
default:
|
||||
return "<Unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A string representing the given GPS_AGPS_DATA status.
|
||||
*/
|
||||
private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
|
||||
switch (agpsDataConnStatus) {
|
||||
case GPS_AGPS_DATA_CONNECTED:
|
||||
return "CONNECTED";
|
||||
case GPS_AGPS_DATA_CONN_DONE:
|
||||
return "DONE";
|
||||
case GPS_AGPS_DATA_CONN_FAILED:
|
||||
return "FAILED";
|
||||
case GPS_RELEASE_AGPS_DATA_CONN:
|
||||
return "RELEASE";
|
||||
case GPS_REQUEST_AGPS_DATA_CONN:
|
||||
return "REQUEST";
|
||||
default:
|
||||
return "<Unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
private int getApnIpType(String apn) {
|
||||
ensureInHandlerThread();
|
||||
if (apn == null) {
|
||||
return APN_INVALID;
|
||||
}
|
||||
TelephonyManager phone = (TelephonyManager)
|
||||
mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
// Carrier configuration may override framework roaming state, we need to use the actual
|
||||
// modem roaming state instead of the framework roaming state.
|
||||
boolean isDataRoamingFromRegistration = phone.getServiceState()
|
||||
.getDataRoamingFromRegistration();
|
||||
String projection = isDataRoamingFromRegistration ? Carriers.ROAMING_PROTOCOL :
|
||||
Carriers.PROTOCOL;
|
||||
String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
|
||||
try (Cursor cursor = mContext.getContentResolver().query(
|
||||
Carriers.CONTENT_URI,
|
||||
new String[]{projection},
|
||||
selection,
|
||||
null,
|
||||
Carriers.DEFAULT_SORT_ORDER)) {
|
||||
if (null != cursor && cursor.moveToFirst()) {
|
||||
return translateToApnIpType(cursor.getString(0), apn);
|
||||
} else {
|
||||
Log.e(TAG, "No entry found in query for APN: " + apn);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error encountered on APN query for: " + apn, e);
|
||||
}
|
||||
|
||||
return APN_INVALID;
|
||||
}
|
||||
|
||||
private int translateToApnIpType(String ipProtocol, String apn) {
|
||||
if ("IP".equals(ipProtocol)) {
|
||||
return APN_IPV4;
|
||||
}
|
||||
if ("IPV6".equals(ipProtocol)) {
|
||||
return APN_IPV6;
|
||||
}
|
||||
if ("IPV4V6".equals(ipProtocol)) {
|
||||
return APN_IPV4V6;
|
||||
}
|
||||
|
||||
// we hit the default case so the ipProtocol is not recognized
|
||||
String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
|
||||
Log.e(TAG, message);
|
||||
return APN_INVALID;
|
||||
}
|
||||
|
||||
private String getSelectedApn() {
|
||||
Uri uri = Uri.parse("content://telephony/carriers/preferapn");
|
||||
try (Cursor cursor = mContext.getContentResolver().query(
|
||||
uri,
|
||||
new String[]{"apn"},
|
||||
null /* selection */,
|
||||
null /* selectionArgs */,
|
||||
Carriers.DEFAULT_SORT_ORDER)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getString(0);
|
||||
} else {
|
||||
Log.e(TAG, "No APN found to select.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error encountered on selecting the APN.", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// AGPS support
|
||||
private native void native_agps_data_conn_open(String apn, int apnIpType);
|
||||
|
||||
private native void native_agps_data_conn_closed();
|
||||
|
||||
private native void native_agps_data_conn_failed();
|
||||
|
||||
// AGPS ril support
|
||||
private static native boolean native_is_agps_ril_supported();
|
||||
|
||||
private native void native_update_network_state(boolean connected, int type,
|
||||
boolean roaming, boolean available, String extraInfo, String defaultAPN);
|
||||
}
|
||||
@@ -1299,7 +1299,7 @@ static jboolean android_location_GnssLocationProvider_is_supported(
|
||||
return (gnssHal != nullptr) ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
static jboolean android_location_GnssLocationProvider_is_agps_ril_supported(
|
||||
static jboolean android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported(
|
||||
JNIEnv* /* env */, jclass /* clazz */) {
|
||||
return (agnssRilIface != nullptr) ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
@@ -1571,7 +1571,7 @@ static void android_location_GnssLocationProvider_inject_xtra_data(JNIEnv* env,
|
||||
env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
|
||||
}
|
||||
|
||||
static void android_location_GnssLocationProvider_agps_data_conn_open(
|
||||
static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_open(
|
||||
JNIEnv* env, jobject /* obj */, jstring apn, jint apnIpType) {
|
||||
if (agnssIface == nullptr) {
|
||||
ALOGE("no AGPS interface in agps_data_conn_open");
|
||||
@@ -1591,7 +1591,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_open(
|
||||
env->ReleaseStringUTFChars(apn, apnStr);
|
||||
}
|
||||
|
||||
static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv* /* env */,
|
||||
static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed(JNIEnv* /* env */,
|
||||
jobject /* obj */) {
|
||||
if (agnssIface == nullptr) {
|
||||
ALOGE("%s: AGPS interface not supported", __func__);
|
||||
@@ -1604,7 +1604,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv*
|
||||
}
|
||||
}
|
||||
|
||||
static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv* /* env */,
|
||||
static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed(JNIEnv* /* env */,
|
||||
jobject /* obj */) {
|
||||
if (agnssIface == nullptr) {
|
||||
ALOGE("%s: AGPS interface not supported", __func__);
|
||||
@@ -1718,7 +1718,7 @@ static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv*
|
||||
return result;
|
||||
}
|
||||
|
||||
static void android_location_GnssLocationProvider_update_network_state(JNIEnv* env,
|
||||
static void android_location_GnssNetworkConnectivityHandler_update_network_state(JNIEnv* env,
|
||||
jobject /* obj */,
|
||||
jboolean connected,
|
||||
jint type,
|
||||
@@ -2118,8 +2118,6 @@ static const JNINativeMethod sMethods[] = {
|
||||
android_location_GnssLocationProvider_class_init_native)},
|
||||
{"native_is_supported", "()Z", reinterpret_cast<void *>(
|
||||
android_location_GnssLocationProvider_is_supported)},
|
||||
{"native_is_agps_ril_supported", "()Z",
|
||||
reinterpret_cast<void *>(android_location_GnssLocationProvider_is_agps_ril_supported)},
|
||||
{"native_is_gnss_configuration_supported", "()Z",
|
||||
reinterpret_cast<void *>(
|
||||
android_location_gpsLocationProvider_is_gnss_configuration_supported)},
|
||||
@@ -2151,15 +2149,6 @@ static const JNINativeMethod sMethods[] = {
|
||||
{"native_inject_xtra_data",
|
||||
"([BI)V",
|
||||
reinterpret_cast<void *>(android_location_GnssLocationProvider_inject_xtra_data)},
|
||||
{"native_agps_data_conn_open",
|
||||
"(Ljava/lang/String;I)V",
|
||||
reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_data_conn_open)},
|
||||
{"native_agps_data_conn_closed",
|
||||
"()V",
|
||||
reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_data_conn_closed)},
|
||||
{"native_agps_data_conn_failed",
|
||||
"()V",
|
||||
reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_data_conn_failed)},
|
||||
{"native_agps_set_id",
|
||||
"(ILjava/lang/String;)V",
|
||||
reinterpret_cast<void *>(android_location_GnssLocationProvider_agps_set_id)},
|
||||
@@ -2176,9 +2165,6 @@ static const JNINativeMethod sMethods[] = {
|
||||
{"native_get_internal_state",
|
||||
"()Ljava/lang/String;",
|
||||
reinterpret_cast<void *>(android_location_GnssLocationProvider_get_internal_state)},
|
||||
{"native_update_network_state",
|
||||
"(ZIZZLjava/lang/String;Ljava/lang/String;)V",
|
||||
reinterpret_cast<void *>(android_location_GnssLocationProvider_update_network_state)},
|
||||
{"native_set_supl_es",
|
||||
"(I)Z",
|
||||
reinterpret_cast<void *>(android_location_GnssLocationProvider_set_supl_es)},
|
||||
@@ -2278,6 +2264,24 @@ static const JNINativeMethod sNavigationMessageMethods[] = {
|
||||
android_location_GnssNavigationMessageProvider_stop_navigation_message_collection)},
|
||||
};
|
||||
|
||||
static const JNINativeMethod sNetworkConnectivityMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{"native_is_agps_ril_supported", "()Z",
|
||||
reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported)},
|
||||
{"native_update_network_state",
|
||||
"(ZIZZLjava/lang/String;Ljava/lang/String;)V",
|
||||
reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_update_network_state)},
|
||||
{"native_agps_data_conn_open",
|
||||
"(Ljava/lang/String;I)V",
|
||||
reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_open)},
|
||||
{"native_agps_data_conn_closed",
|
||||
"()V",
|
||||
reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed)},
|
||||
{"native_agps_data_conn_failed",
|
||||
"()V",
|
||||
reinterpret_cast<void *>(android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)},
|
||||
};
|
||||
|
||||
int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
|
||||
jniRegisterNativeMethods(
|
||||
env,
|
||||
@@ -2299,6 +2303,11 @@ int register_android_server_location_GnssLocationProvider(JNIEnv* env) {
|
||||
"com/android/server/location/GnssNavigationMessageProvider",
|
||||
sNavigationMessageMethods,
|
||||
NELEM(sNavigationMessageMethods));
|
||||
jniRegisterNativeMethods(
|
||||
env,
|
||||
"com/android/server/location/GnssNetworkConnectivityHandler",
|
||||
sNetworkConnectivityMethods,
|
||||
NELEM(sNetworkConnectivityMethods));
|
||||
return jniRegisterNativeMethods(
|
||||
env,
|
||||
"com/android/server/location/GnssLocationProvider",
|
||||
|
||||
Reference in New Issue
Block a user