From 50ba15e520af88016ea770261c41073794cc6e6b Mon Sep 17 00:00:00 2001 From: Anil Admal Date: Thu, 1 Nov 2018 16:42:42 -0700 Subject: GNSS HAL must be notified correctly when networks disconnect When a network connection is lost, we cannot reliably get the network connection status information from the method ConnectivityManager.getNetworkInfo(). Sometimes, it returns null and other times it returns network information with incorrect connection status. It is a synchronous method and should not be called from within an async NetworkCallback class method such as onLost(). The GnssLocationProvider class should be modified to maintain the network type and other information of all connected networks reported to GNSS HAL and provide that information to GNSS HAL when a network disconnects so that the GNSS HAL knows which network actually disconnected. The impact of this bug is noted in b/110186412 and b/93175534. Fixes: 110186412 Fixes: 93175534 Test: On a Pixel device, tested XTRA/SUPL download in the following cases: WiFi/Cell OFF on boot 1. WiFi ON only - WiFi ON, Cell ON, Cell OFF 2. Cell ON only - WiFi ON, Cell ON, WiFi OFF 3. Both WiFi/Cell ON - WiFi ON, Cell ON 4. Both WiFi/Cell ON - WiFi ON, Cell ON, Cell OFF, Cell ON 4. Both WiFi/Cell ON - WiFi ON, Cell ON, WiFi OFF, WiFi ON 6. Both WiFi/Cell OFF - WiFi ON, Cell ON, Cell OFF, WiFi OFF 7. And few other sequences. Repeated similar test sequences with WiFi ON and Cell OFF on boot and with WiFi oFF and Cell ON boot. Reviewed the GNSS Framework/HAL log messages to confirm correct connect/disconnect notification to HAL. Observed issue noted in b/64816395. Change-Id: I0db44108b195c6d5c75f8247fe1796951d546e56 --- .../server/location/GnssLocationProvider.java | 458 +-------------- .../location/GnssNetworkConnectivityHandler.java | 631 +++++++++++++++++++++ ...ndroid_server_location_GnssLocationProvider.cpp | 47 +- 3 files changed, 679 insertions(+), 457 deletions(-) create mode 100644 services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java 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 ""; - } - } - - /** - * @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 ""; - } - } - /** * @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 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 + 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 ""; + } + } + + /** + * @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 ""; + } + } + + 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 b47dbfa58669..071d4d452ddc 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -1301,7 +1301,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; } @@ -1573,7 +1573,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"); @@ -1593,7 +1593,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__); @@ -1606,7 +1606,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__); @@ -1720,7 +1720,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, @@ -2120,8 +2120,6 @@ static const JNINativeMethod sMethods[] = { android_location_GnssLocationProvider_class_init_native)}, {"native_is_supported", "()Z", reinterpret_cast( android_location_GnssLocationProvider_is_supported)}, - {"native_is_agps_ril_supported", "()Z", - reinterpret_cast(android_location_GnssLocationProvider_is_agps_ril_supported)}, {"native_is_gnss_configuration_supported", "()Z", reinterpret_cast( android_location_gpsLocationProvider_is_gnss_configuration_supported)}, @@ -2153,15 +2151,6 @@ static const JNINativeMethod sMethods[] = { {"native_inject_xtra_data", "([BI)V", reinterpret_cast(android_location_GnssLocationProvider_inject_xtra_data)}, - {"native_agps_data_conn_open", - "(Ljava/lang/String;I)V", - reinterpret_cast(android_location_GnssLocationProvider_agps_data_conn_open)}, - {"native_agps_data_conn_closed", - "()V", - reinterpret_cast(android_location_GnssLocationProvider_agps_data_conn_closed)}, - {"native_agps_data_conn_failed", - "()V", - reinterpret_cast(android_location_GnssLocationProvider_agps_data_conn_failed)}, {"native_agps_set_id", "(ILjava/lang/String;)V", reinterpret_cast(android_location_GnssLocationProvider_agps_set_id)}, @@ -2178,9 +2167,6 @@ static const JNINativeMethod sMethods[] = { {"native_get_internal_state", "()Ljava/lang/String;", reinterpret_cast(android_location_GnssLocationProvider_get_internal_state)}, - {"native_update_network_state", - "(ZIZZLjava/lang/String;Ljava/lang/String;)V", - reinterpret_cast(android_location_GnssLocationProvider_update_network_state)}, {"native_set_supl_es", "(I)Z", reinterpret_cast(android_location_GnssLocationProvider_set_supl_es)}, @@ -2280,6 +2266,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(android_location_GnssNetworkConnectivityHandler_is_agps_ril_supported)}, + {"native_update_network_state", + "(ZIZZLjava/lang/String;Ljava/lang/String;)V", + reinterpret_cast(android_location_GnssNetworkConnectivityHandler_update_network_state)}, + {"native_agps_data_conn_open", + "(Ljava/lang/String;I)V", + reinterpret_cast(android_location_GnssNetworkConnectivityHandler_agps_data_conn_open)}, + {"native_agps_data_conn_closed", + "()V", + reinterpret_cast(android_location_GnssNetworkConnectivityHandler_agps_data_conn_closed)}, + {"native_agps_data_conn_failed", + "()V", + reinterpret_cast(android_location_GnssNetworkConnectivityHandler_agps_data_conn_failed)}, +}; + int register_android_server_location_GnssLocationProvider(JNIEnv* env) { jniRegisterNativeMethods( env, @@ -2301,6 +2305,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", -- cgit v1.2.3-59-g8ed1b