1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.location.gnss; 18 19 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; 20 21 import android.annotation.RequiresPermission; 22 import android.content.Context; 23 import android.location.flags.Flags; 24 import android.net.ConnectivityManager; 25 import android.net.LinkAddress; 26 import android.net.LinkProperties; 27 import android.net.Network; 28 import android.net.NetworkCapabilities; 29 import android.net.NetworkInfo; 30 import android.net.NetworkRequest; 31 import android.os.Handler; 32 import android.os.Looper; 33 import android.os.PowerManager; 34 import android.telephony.PhoneStateListener; 35 import android.telephony.PreciseCallState; 36 import android.telephony.ServiceState; 37 import android.telephony.SubscriptionInfo; 38 import android.telephony.SubscriptionManager; 39 import android.telephony.TelephonyManager; 40 import android.util.Log; 41 42 import com.android.internal.location.GpsNetInitiatedHandler; 43 import com.android.server.FgThread; 44 45 import java.net.Inet4Address; 46 import java.net.Inet6Address; 47 import java.net.InetAddress; 48 import java.net.UnknownHostException; 49 import java.util.Arrays; 50 import java.util.HashMap; 51 import java.util.HashSet; 52 import java.util.Iterator; 53 import java.util.List; 54 import java.util.Map; 55 import java.util.concurrent.TimeUnit; 56 57 /** 58 * Handles network connection requests and network state change updates for AGPS data download. 59 */ 60 class GnssNetworkConnectivityHandler { 61 static final String TAG = "GnssNetworkConnectivityHandler"; 62 63 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 64 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 65 66 // for mAGpsDataConnectionState 67 private static final int AGPS_DATA_CONNECTION_CLOSED = 0; 68 private static final int AGPS_DATA_CONNECTION_OPENING = 1; 69 private static final int AGPS_DATA_CONNECTION_OPEN = 2; 70 71 // these need to match AGnssStatusValue enum in IAGnssCallback.hal 72 /** AGPS status event values. */ 73 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1; 74 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2; 75 private static final int GPS_AGPS_DATA_CONNECTED = 3; 76 private static final int GPS_AGPS_DATA_CONN_DONE = 4; 77 private static final int GPS_AGPS_DATA_CONN_FAILED = 5; 78 79 // these must match the ApnIpType enum in IAGnss.hal 80 private static final int APN_INVALID = 0; 81 private static final int APN_IPV4 = 1; 82 private static final int APN_IPV6 = 2; 83 private static final int APN_IPV4V6 = 3; 84 85 // these must match the NetworkCapability enum flags in IAGnssRil.hal 86 private static final int AGNSS_NET_CAPABILITY_NOT_METERED = 1 << 0; 87 private static final int AGNSS_NET_CAPABILITY_NOT_ROAMING = 1 << 1; 88 89 // these need to match AGnssType enum in IAGnssCallback.hal 90 public static final int AGPS_TYPE_SUPL = 1; 91 public static final int AGPS_TYPE_C2K = 2; 92 private static final int AGPS_TYPE_EIMS = 3; 93 private static final int AGPS_TYPE_IMS = 4; 94 95 // Default time limit in milliseconds for the ConnectivityManager to find a suitable 96 // network with SUPL connectivity or report an error. 97 private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 20 * 1000; 98 99 // If the chipset does not request to release a SUPL connection before the specified timeout in 100 // milliseconds, the connection will be automatically released. 101 private static final long SUPL_CONNECTION_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(1); 102 103 private static final int HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS = 5; 104 105 // Keeps track of networks and their state as notified by the network request callbacks. 106 // Limit initial capacity to 5 as the number of connected networks will likely be small. 107 // NOTE: Must be accessed/modified only through the mHandler thread. 108 private HashMap<Network, NetworkAttributes> mAvailableNetworkAttributes = 109 new HashMap<>(HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS); 110 111 // Phone State Listeners to track all the active sub IDs 112 private HashMap<Integer, SubIdPhoneStateListener> mPhoneStateListeners; 113 114 private final ConnectivityManager mConnMgr; 115 116 private final Handler mHandler; 117 private final GnssNetworkListener mGnssNetworkListener; 118 119 private int mAGpsDataConnectionState; 120 private InetAddress mAGpsDataConnectionIpAddr; 121 private int mAGpsType; 122 private int mActiveSubId = -1; 123 private final GpsNetInitiatedHandler mNiHandler; 124 125 126 private final Context mContext; 127 128 // Wakelocks 129 private static final String WAKELOCK_KEY = "GnssNetworkConnectivityHandler"; 130 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000; 131 private final PowerManager.WakeLock mWakeLock; 132 133 private final Object mSuplConnectionReleaseOnTimeoutToken = new Object(); 134 135 /** 136 * Network attributes needed when updating HAL about network connectivity status changes. 137 */ 138 private static class NetworkAttributes { 139 private NetworkCapabilities mCapabilities; 140 private String mApn; 141 private int mType = ConnectivityManager.TYPE_NONE; 142 143 /** 144 * Returns true if the capabilities that we pass on to HAL change between {@curCapabilities} 145 * and {@code newCapabilities}. 146 */ hasCapabilitiesChanged(NetworkCapabilities curCapabilities, NetworkCapabilities newCapabilities)147 private static boolean hasCapabilitiesChanged(NetworkCapabilities curCapabilities, 148 NetworkCapabilities newCapabilities) { 149 if (curCapabilities == null || newCapabilities == null) { 150 return true; 151 } 152 153 // Monitor for roaming and metered capability changes. 154 return hasCapabilityChanged(curCapabilities, newCapabilities, 155 NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) 156 || hasCapabilityChanged(curCapabilities, newCapabilities, 157 NetworkCapabilities.NET_CAPABILITY_NOT_METERED); 158 } 159 hasCapabilityChanged(NetworkCapabilities curCapabilities, NetworkCapabilities newCapabilities, int capability)160 private static boolean hasCapabilityChanged(NetworkCapabilities curCapabilities, 161 NetworkCapabilities newCapabilities, int capability) { 162 return curCapabilities.hasCapability(capability) 163 != newCapabilities.hasCapability(capability); 164 } 165 getCapabilityFlags(NetworkCapabilities capabilities)166 private static short getCapabilityFlags(NetworkCapabilities capabilities) { 167 short capabilityFlags = 0; 168 if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) { 169 capabilityFlags |= AGNSS_NET_CAPABILITY_NOT_ROAMING; 170 } 171 if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) { 172 capabilityFlags |= AGNSS_NET_CAPABILITY_NOT_METERED; 173 } 174 return capabilityFlags; 175 } 176 } 177 178 /** 179 * Callback used to listen for data connectivity changes. 180 */ 181 private ConnectivityManager.NetworkCallback mNetworkConnectivityCallback; 182 183 /** 184 * Callback used to listen for availability of a requested SUPL connection. 185 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to 186 * manage the registration/un-registration lifetimes separately. 187 */ 188 private ConnectivityManager.NetworkCallback mSuplConnectivityCallback; 189 190 /** 191 * Interface to listen for network availability changes. 192 */ 193 interface GnssNetworkListener { onNetworkAvailable()194 void onNetworkAvailable(); 195 } 196 GnssNetworkConnectivityHandler(Context context, GnssNetworkListener gnssNetworkListener, Looper looper, GpsNetInitiatedHandler niHandler)197 GnssNetworkConnectivityHandler(Context context, 198 GnssNetworkListener gnssNetworkListener, 199 Looper looper, 200 GpsNetInitiatedHandler niHandler) { 201 mContext = context; 202 mGnssNetworkListener = gnssNetworkListener; 203 204 SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class); 205 if (subManager != null) { 206 if (Flags.subscriptionsChangedListenerThread()) { 207 subManager.addOnSubscriptionsChangedListener(FgThread.getExecutor(), 208 mOnSubscriptionsChangeListener); 209 } else { 210 subManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener); 211 } 212 } 213 214 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 215 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 216 217 mHandler = new Handler(looper); 218 mNiHandler = niHandler; 219 mConnMgr = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 220 mSuplConnectivityCallback = null; 221 } 222 223 /** 224 * SubId Phone State Listener is used cache the last active Sub ID when a call is made, 225 * which will be used during an emergency call to set the Network Specifier to the particular 226 * sub when an emergency supl connection is requested 227 */ 228 private final class SubIdPhoneStateListener extends PhoneStateListener { 229 private Integer mSubId; SubIdPhoneStateListener(Integer subId)230 SubIdPhoneStateListener(Integer subId) { 231 mSubId = subId; 232 } 233 @Override onPreciseCallStateChanged(PreciseCallState state)234 public void onPreciseCallStateChanged(PreciseCallState state) { 235 if (PreciseCallState.PRECISE_CALL_STATE_ACTIVE == state.getForegroundCallState() 236 || PreciseCallState.PRECISE_CALL_STATE_DIALING 237 == state.getForegroundCallState()) { 238 mActiveSubId = mSubId; 239 if (DEBUG) Log.d(TAG, "mActiveSubId: " + mActiveSubId); 240 } 241 } 242 }; 243 244 /** 245 * Subscription Changed Listener is used to get all active subscriptions and create a 246 * Phone State Listener for each Sub ID that we find in the active subscription list 247 */ 248 private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener 249 = new SubscriptionManager.OnSubscriptionsChangedListener() { 250 @Override 251 public void onSubscriptionsChanged() { 252 if (mPhoneStateListeners == null) { 253 // Capacity=2 Load-Factor=1.0, as typically no more than 2 SIMs 254 mPhoneStateListeners = new HashMap<Integer, SubIdPhoneStateListener>(2,1); 255 } 256 SubscriptionManager subManager = mContext.getSystemService(SubscriptionManager.class); 257 TelephonyManager telManager = mContext.getSystemService(TelephonyManager.class); 258 if (subManager != null && telManager != null) { 259 subManager = subManager.createForAllUserProfiles(); 260 List<SubscriptionInfo> subscriptionInfoList = 261 subManager.getActiveSubscriptionInfoList(); 262 HashSet<Integer> activeSubIds = new HashSet<Integer>(); 263 if (subscriptionInfoList != null) { 264 if (DEBUG) Log.d(TAG, "Active Sub List size: " + subscriptionInfoList.size()); 265 // populate phone state listeners with all new active subs 266 for (SubscriptionInfo subInfo : subscriptionInfoList) { 267 activeSubIds.add(subInfo.getSubscriptionId()); 268 if (!mPhoneStateListeners.containsKey(subInfo.getSubscriptionId())) { 269 TelephonyManager subIdTelManager = 270 telManager.createForSubscriptionId(subInfo.getSubscriptionId()); 271 if (subIdTelManager != null) { 272 if (DEBUG) Log.d(TAG, "Listener sub" + subInfo.getSubscriptionId()); 273 SubIdPhoneStateListener subIdPhoneStateListener = 274 new SubIdPhoneStateListener(subInfo.getSubscriptionId()); 275 mPhoneStateListeners.put(subInfo.getSubscriptionId(), 276 subIdPhoneStateListener); 277 subIdTelManager.listen(subIdPhoneStateListener, 278 PhoneStateListener.LISTEN_PRECISE_CALL_STATE); 279 } 280 } 281 } 282 } 283 // clean up phone state listeners than no longer have active subs 284 Iterator<Map.Entry<Integer, SubIdPhoneStateListener> > iterator = 285 mPhoneStateListeners.entrySet().iterator(); 286 while (iterator.hasNext()) { 287 Map.Entry<Integer, SubIdPhoneStateListener> element = iterator.next(); 288 if (!activeSubIds.contains(element.getKey())) { 289 TelephonyManager subIdTelManager = 290 telManager.createForSubscriptionId(element.getKey()); 291 if (subIdTelManager != null) { 292 if (DEBUG) Log.d(TAG, "unregister listener sub " + element.getKey()); 293 subIdTelManager.listen(element.getValue(), 294 PhoneStateListener.LISTEN_NONE); 295 // removes the element from mPhoneStateListeners 296 iterator.remove(); 297 } else { 298 Log.e(TAG, "Telephony Manager for Sub " + element.getKey() + " null"); 299 } 300 } 301 } 302 // clean up cached active phone call sub if it is no longer an active sub 303 if (!activeSubIds.contains(mActiveSubId)) { 304 mActiveSubId = -1; 305 } 306 } 307 } 308 }; 309 registerNetworkCallbacks()310 void registerNetworkCallbacks() { 311 // register for connectivity change events. 312 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); 313 networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 314 networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); 315 networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); 316 NetworkRequest networkRequest = networkRequestBuilder.build(); 317 mNetworkConnectivityCallback = createNetworkConnectivityCallback(); 318 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback, mHandler); 319 } 320 unregisterNetworkCallbacks()321 void unregisterNetworkCallbacks() { 322 mConnMgr.unregisterNetworkCallback(mNetworkConnectivityCallback); 323 mNetworkConnectivityCallback = null; 324 } 325 326 /** 327 * @return {@code true} if there is a data network available for outgoing connections, 328 * {@code false} otherwise. 329 */ isDataNetworkConnected()330 boolean isDataNetworkConnected() { 331 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo(); 332 return activeNetworkInfo != null && activeNetworkInfo.isConnected(); 333 } 334 335 /** 336 * Returns the active Sub ID for emergency SUPL connection. 337 */ getActiveSubId()338 int getActiveSubId() { 339 return mActiveSubId; 340 } 341 342 /** 343 * Called from native code to update AGPS connection status, or to request or release a SUPL 344 * connection. 345 * 346 * <p>Note: {@code suplIpAddr} parameter is not present from IAGnssCallback.hal@2.0 onwards 347 * and is set to {@code null}. 348 */ onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr)349 void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { 350 if (DEBUG) Log.d(TAG, "AGPS_DATA_CONNECTION: " + agpsDataConnStatusAsString(agpsStatus)); 351 switch (agpsStatus) { 352 case GPS_REQUEST_AGPS_DATA_CONN: 353 runOnHandler(() -> handleRequestSuplConnection(agpsType, suplIpAddr)); 354 break; 355 case GPS_RELEASE_AGPS_DATA_CONN: 356 runOnHandler(() -> handleReleaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN)); 357 break; 358 case GPS_AGPS_DATA_CONNECTED: 359 case GPS_AGPS_DATA_CONN_DONE: 360 case GPS_AGPS_DATA_CONN_FAILED: 361 break; 362 default: 363 Log.w(TAG, "Received unknown AGPS status: " + agpsStatus); 364 } 365 } 366 createNetworkConnectivityCallback()367 private ConnectivityManager.NetworkCallback createNetworkConnectivityCallback() { 368 return new ConnectivityManager.NetworkCallback() { 369 // Used to filter out network capabilities changes that we are not interested in. 370 // NOTE: Not using a ConcurrentHashMap and also not using locking around updates 371 // and access to the map object because it is all done inside the same 372 // handler thread invoking the callback methods. 373 private HashMap<Network, NetworkCapabilities> 374 mAvailableNetworkCapabilities = new HashMap<>( 375 HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS); 376 377 @Override 378 public void onCapabilitiesChanged(Network network, 379 NetworkCapabilities capabilities) { 380 // This callback is invoked for any change in the network capabilities including 381 // initial availability, and changes while still available. Only process if the 382 // capabilities that we pass on to HAL change. 383 if (!NetworkAttributes.hasCapabilitiesChanged( 384 mAvailableNetworkCapabilities.get(network), capabilities)) { 385 if (VERBOSE) { 386 Log.v(TAG, "Relevant network capabilities unchanged. Capabilities: " 387 + capabilities); 388 } 389 return; 390 } 391 392 mAvailableNetworkCapabilities.put(network, capabilities); 393 if (DEBUG) { 394 Log.d(TAG, "Network connected/capabilities updated. Available networks count: " 395 + mAvailableNetworkCapabilities.size()); 396 } 397 398 mGnssNetworkListener.onNetworkAvailable(); 399 400 // Always on, notify HAL so it can get data it needs 401 handleUpdateNetworkState(network, true, capabilities); 402 } 403 404 @Override 405 public void onLost(Network network) { 406 if (mAvailableNetworkCapabilities.remove(network) == null) { 407 Log.w(TAG, "Incorrectly received network callback onLost() before" 408 + " onCapabilitiesChanged() for network: " + network); 409 return; 410 } 411 412 Log.i(TAG, "Network connection lost. Available networks count: " 413 + mAvailableNetworkCapabilities.size()); 414 handleUpdateNetworkState(network, false, null); 415 } 416 }; 417 } 418 createSuplConnectivityCallback()419 private ConnectivityManager.NetworkCallback createSuplConnectivityCallback() { 420 return new ConnectivityManager.NetworkCallback() { 421 @Override 422 public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) { 423 if (DEBUG) Log.d(TAG, "SUPL network connection available."); 424 // Specific to a change to a SUPL enabled network becoming ready 425 handleSuplConnectionAvailable(network, linkProperties); 426 } 427 428 @Override 429 public void onLost(Network network) { 430 Log.i(TAG, "SUPL network connection lost."); 431 handleReleaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN); 432 } 433 434 @Override 435 public void onUnavailable() { 436 Log.i(TAG, "SUPL network connection request timed out."); 437 // Could not setup the connection to the network in the specified time duration. 438 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); 439 } 440 }; 441 } 442 443 private void runOnHandler(Runnable event) { 444 // hold a wake lock until this message is delivered 445 // note that this assumes the message will not be removed from the queue before 446 // it is handled (otherwise the wake lock would be leaked). 447 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS); 448 if (!mHandler.post(runEventAndReleaseWakeLock(event))) { 449 mWakeLock.release(); 450 } 451 } 452 453 private Runnable runEventAndReleaseWakeLock(Runnable event) { 454 return () -> { 455 try { 456 event.run(); 457 } finally { 458 mWakeLock.release(); 459 } 460 }; 461 } 462 463 private void handleUpdateNetworkState(Network network, boolean isConnected, 464 NetworkCapabilities capabilities) { 465 boolean networkAvailable = false; 466 TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class); 467 if (telephonyManager != null) { 468 networkAvailable = isConnected && telephonyManager.getDataEnabled(); 469 } 470 NetworkAttributes networkAttributes = updateTrackedNetworksState(isConnected, network, 471 capabilities); 472 String apn = networkAttributes.mApn; 473 int type = networkAttributes.mType; 474 // When isConnected is false, capabilities argument is null. So, use last received 475 // capabilities. 476 capabilities = networkAttributes.mCapabilities; 477 Log.i(TAG, String.format( 478 "updateNetworkState, state=%s, connected=%s, network=%s, capabilityFlags=%d" 479 + ", availableNetworkCount: %d", 480 agpsDataConnStateAsString(), 481 isConnected, 482 network, 483 NetworkAttributes.getCapabilityFlags(capabilities), 484 mAvailableNetworkAttributes.size())); 485 486 if (native_is_agps_ril_supported()) { 487 native_update_network_state( 488 isConnected, 489 type, 490 !capabilities.hasTransport( 491 NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING), /* isRoaming */ 492 networkAvailable, 493 apn != null ? apn : "", 494 network.getNetworkHandle(), 495 NetworkAttributes.getCapabilityFlags(capabilities)); 496 } else if (DEBUG) { 497 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported"); 498 } 499 } 500 501 private NetworkAttributes updateTrackedNetworksState(boolean isConnected, Network network, 502 NetworkCapabilities capabilities) { 503 if (!isConnected) { 504 // Connection lost event. So, remove it from tracked networks. 505 return mAvailableNetworkAttributes.remove(network); 506 } 507 508 NetworkAttributes networkAttributes = mAvailableNetworkAttributes.get(network); 509 if (networkAttributes != null) { 510 // Capabilities updated event for the connected network. 511 networkAttributes.mCapabilities = capabilities; 512 return networkAttributes; 513 } 514 515 // Initial capabilities event (equivalent to connection available event). 516 networkAttributes = new NetworkAttributes(); 517 networkAttributes.mCapabilities = capabilities; 518 519 // TODO: The synchronous method ConnectivityManager.getNetworkInfo() should not be called 520 // inside the asynchronous ConnectivityManager.NetworkCallback methods. 521 NetworkInfo info = mConnMgr.getNetworkInfo(network); 522 if (info != null) { 523 networkAttributes.mApn = info.getExtraInfo(); 524 networkAttributes.mType = info.getType(); 525 } 526 527 // Start tracking this network for connection status updates. 528 mAvailableNetworkAttributes.put(network, networkAttributes); 529 return networkAttributes; 530 } 531 532 private void handleSuplConnectionAvailable(Network network, LinkProperties linkProperties) { 533 // TODO: The synchronous method ConnectivityManager.getNetworkInfo() should not be called 534 // inside the asynchronous ConnectivityManager.NetworkCallback methods. 535 NetworkInfo info = mConnMgr.getNetworkInfo(network); 536 String apn = null; 537 if (info != null) { 538 apn = info.getExtraInfo(); 539 } 540 541 if (DEBUG) { 542 String message = String.format( 543 "handleSuplConnectionAvailable: state=%s, suplNetwork=%s, info=%s", 544 agpsDataConnStateAsString(), 545 network, 546 info); 547 Log.d(TAG, message); 548 } 549 550 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 551 if (apn == null) { 552 // assign a placeholder value in the case of C2K as otherwise we will have a runtime 553 // exception in the following call to native_agps_data_conn_open 554 apn = "dummy-apn"; 555 } 556 557 // Setting route to host is needed for GNSS HAL implementations earlier than 558 // @2.0::IAgnssCallback. The HAL @2.0::IAgnssCallback.agnssStatusCb() method does 559 // not require setting route to SUPL host and hence does not provide an IP address. 560 if (mAGpsDataConnectionIpAddr != null) { 561 setRouting(); 562 } 563 564 int apnIpType = getLinkIpType(linkProperties); 565 if (DEBUG) { 566 String message = String.format( 567 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", 568 apn, 569 apnIpType); 570 Log.d(TAG, message); 571 } 572 native_agps_data_conn_open(network.getNetworkHandle(), apn, apnIpType); 573 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 574 } 575 } 576 577 @RequiresPermission(allOf = { 578 android.Manifest.permission.ACCESS_COARSE_LOCATION, 579 android.Manifest.permission.READ_PHONE_STATE 580 }) 581 private void handleRequestSuplConnection(int agpsType, byte[] suplIpAddr) { 582 mAGpsDataConnectionIpAddr = null; 583 mAGpsType = agpsType; 584 if (suplIpAddr != null) { 585 if (VERBOSE) Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(suplIpAddr)); 586 try { 587 mAGpsDataConnectionIpAddr = InetAddress.getByAddress(suplIpAddr); 588 if (DEBUG) Log.d(TAG, "IP address converted to: " + mAGpsDataConnectionIpAddr); 589 } catch (UnknownHostException e) { 590 Log.e(TAG, "Bad IP Address: " + Arrays.toString(suplIpAddr), e); 591 } 592 } 593 594 if (DEBUG) { 595 String message = String.format( 596 "requestSuplConnection, state=%s, agpsType=%s, address=%s", 597 agpsDataConnStateAsString(), 598 agpsTypeAsString(agpsType), 599 mAGpsDataConnectionIpAddr); 600 Log.d(TAG, message); 601 } 602 603 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 604 return; 605 } 606 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 607 608 // The transport type must be set to NetworkCapabilities.TRANSPORT_CELLULAR for the 609 // deprecated requestRouteToHostAddress() method in ConnectivityService to work for 610 // pre-gnss@2.0 devices. 611 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); 612 networkRequestBuilder.addCapability(getNetworkCapability(mAGpsType)); 613 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); 614 615 if (com.android.internal.telephony.flags.Flags.satelliteInternet()) { 616 // Add transport type NetworkCapabilities.TRANSPORT_SATELLITE on satellite network. 617 TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class); 618 if (telephonyManager != null) { 619 ServiceState state = telephonyManager.getServiceState(); 620 if (state != null && state.isUsingNonTerrestrialNetwork()) { 621 networkRequestBuilder.removeCapability(NET_CAPABILITY_NOT_RESTRICTED); 622 try { 623 networkRequestBuilder.addTransportType(NetworkCapabilities 624 .TRANSPORT_SATELLITE); 625 networkRequestBuilder.removeCapability(NetworkCapabilities 626 .NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED); 627 } catch (IllegalArgumentException ignored) { 628 // In case TRANSPORT_SATELLITE or NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED 629 // are not recognized, meaning an old connectivity module runs on new 630 // android in which case no network with such capabilities will be brought 631 // up, so it's safe to ignore the exception. 632 // TODO: Can remove the try-catch in next quarter release. 633 } 634 } 635 } 636 } 637 638 // During an emergency call, and when we have cached the Active Sub Id, we set the 639 // Network Specifier so that the network request goes to the correct Sub Id 640 if (mNiHandler.getInEmergency() && mActiveSubId >= 0) { 641 if (DEBUG) Log.d(TAG, "Adding Network Specifier: " + Integer.toString(mActiveSubId)); 642 networkRequestBuilder.setNetworkSpecifier(Integer.toString(mActiveSubId)); 643 networkRequestBuilder.removeCapability(NET_CAPABILITY_NOT_RESTRICTED); 644 } 645 NetworkRequest networkRequest = networkRequestBuilder.build(); 646 // Make sure we only have a single request. 647 if (mSuplConnectivityCallback != null) { 648 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback); 649 } 650 mSuplConnectivityCallback = createSuplConnectivityCallback(); 651 try { 652 mConnMgr.requestNetwork( 653 networkRequest, 654 mSuplConnectivityCallback, 655 mHandler, 656 SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS); 657 if (Flags.releaseSuplConnectionOnTimeout()) { 658 // Schedule to release the SUPL connection after timeout 659 mHandler.removeCallbacksAndMessages(mSuplConnectionReleaseOnTimeoutToken); 660 mHandler.postDelayed(() -> handleReleaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN), 661 mSuplConnectionReleaseOnTimeoutToken, 662 SUPL_CONNECTION_TIMEOUT_MILLIS); 663 } 664 } catch (RuntimeException e) { 665 Log.e(TAG, "Failed to request network.", e); 666 mSuplConnectivityCallback = null; 667 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); 668 } 669 } 670 671 private int getNetworkCapability(int agpsType) { 672 switch (agpsType) { 673 case AGPS_TYPE_C2K: 674 case AGPS_TYPE_SUPL: 675 return NetworkCapabilities.NET_CAPABILITY_SUPL; 676 case AGPS_TYPE_EIMS: 677 return NetworkCapabilities.NET_CAPABILITY_EIMS; 678 case AGPS_TYPE_IMS: 679 return NetworkCapabilities.NET_CAPABILITY_IMS; 680 default: 681 throw new IllegalArgumentException("agpsType: " + agpsType); 682 } 683 } 684 685 private void handleReleaseSuplConnection(int agpsDataConnStatus) { 686 if (DEBUG) { 687 String message = String.format( 688 "releaseSuplConnection, state=%s, status=%s", 689 agpsDataConnStateAsString(), 690 agpsDataConnStatusAsString(agpsDataConnStatus)); 691 Log.d(TAG, message); 692 } 693 694 if (Flags.releaseSuplConnectionOnTimeout()) { 695 // Remove pending task to avoid releasing an incorrect connection 696 mHandler.removeCallbacksAndMessages(mSuplConnectionReleaseOnTimeoutToken); 697 } 698 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) { 699 return; 700 } 701 702 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 703 if (mSuplConnectivityCallback != null) { 704 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback); 705 mSuplConnectivityCallback = null; 706 } 707 switch (agpsDataConnStatus) { 708 case GPS_AGPS_DATA_CONN_FAILED: 709 native_agps_data_conn_failed(); 710 break; 711 case GPS_RELEASE_AGPS_DATA_CONN: 712 native_agps_data_conn_closed(); 713 break; 714 default: 715 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus); 716 } 717 } 718 719 // TODO: Delete this method when all devices upgrade to HAL @2.0::IAGnssCallback 720 // interface which does not require setting route to host. 721 private void setRouting() { 722 boolean result = mConnMgr.requestRouteToHostAddress( 723 ConnectivityManager.TYPE_MOBILE_SUPL, 724 mAGpsDataConnectionIpAddr); 725 726 if (!result) { 727 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); 728 } else if (DEBUG) { 729 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); 730 } 731 } 732 733 /** 734 * Ensures the calling function is running in the thread associated with {@link #mHandler}. 735 */ 736 private void ensureInHandlerThread() { 737 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) { 738 return; 739 } 740 throw new IllegalStateException("This method must run on the Handler thread."); 741 } 742 743 /** 744 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}. 745 */ 746 private String agpsDataConnStateAsString() { 747 switch (mAGpsDataConnectionState) { 748 case AGPS_DATA_CONNECTION_CLOSED: 749 return "CLOSED"; 750 case AGPS_DATA_CONNECTION_OPEN: 751 return "OPEN"; 752 case AGPS_DATA_CONNECTION_OPENING: 753 return "OPENING"; 754 default: 755 return "<Unknown>(" + mAGpsDataConnectionState + ")"; 756 } 757 } 758 759 /** 760 * @return A string representing the given GPS_AGPS_DATA status. 761 */ 762 private String agpsDataConnStatusAsString(int agpsDataConnStatus) { 763 switch (agpsDataConnStatus) { 764 case GPS_AGPS_DATA_CONNECTED: 765 return "CONNECTED"; 766 case GPS_AGPS_DATA_CONN_DONE: 767 return "DONE"; 768 case GPS_AGPS_DATA_CONN_FAILED: 769 return "FAILED"; 770 case GPS_RELEASE_AGPS_DATA_CONN: 771 return "RELEASE"; 772 case GPS_REQUEST_AGPS_DATA_CONN: 773 return "REQUEST"; 774 default: 775 return "<Unknown>(" + agpsDataConnStatus + ")"; 776 } 777 } 778 779 private String agpsTypeAsString(int agpsType) { 780 switch (agpsType) { 781 case AGPS_TYPE_SUPL: 782 return "SUPL"; 783 case AGPS_TYPE_C2K: 784 return "C2K"; 785 case AGPS_TYPE_EIMS: 786 return "EIMS"; 787 case AGPS_TYPE_IMS: 788 return "IMS"; 789 default: 790 return "<Unknown>(" + agpsType + ")"; 791 } 792 } 793 794 private int getLinkIpType(LinkProperties linkProperties) { 795 ensureInHandlerThread(); 796 boolean isIPv4 = false; 797 boolean isIPv6 = false; 798 799 List<LinkAddress> linkAddresses = linkProperties.getLinkAddresses(); 800 for (LinkAddress linkAddress : linkAddresses) { 801 InetAddress inetAddress = linkAddress.getAddress(); 802 if (inetAddress instanceof Inet4Address) { 803 isIPv4 = true; 804 } else if (inetAddress instanceof Inet6Address) { 805 isIPv6 = true; 806 } 807 if (DEBUG) Log.d(TAG, "LinkAddress : " + inetAddress.toString()); 808 } 809 810 if (isIPv4 && isIPv6) { 811 return APN_IPV4V6; 812 } 813 if (isIPv4) { 814 return APN_IPV4; 815 } 816 if (isIPv6) { 817 return APN_IPV6; 818 } 819 return APN_INVALID; 820 } 821 822 protected boolean isNativeAgpsRilSupported() { 823 return native_is_agps_ril_supported(); 824 } 825 826 // AGPS support 827 private native void native_agps_data_conn_open(long networkHandle, String apn, int apnIpType); 828 829 private native void native_agps_data_conn_closed(); 830 831 private native void native_agps_data_conn_failed(); 832 833 // AGPS ril support 834 private static native boolean native_is_agps_ril_supported(); 835 836 private native void native_update_network_state(boolean connected, int type, boolean roaming, 837 boolean available, String apn, long networkHandle, short capabilities); 838 } 839