1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.location; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.net.ConnectivityManager; 22 import android.net.Network; 23 import android.net.NetworkCapabilities; 24 import android.net.NetworkInfo; 25 import android.net.NetworkRequest; 26 import android.os.Handler; 27 import android.os.Looper; 28 import android.os.PowerManager; 29 import android.provider.Telephony.Carriers; 30 import android.telephony.ServiceState; 31 import android.telephony.TelephonyManager; 32 import android.util.Log; 33 34 import java.net.InetAddress; 35 import java.net.UnknownHostException; 36 import java.util.Arrays; 37 import java.util.HashMap; 38 39 /** 40 * Handles network connection requests and network state change updates for AGPS data download. 41 */ 42 class GnssNetworkConnectivityHandler { 43 static final String TAG = "GnssNetworkConnectivityHandler"; 44 45 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 46 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); 47 48 // for mAGpsDataConnectionState 49 private static final int AGPS_DATA_CONNECTION_CLOSED = 0; 50 private static final int AGPS_DATA_CONNECTION_OPENING = 1; 51 private static final int AGPS_DATA_CONNECTION_OPEN = 2; 52 53 // these need to match AGnssStatusValue enum in IAGnssCallback.hal 54 /** AGPS status event values. */ 55 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1; 56 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2; 57 private static final int GPS_AGPS_DATA_CONNECTED = 3; 58 private static final int GPS_AGPS_DATA_CONN_DONE = 4; 59 private static final int GPS_AGPS_DATA_CONN_FAILED = 5; 60 61 // these must match the ApnIpType enum in IAGnss.hal 62 private static final int APN_INVALID = 0; 63 private static final int APN_IPV4 = 1; 64 private static final int APN_IPV6 = 2; 65 private static final int APN_IPV4V6 = 3; 66 67 // these must match the NetworkCapability enum flags in IAGnssRil.hal 68 private static final int AGNSS_NET_CAPABILITY_NOT_METERED = 1 << 0; 69 private static final int AGNSS_NET_CAPABILITY_NOT_ROAMING = 1 << 1; 70 71 // these need to match AGnssType enum in IAGnssCallback.hal 72 public static final int AGPS_TYPE_SUPL = 1; 73 public static final int AGPS_TYPE_C2K = 2; 74 private static final int AGPS_TYPE_EIMS = 3; 75 private static final int AGPS_TYPE_IMS = 4; 76 77 // Default time limit in milliseconds for the ConnectivityManager to find a suitable 78 // network with SUPL connectivity or report an error. 79 private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 10 * 1000; 80 81 private static final int HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS = 5; 82 83 // Keeps track of networks and their state as notified by the network request callbacks. 84 // Limit initial capacity to 5 as the number of connected networks will likely be small. 85 // NOTE: Must be accessed/modified only through the mHandler thread. 86 private HashMap<Network, NetworkAttributes> mAvailableNetworkAttributes = 87 new HashMap<>(HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS); 88 89 private final ConnectivityManager mConnMgr; 90 91 private final Handler mHandler; 92 private final GnssNetworkListener mGnssNetworkListener; 93 94 private int mAGpsDataConnectionState; 95 private InetAddress mAGpsDataConnectionIpAddr; 96 private int mAGpsType; 97 98 private final Context mContext; 99 100 // Wakelocks 101 private static final String WAKELOCK_KEY = "GnssNetworkConnectivityHandler"; 102 private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000; 103 private final PowerManager.WakeLock mWakeLock; 104 105 /** 106 * Network attributes needed when updating HAL about network connectivity status changes. 107 */ 108 private static class NetworkAttributes { 109 private NetworkCapabilities mCapabilities; 110 private String mApn; 111 private int mType = ConnectivityManager.TYPE_NONE; 112 113 /** 114 * Returns true if the capabilities that we pass on to HAL change between {@curCapabilities} 115 * and {@code newCapabilities}. 116 */ hasCapabilitiesChanged(NetworkCapabilities curCapabilities, NetworkCapabilities newCapabilities)117 private static boolean hasCapabilitiesChanged(NetworkCapabilities curCapabilities, 118 NetworkCapabilities newCapabilities) { 119 if (curCapabilities == null || newCapabilities == null) { 120 return true; 121 } 122 123 // Monitor for roaming and metered capability changes. 124 return hasCapabilityChanged(curCapabilities, newCapabilities, 125 NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) 126 || hasCapabilityChanged(curCapabilities, newCapabilities, 127 NetworkCapabilities.NET_CAPABILITY_NOT_METERED); 128 } 129 hasCapabilityChanged(NetworkCapabilities curCapabilities, NetworkCapabilities newCapabilities, int capability)130 private static boolean hasCapabilityChanged(NetworkCapabilities curCapabilities, 131 NetworkCapabilities newCapabilities, int capability) { 132 return curCapabilities.hasCapability(capability) 133 != newCapabilities.hasCapability(capability); 134 } 135 getCapabilityFlags(NetworkCapabilities capabilities)136 private static short getCapabilityFlags(NetworkCapabilities capabilities) { 137 short capabilityFlags = 0; 138 if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) { 139 capabilityFlags |= AGNSS_NET_CAPABILITY_NOT_ROAMING; 140 } 141 if (capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) { 142 capabilityFlags |= AGNSS_NET_CAPABILITY_NOT_METERED; 143 } 144 return capabilityFlags; 145 } 146 } 147 148 /** 149 * Callback used to listen for data connectivity changes. 150 */ 151 private ConnectivityManager.NetworkCallback mNetworkConnectivityCallback; 152 153 /** 154 * Callback used to listen for availability of a requested SUPL connection. 155 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to 156 * manage the registration/un-registration lifetimes separately. 157 */ 158 private ConnectivityManager.NetworkCallback mSuplConnectivityCallback; 159 160 /** 161 * Interface to listen for network availability changes. 162 */ 163 interface GnssNetworkListener { onNetworkAvailable()164 void onNetworkAvailable(); 165 } 166 GnssNetworkConnectivityHandler(Context context, GnssNetworkListener gnssNetworkListener, Looper looper)167 GnssNetworkConnectivityHandler(Context context, 168 GnssNetworkListener gnssNetworkListener, 169 Looper looper) { 170 mContext = context; 171 mGnssNetworkListener = gnssNetworkListener; 172 173 PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 174 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); 175 176 mHandler = new Handler(looper); 177 mConnMgr = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 178 mSuplConnectivityCallback = createSuplConnectivityCallback(); 179 } 180 registerNetworkCallbacks()181 void registerNetworkCallbacks() { 182 // register for connectivity change events. 183 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); 184 networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 185 networkRequestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); 186 networkRequestBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); 187 NetworkRequest networkRequest = networkRequestBuilder.build(); 188 mNetworkConnectivityCallback = createNetworkConnectivityCallback(); 189 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback, mHandler); 190 } 191 192 /** 193 * @return {@code true} if there is a data network available for outgoing connections, 194 * {@code false} otherwise. 195 */ isDataNetworkConnected()196 boolean isDataNetworkConnected() { 197 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo(); 198 return activeNetworkInfo != null && activeNetworkInfo.isConnected(); 199 } 200 201 /** 202 * Called from native code to update AGPS connection status, or to request or release a SUPL 203 * connection. 204 * 205 * <p>Note: {@code suplIpAddr} parameter is not present from IAGnssCallback.hal@2.0 onwards 206 * and is set to {@code null}. 207 */ onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr)208 void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) { 209 if (DEBUG) Log.d(TAG, "AGPS_DATA_CONNECTION: " + agpsDataConnStatusAsString(agpsStatus)); 210 switch (agpsStatus) { 211 case GPS_REQUEST_AGPS_DATA_CONN: 212 runOnHandler(() -> handleRequestSuplConnection(agpsType, suplIpAddr)); 213 break; 214 case GPS_RELEASE_AGPS_DATA_CONN: 215 runOnHandler(() -> handleReleaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN)); 216 break; 217 case GPS_AGPS_DATA_CONNECTED: 218 case GPS_AGPS_DATA_CONN_DONE: 219 case GPS_AGPS_DATA_CONN_FAILED: 220 break; 221 default: 222 Log.w(TAG, "Received unknown AGPS status: " + agpsStatus); 223 } 224 } 225 createNetworkConnectivityCallback()226 private ConnectivityManager.NetworkCallback createNetworkConnectivityCallback() { 227 return new ConnectivityManager.NetworkCallback() { 228 // Used to filter out network capabilities changes that we are not interested in. 229 // NOTE: Not using a ConcurrentHashMap and also not using locking around updates 230 // and access to the map object because it is all done inside the same 231 // handler thread invoking the callback methods. 232 private HashMap<Network, NetworkCapabilities> 233 mAvailableNetworkCapabilities = new HashMap<>( 234 HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS); 235 236 @Override 237 public void onCapabilitiesChanged(Network network, 238 NetworkCapabilities capabilities) { 239 // This callback is invoked for any change in the network capabilities including 240 // initial availability, and changes while still available. Only process if the 241 // capabilities that we pass on to HAL change. 242 if (!NetworkAttributes.hasCapabilitiesChanged( 243 mAvailableNetworkCapabilities.get(network), capabilities)) { 244 if (VERBOSE) { 245 Log.v(TAG, "Relevant network capabilities unchanged. Capabilities: " 246 + capabilities); 247 } 248 return; 249 } 250 251 mAvailableNetworkCapabilities.put(network, capabilities); 252 if (DEBUG) { 253 Log.d(TAG, "Network connected/capabilities updated. Available networks count: " 254 + mAvailableNetworkCapabilities.size()); 255 } 256 257 mGnssNetworkListener.onNetworkAvailable(); 258 259 // Always on, notify HAL so it can get data it needs 260 handleUpdateNetworkState(network, true, capabilities); 261 } 262 263 @Override 264 public void onLost(Network network) { 265 if (mAvailableNetworkCapabilities.remove(network) == null) { 266 Log.w(TAG, "Incorrectly received network callback onLost() before" 267 + " onCapabilitiesChanged() for network: " + network); 268 return; 269 } 270 271 Log.i(TAG, "Network connection lost. Available networks count: " 272 + mAvailableNetworkCapabilities.size()); 273 handleUpdateNetworkState(network, false, null); 274 } 275 }; 276 } 277 createSuplConnectivityCallback()278 private ConnectivityManager.NetworkCallback createSuplConnectivityCallback() { 279 return new ConnectivityManager.NetworkCallback() { 280 @Override 281 public void onAvailable(Network network) { 282 if (DEBUG) Log.d(TAG, "SUPL network connection available."); 283 // Specific to a change to a SUPL enabled network becoming ready 284 handleSuplConnectionAvailable(network); 285 } 286 287 @Override 288 public void onLost(Network network) { 289 Log.i(TAG, "SUPL network connection lost."); 290 handleReleaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN); 291 } 292 293 @Override 294 public void onUnavailable() { 295 Log.i(TAG, "SUPL network connection request timed out."); 296 // Could not setup the connection to the network in the specified time duration. 297 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED); 298 } 299 }; 300 } 301 302 private void runOnHandler(Runnable event) { 303 // hold a wake lock until this message is delivered 304 // note that this assumes the message will not be removed from the queue before 305 // it is handled (otherwise the wake lock would be leaked). 306 mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS); 307 if (!mHandler.post(runEventAndReleaseWakeLock(event))) { 308 mWakeLock.release(); 309 } 310 } 311 312 private Runnable runEventAndReleaseWakeLock(Runnable event) { 313 return () -> { 314 try { 315 event.run(); 316 } finally { 317 mWakeLock.release(); 318 } 319 }; 320 } 321 322 private void handleUpdateNetworkState(Network network, boolean isConnected, 323 NetworkCapabilities capabilities) { 324 boolean networkAvailable = false; 325 TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class); 326 if (telephonyManager != null) { 327 networkAvailable = isConnected && telephonyManager.getDataEnabled(); 328 } 329 NetworkAttributes networkAttributes = updateTrackedNetworksState(isConnected, network, 330 capabilities); 331 String apn = networkAttributes.mApn; 332 int type = networkAttributes.mType; 333 // When isConnected is false, capabilities argument is null. So, use last received 334 // capabilities. 335 capabilities = networkAttributes.mCapabilities; 336 Log.i(TAG, String.format( 337 "updateNetworkState, state=%s, connected=%s, network=%s, capabilities=%s" 338 + ", apn: %s, availableNetworkCount: %d", 339 agpsDataConnStateAsString(), 340 isConnected, 341 network, 342 capabilities, 343 apn, 344 mAvailableNetworkAttributes.size())); 345 346 if (native_is_agps_ril_supported()) { 347 native_update_network_state( 348 isConnected, 349 type, 350 !capabilities.hasTransport( 351 NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING), /* isRoaming */ 352 networkAvailable, 353 apn != null ? apn : "", 354 network.getNetworkHandle(), 355 NetworkAttributes.getCapabilityFlags(capabilities)); 356 } else if (DEBUG) { 357 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported"); 358 } 359 } 360 361 private NetworkAttributes updateTrackedNetworksState(boolean isConnected, Network network, 362 NetworkCapabilities capabilities) { 363 if (!isConnected) { 364 // Connection lost event. So, remove it from tracked networks. 365 return mAvailableNetworkAttributes.remove(network); 366 } 367 368 NetworkAttributes networkAttributes = mAvailableNetworkAttributes.get(network); 369 if (networkAttributes != null) { 370 // Capabilities updated event for the connected network. 371 networkAttributes.mCapabilities = capabilities; 372 return networkAttributes; 373 } 374 375 // Initial capabilities event (equivalent to connection available event). 376 networkAttributes = new NetworkAttributes(); 377 networkAttributes.mCapabilities = capabilities; 378 379 // TODO: The synchronous method ConnectivityManager.getNetworkInfo() should not be called 380 // inside the asynchronous ConnectivityManager.NetworkCallback methods. 381 NetworkInfo info = mConnMgr.getNetworkInfo(network); 382 if (info != null) { 383 networkAttributes.mApn = info.getExtraInfo(); 384 networkAttributes.mType = info.getType(); 385 } 386 387 // Start tracking this network for connection status updates. 388 mAvailableNetworkAttributes.put(network, networkAttributes); 389 return networkAttributes; 390 } 391 392 private void handleSuplConnectionAvailable(Network network) { 393 // TODO: The synchronous method ConnectivityManager.getNetworkInfo() should not be called 394 // inside the asynchronous ConnectivityManager.NetworkCallback methods. 395 NetworkInfo info = mConnMgr.getNetworkInfo(network); 396 String apn = null; 397 if (info != null) { 398 apn = info.getExtraInfo(); 399 } 400 401 if (DEBUG) { 402 String message = String.format( 403 "handleSuplConnectionAvailable: state=%s, suplNetwork=%s, info=%s", 404 agpsDataConnStateAsString(), 405 network, 406 info); 407 Log.d(TAG, message); 408 } 409 410 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { 411 if (apn == null) { 412 // assign a dummy value in the case of C2K as otherwise we will have a runtime 413 // exception in the following call to native_agps_data_conn_open 414 apn = "dummy-apn"; 415 } 416 417 // Setting route to host is needed for GNSS HAL implementations earlier than 418 // @2.0::IAgnssCallback. The HAL @2.0::IAgnssCallback.agnssStatusCb() method does 419 // not require setting route to SUPL host and hence does not provide an IP address. 420 if (mAGpsDataConnectionIpAddr != null) { 421 setRouting(); 422 } 423 424 int apnIpType = getApnIpType(apn); 425 if (DEBUG) { 426 String message = String.format( 427 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s", 428 apn, 429 apnIpType); 430 Log.d(TAG, message); 431 } 432 native_agps_data_conn_open(network.getNetworkHandle(), apn, apnIpType); 433 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; 434 } 435 } 436 437 private void handleRequestSuplConnection(int agpsType, byte[] suplIpAddr) { 438 mAGpsDataConnectionIpAddr = null; 439 mAGpsType = agpsType; 440 if (suplIpAddr != null) { 441 if (VERBOSE) Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(suplIpAddr)); 442 try { 443 mAGpsDataConnectionIpAddr = InetAddress.getByAddress(suplIpAddr); 444 if (DEBUG) Log.d(TAG, "IP address converted to: " + mAGpsDataConnectionIpAddr); 445 } catch (UnknownHostException e) { 446 Log.e(TAG, "Bad IP Address: " + suplIpAddr, e); 447 } 448 } 449 450 if (DEBUG) { 451 String message = String.format( 452 "requestSuplConnection, state=%s, agpsType=%s, address=%s", 453 agpsDataConnStateAsString(), 454 agpsTypeAsString(agpsType), 455 mAGpsDataConnectionIpAddr); 456 Log.d(TAG, message); 457 } 458 459 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { 460 return; 461 } 462 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; 463 464 // The transport type must be set to NetworkCapabilities.TRANSPORT_CELLULAR for the 465 // deprecated requestRouteToHostAddress() method in ConnectivityService to work for 466 // pre-gnss@2.0 devices. 467 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); 468 networkRequestBuilder.addCapability(getNetworkCapability(mAGpsType)); 469 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); 470 NetworkRequest networkRequest = networkRequestBuilder.build(); 471 mConnMgr.requestNetwork( 472 networkRequest, 473 mSuplConnectivityCallback, 474 mHandler, 475 SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS); 476 } 477 478 private int getNetworkCapability(int agpsType) { 479 switch (agpsType) { 480 case AGPS_TYPE_C2K: 481 case AGPS_TYPE_SUPL: 482 return NetworkCapabilities.NET_CAPABILITY_SUPL; 483 case AGPS_TYPE_EIMS: 484 return NetworkCapabilities.NET_CAPABILITY_EIMS; 485 case AGPS_TYPE_IMS: 486 return NetworkCapabilities.NET_CAPABILITY_IMS; 487 default: 488 throw new IllegalArgumentException("agpsType: " + agpsType); 489 } 490 } 491 492 private void handleReleaseSuplConnection(int agpsDataConnStatus) { 493 if (DEBUG) { 494 String message = String.format( 495 "releaseSuplConnection, state=%s, status=%s", 496 agpsDataConnStateAsString(), 497 agpsDataConnStatusAsString(agpsDataConnStatus)); 498 Log.d(TAG, message); 499 } 500 501 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) { 502 return; 503 } 504 505 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; 506 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback); 507 switch (agpsDataConnStatus) { 508 case GPS_AGPS_DATA_CONN_FAILED: 509 native_agps_data_conn_failed(); 510 break; 511 case GPS_RELEASE_AGPS_DATA_CONN: 512 native_agps_data_conn_closed(); 513 break; 514 default: 515 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus); 516 } 517 } 518 519 // TODO: Delete this method when all devices upgrade to HAL @2.0::IAGnssCallback 520 // interface which does not require setting route to host. 521 private void setRouting() { 522 boolean result = mConnMgr.requestRouteToHostAddress( 523 ConnectivityManager.TYPE_MOBILE_SUPL, 524 mAGpsDataConnectionIpAddr); 525 526 if (!result) { 527 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr); 528 } else if (DEBUG) { 529 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr); 530 } 531 } 532 533 /** 534 * Ensures the calling function is running in the thread associated with {@link #mHandler}. 535 */ 536 private void ensureInHandlerThread() { 537 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) { 538 return; 539 } 540 throw new IllegalStateException("This method must run on the Handler thread."); 541 } 542 543 /** 544 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}. 545 */ 546 private String agpsDataConnStateAsString() { 547 switch (mAGpsDataConnectionState) { 548 case AGPS_DATA_CONNECTION_CLOSED: 549 return "CLOSED"; 550 case AGPS_DATA_CONNECTION_OPEN: 551 return "OPEN"; 552 case AGPS_DATA_CONNECTION_OPENING: 553 return "OPENING"; 554 default: 555 return "<Unknown>(" + mAGpsDataConnectionState + ")"; 556 } 557 } 558 559 /** 560 * @return A string representing the given GPS_AGPS_DATA status. 561 */ 562 private String agpsDataConnStatusAsString(int agpsDataConnStatus) { 563 switch (agpsDataConnStatus) { 564 case GPS_AGPS_DATA_CONNECTED: 565 return "CONNECTED"; 566 case GPS_AGPS_DATA_CONN_DONE: 567 return "DONE"; 568 case GPS_AGPS_DATA_CONN_FAILED: 569 return "FAILED"; 570 case GPS_RELEASE_AGPS_DATA_CONN: 571 return "RELEASE"; 572 case GPS_REQUEST_AGPS_DATA_CONN: 573 return "REQUEST"; 574 default: 575 return "<Unknown>(" + agpsDataConnStatus + ")"; 576 } 577 } 578 579 private String agpsTypeAsString(int agpsType) { 580 switch (agpsType) { 581 case AGPS_TYPE_SUPL: 582 return "SUPL"; 583 case AGPS_TYPE_C2K: 584 return "C2K"; 585 case AGPS_TYPE_EIMS: 586 return "EIMS"; 587 case AGPS_TYPE_IMS: 588 return "IMS"; 589 default: 590 return "<Unknown>(" + agpsType + ")"; 591 } 592 } 593 594 private int getApnIpType(String apn) { 595 ensureInHandlerThread(); 596 if (apn == null) { 597 return APN_INVALID; 598 } 599 TelephonyManager phone = (TelephonyManager) 600 mContext.getSystemService(Context.TELEPHONY_SERVICE); 601 ServiceState serviceState = phone.getServiceState(); 602 String projection = null; 603 String selection = null; 604 605 // Carrier configuration may override framework roaming state, we need to use the actual 606 // modem roaming state instead of the framework roaming state. 607 if (serviceState != null && serviceState.getDataRoamingFromRegistration()) { 608 projection = Carriers.ROAMING_PROTOCOL; 609 } else { 610 projection = Carriers.PROTOCOL; 611 } 612 // No SIM case for emergency 613 if (TelephonyManager.NETWORK_TYPE_UNKNOWN == phone.getNetworkType() 614 && AGPS_TYPE_EIMS == mAGpsType) { 615 selection = String.format( 616 "type like '%%emergency%%' and apn = '%s' and carrier_enabled = 1", apn); 617 } else { 618 selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn); 619 } 620 try (Cursor cursor = mContext.getContentResolver().query( 621 Carriers.CONTENT_URI, 622 new String[]{projection}, 623 selection, 624 null, 625 Carriers.DEFAULT_SORT_ORDER)) { 626 if (null != cursor && cursor.moveToFirst()) { 627 return translateToApnIpType(cursor.getString(0), apn); 628 } else { 629 Log.e(TAG, "No entry found in query for APN: " + apn); 630 } 631 } catch (Exception e) { 632 Log.e(TAG, "Error encountered on APN query for: " + apn, e); 633 } 634 635 return APN_IPV4V6; 636 } 637 638 private int translateToApnIpType(String ipProtocol, String apn) { 639 if ("IP".equals(ipProtocol)) { 640 return APN_IPV4; 641 } 642 if ("IPV6".equals(ipProtocol)) { 643 return APN_IPV6; 644 } 645 if ("IPV4V6".equals(ipProtocol)) { 646 return APN_IPV4V6; 647 } 648 649 // we hit the default case so the ipProtocol is not recognized 650 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn); 651 Log.e(TAG, message); 652 return APN_IPV4V6; 653 } 654 655 // AGPS support 656 private native void native_agps_data_conn_open(long networkHandle, String apn, int apnIpType); 657 658 private native void native_agps_data_conn_closed(); 659 660 private native void native_agps_data_conn_failed(); 661 662 // AGPS ril support 663 private static native boolean native_is_agps_ril_supported(); 664 665 private native void native_update_network_state(boolean connected, int type, boolean roaming, 666 boolean available, String apn, long networkHandle, short capabilities); 667 } 668