summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Anil Admal <aadmal@google.com> 2018-11-12 17:05:29 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-11-12 17:05:29 +0000
commitaff67bc4a1687f582c32876ce618b14844c8b680 (patch)
tree372c35eef54818c06d71c15db89f9f98e2c03f55
parentb2eb6bd683022f2bab48eaaebdf1afc19dd35681 (diff)
parent50ba15e520af88016ea770261c41073794cc6e6b (diff)
Merge "GNSS HAL must be notified correctly when networks disconnect"
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java458
-rw-r--r--services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java631
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp47
3 files changed, 679 insertions, 457 deletions
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 53d54ba11e99..f0745731ffeb 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -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,127 +786,20 @@ 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";
- }
-
- 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);
+ /**
+ * 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();
}
}
}
- 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 handleRequestLocation(boolean independentFromGnss) {
if (isRequestLocationRateLimited()) {
if (DEBUG) {
@@ -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);
diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
new file mode 100644
index 000000000000..b211948f73cf
--- /dev/null
+++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
@@ -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);
+}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index a4983a96afd8..92160053804d 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -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",