1 /* 2 * Copyright 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.internal.telephony.dataconnection; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.StringDef; 22 import android.os.AsyncResult; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.os.RegistrantList; 26 import android.os.SystemProperties; 27 import android.telephony.AccessNetworkConstants; 28 import android.telephony.AccessNetworkConstants.AccessNetworkType; 29 import android.telephony.AccessNetworkConstants.TransportType; 30 import android.telephony.Annotation.ApnType; 31 import android.telephony.CarrierConfigManager; 32 import android.telephony.data.ApnSetting; 33 import android.util.IndentingPrintWriter; 34 import android.util.LocalLog; 35 import android.util.SparseArray; 36 import android.util.SparseIntArray; 37 38 import com.android.internal.annotations.VisibleForTesting; 39 import com.android.internal.telephony.Phone; 40 import com.android.internal.telephony.RIL; 41 import com.android.internal.telephony.dataconnection.AccessNetworksManager.QualifiedNetworks; 42 import com.android.internal.telephony.util.ArrayUtils; 43 import com.android.telephony.Rlog; 44 45 import java.io.FileDescriptor; 46 import java.io.PrintWriter; 47 import java.lang.annotation.Retention; 48 import java.lang.annotation.RetentionPolicy; 49 import java.util.ArrayDeque; 50 import java.util.Arrays; 51 import java.util.HashMap; 52 import java.util.Iterator; 53 import java.util.List; 54 import java.util.Map; 55 import java.util.concurrent.ConcurrentHashMap; 56 import java.util.stream.Collectors; 57 58 /** 59 * This class represents the transport manager which manages available transports (i.e. WWAN or 60 * WLAN) and determine the correct transport for {@link TelephonyNetworkFactory} to handle the data 61 * requests. 62 * 63 * The device can operate in the following modes, which is stored in the system properties 64 * ro.telephony.iwlan_operation_mode. If the system properties is missing, then it's tied to 65 * IRadio version. For 1.4 or above, it's AP-assisted mdoe. For 1.3 or below, it's legacy mode. 66 * 67 * Legacy mode: 68 * Frameworks send all data requests to the default data service, which is the cellular data 69 * service. IWLAN should be still reported as a RAT on cellular network service. 70 * 71 * AP-assisted mode: 72 * IWLAN is handled by IWLAN data service extending {@link android.telephony.data.DataService}, 73 * IWLAN network service extending {@link android.telephony.NetworkService}, and qualified 74 * network service extending {@link android.telephony.data.QualifiedNetworksService}. 75 * 76 * The following settings for service package name need to be configured properly for 77 * frameworks to bind. 78 * 79 * Package name of data service: 80 * The resource overlay 'config_wlan_data_service_package' or, 81 * the carrier config 82 * {@link CarrierConfigManager#KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}. 83 * The carrier config takes precedence over the resource overlay if both exist. 84 * 85 * Package name of network service 86 * The resource overlay 'config_wlan_network_service_package' or 87 * the carrier config 88 * {@link CarrierConfigManager#KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING}. 89 * The carrier config takes precedence over the resource overlay if both exist. 90 * 91 * Package name of qualified network service 92 * The resource overlay 'config_qualified_networks_service_package' or 93 * the carrier config 94 * {@link CarrierConfigManager# 95 * KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING}. 96 * The carrier config takes precedence over the resource overlay if both exist. 97 */ 98 public class TransportManager extends Handler { 99 private final String mLogTag; 100 101 // Key is the access network, value is the transport. 102 private static final Map<Integer, Integer> ACCESS_NETWORK_TRANSPORT_TYPE_MAP; 103 104 static { 105 ACCESS_NETWORK_TRANSPORT_TYPE_MAP = new HashMap<>(); ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.GERAN, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)106 ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.GERAN, 107 AccessNetworkConstants.TRANSPORT_TYPE_WWAN); ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.UTRAN, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)108 ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.UTRAN, 109 AccessNetworkConstants.TRANSPORT_TYPE_WWAN); ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.EUTRAN, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)110 ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.EUTRAN, 111 AccessNetworkConstants.TRANSPORT_TYPE_WWAN); ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.CDMA2000, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)112 ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.CDMA2000, 113 AccessNetworkConstants.TRANSPORT_TYPE_WWAN); ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.NGRAN, AccessNetworkConstants.TRANSPORT_TYPE_WWAN)114 ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.NGRAN, 115 AccessNetworkConstants.TRANSPORT_TYPE_WWAN); ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.IWLAN, AccessNetworkConstants.TRANSPORT_TYPE_WLAN)116 ACCESS_NETWORK_TRANSPORT_TYPE_MAP.put(AccessNetworkType.IWLAN, 117 AccessNetworkConstants.TRANSPORT_TYPE_WLAN); 118 } 119 120 private static final int EVENT_QUALIFIED_NETWORKS_CHANGED = 1; 121 122 private static final int EVENT_UPDATE_AVAILABLE_NETWORKS = 2; 123 124 public static final String SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE = 125 "ro.telephony.iwlan_operation_mode"; 126 127 @Retention(RetentionPolicy.SOURCE) 128 @StringDef(prefix = {"IWLAN_OPERATION_MODE_"}, 129 value = { 130 IWLAN_OPERATION_MODE_DEFAULT, 131 IWLAN_OPERATION_MODE_LEGACY, 132 IWLAN_OPERATION_MODE_AP_ASSISTED}) 133 public @interface IwlanOperationMode {} 134 135 /** 136 * IWLAN default mode. On device that has IRadio 1.4 or above, it means 137 * {@link #IWLAN_OPERATION_MODE_AP_ASSISTED}. On device that has IRadio 1.3 or below, it means 138 * {@link #IWLAN_OPERATION_MODE_LEGACY}. 139 */ 140 public static final String IWLAN_OPERATION_MODE_DEFAULT = "default"; 141 142 /** 143 * IWLAN legacy mode. IWLAN is completely handled by the modem, and when the device is on 144 * IWLAN, modem reports IWLAN as a RAT. 145 */ 146 public static final String IWLAN_OPERATION_MODE_LEGACY = "legacy"; 147 148 /** 149 * IWLAN application processor assisted mode. IWLAN is handled by the bound IWLAN data service 150 * and network service separately. 151 */ 152 public static final String IWLAN_OPERATION_MODE_AP_ASSISTED = "AP-assisted"; 153 154 private final Phone mPhone; 155 156 private final LocalLog mLocalLog = new LocalLog(100); 157 158 /** The available transports. Must be one or more of AccessNetworkConstants.TransportType.XXX */ 159 private final int[] mAvailableTransports; 160 161 @Nullable 162 private AccessNetworksManager mAccessNetworksManager; 163 164 /** 165 * Current available networks. The key is the APN type, and the value is the available network 166 * list in the preferred order. 167 */ 168 private final SparseArray<int[]> mCurrentAvailableNetworks; 169 170 /** 171 * The queued available networks list. 172 */ 173 private final ArrayDeque<List<QualifiedNetworks>> mQueuedNetworksList; 174 175 /** 176 * The current transport of the APN type. The key is the APN type, and the value is the 177 * transport. 178 */ 179 private final Map<Integer, Integer> mCurrentTransports; 180 181 /** 182 * The pending handover list. This is a list of APNs that are being handover to the new 183 * transport. The entry will be removed once handover is completed. The key 184 * is the APN type, and the value is the target transport that the APN is handovered to. 185 */ 186 private final SparseIntArray mPendingHandoverApns; 187 188 /** 189 * The registrants for listening data handover needed events. 190 */ 191 private final RegistrantList mHandoverNeededEventRegistrants; 192 193 /** 194 * Handover parameters 195 */ 196 @VisibleForTesting 197 public static final class HandoverParams { 198 /** 199 * The callback for handover complete. 200 */ 201 public interface HandoverCallback { 202 /** 203 * Called when handover is completed. 204 * 205 * @param success {@true} if handover succeeded, otherwise failed. 206 * @param fallback {@true} if handover failed, the data connection fallback to the 207 * original transport 208 */ onCompleted(boolean success, boolean fallback)209 void onCompleted(boolean success, boolean fallback); 210 } 211 212 public final @ApnType int apnType; 213 public final int targetTransport; 214 public final HandoverCallback callback; 215 216 @VisibleForTesting HandoverParams(int apnType, int targetTransport, HandoverCallback callback)217 public HandoverParams(int apnType, int targetTransport, HandoverCallback callback) { 218 this.apnType = apnType; 219 this.targetTransport = targetTransport; 220 this.callback = callback; 221 } 222 } 223 TransportManager(Phone phone)224 public TransportManager(Phone phone) { 225 mPhone = phone; 226 mCurrentAvailableNetworks = new SparseArray<>(); 227 mCurrentTransports = new ConcurrentHashMap<>(); 228 mPendingHandoverApns = new SparseIntArray(); 229 mHandoverNeededEventRegistrants = new RegistrantList(); 230 mQueuedNetworksList = new ArrayDeque<>(); 231 mLogTag = TransportManager.class.getSimpleName() + "-" + mPhone.getPhoneId(); 232 233 if (isInLegacyMode()) { 234 log("operates in legacy mode."); 235 // For legacy mode, WWAN is the only transport to handle all data connections, even 236 // the IWLAN ones. 237 mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN}; 238 } else { 239 log("operates in AP-assisted mode."); 240 mAccessNetworksManager = new AccessNetworksManager(phone); 241 mAccessNetworksManager.registerForQualifiedNetworksChanged(this, 242 EVENT_QUALIFIED_NETWORKS_CHANGED); 243 mAvailableTransports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN, 244 AccessNetworkConstants.TRANSPORT_TYPE_WLAN}; 245 } 246 } 247 248 @Override handleMessage(Message msg)249 public void handleMessage(Message msg) { 250 switch (msg.what) { 251 case EVENT_QUALIFIED_NETWORKS_CHANGED: 252 AsyncResult ar = (AsyncResult) msg.obj; 253 List<QualifiedNetworks> networks = (List<QualifiedNetworks>) ar.result; 254 mQueuedNetworksList.add(networks); 255 sendEmptyMessage(EVENT_UPDATE_AVAILABLE_NETWORKS); 256 break; 257 case EVENT_UPDATE_AVAILABLE_NETWORKS: 258 updateAvailableNetworks(); 259 break; 260 default: 261 loge("Unexpected event " + msg.what); 262 break; 263 } 264 } 265 isHandoverNeeded(QualifiedNetworks newNetworks)266 private boolean isHandoverNeeded(QualifiedNetworks newNetworks) { 267 int apnType = newNetworks.apnType; 268 int[] newNetworkList = newNetworks.qualifiedNetworks; 269 int[] currentNetworkList = mCurrentAvailableNetworks.get(apnType); 270 271 if (ArrayUtils.isEmpty(currentNetworkList) 272 && ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get(newNetworkList[0]) 273 == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { 274 // This is a special case that when first time boot up in airplane mode with wifi on, 275 // qualified network service reports IWLAN as the preferred network. Although there 276 // is no live data connection on cellular, there might be network requests which were 277 // already sent to cellular DCT. In this case, we still need to handover the network 278 // request to the new transport. 279 return true; 280 } 281 282 // If the current network list is empty, but the new network list is not, then we can 283 // directly setup data on the new network. If the current network list is not empty, but 284 // the new network is, then we can tear down the data directly. Therefore if one of the 285 // list is empty, then we don't need to do handover. 286 if (ArrayUtils.isEmpty(newNetworkList) || ArrayUtils.isEmpty(currentNetworkList)) { 287 return false; 288 } 289 290 291 if (mPendingHandoverApns.get(newNetworks.apnType) 292 == ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get(newNetworkList[0])) { 293 log("Handover not needed. There is already an ongoing handover."); 294 return false; 295 } 296 297 // The list is networks in the preferred order. For now we only pick the first element 298 // because it's the most preferred. In the future we should also consider the rest in the 299 // list, for example, the first one violates carrier/user policy. 300 return !ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get(newNetworkList[0]) 301 .equals(getCurrentTransport(newNetworks.apnType)); 302 } 303 areNetworksValid(QualifiedNetworks networks)304 private static boolean areNetworksValid(QualifiedNetworks networks) { 305 if (networks.qualifiedNetworks == null || networks.qualifiedNetworks.length == 0) { 306 return false; 307 } 308 for (int network : networks.qualifiedNetworks) { 309 if (!ACCESS_NETWORK_TRANSPORT_TYPE_MAP.containsKey(network)) { 310 return false; 311 } 312 } 313 return true; 314 } 315 316 /** 317 * Set the current transport of apn type. 318 * 319 * @param apnType The APN type 320 * @param transport The transport. Must be WWAN or WLAN. 321 */ setCurrentTransport(@pnType int apnType, int transport)322 private synchronized void setCurrentTransport(@ApnType int apnType, int transport) { 323 Integer previousTransport = mCurrentTransports.put(apnType, transport); 324 if (previousTransport == null || previousTransport != transport) { 325 logl("setCurrentTransport: apnType=" + ApnSetting.getApnTypeString(apnType) 326 + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)); 327 } 328 } 329 isHandoverPending()330 private boolean isHandoverPending() { 331 return mPendingHandoverApns.size() > 0; 332 } 333 updateAvailableNetworks()334 private void updateAvailableNetworks() { 335 if (isHandoverPending()) { 336 log("There's ongoing handover. Will update networks once handover completed."); 337 return; 338 } 339 340 if (mQueuedNetworksList.size() == 0) { 341 log("Nothing in the available network list queue."); 342 return; 343 } 344 345 List<QualifiedNetworks> networksList = mQueuedNetworksList.remove(); 346 logl("updateAvailableNetworks: " + networksList); 347 for (QualifiedNetworks networks : networksList) { 348 if (areNetworksValid(networks)) { 349 if (isHandoverNeeded(networks)) { 350 // If handover is needed, perform the handover works. For now we only pick the 351 // first element because it's the most preferred. In the future we should also 352 // consider the rest in the list, for example, the first one violates 353 // carrier/user policy. 354 int targetTransport = ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get( 355 networks.qualifiedNetworks[0]); 356 logl("Handover needed for APN type: " 357 + ApnSetting.getApnTypeString(networks.apnType) 358 + ", target transport: " 359 + AccessNetworkConstants.transportTypeToString(targetTransport)); 360 mPendingHandoverApns.put(networks.apnType, targetTransport); 361 mHandoverNeededEventRegistrants.notifyResult( 362 new HandoverParams(networks.apnType, targetTransport, 363 (success, fallback) -> { 364 // The callback for handover completed. 365 if (success) { 366 logl("Handover succeeded."); 367 } else { 368 logl("APN type " 369 + ApnSetting.getApnTypeString(networks.apnType) 370 + " handover to " 371 + AccessNetworkConstants.transportTypeToString( 372 targetTransport) + " failed." 373 + ", fallback=" + fallback); 374 } 375 if (success || !fallback) { 376 // If handover succeeds or failed without falling back 377 // to the original transport, we should move to the new 378 // transport (even if it is failed). 379 setCurrentTransport(networks.apnType, targetTransport); 380 } 381 mPendingHandoverApns.delete(networks.apnType); 382 383 // If there are still pending available network changes, we 384 // need to process the rest. 385 if (mQueuedNetworksList.size() > 0) { 386 sendEmptyMessage(EVENT_UPDATE_AVAILABLE_NETWORKS); 387 } 388 })); 389 } 390 mCurrentAvailableNetworks.put(networks.apnType, networks.qualifiedNetworks); 391 } else { 392 loge("Invalid networks received: " + networks); 393 } 394 } 395 396 // If there are still pending available network changes, we need to process the rest. 397 if (mQueuedNetworksList.size() > 0) { 398 sendEmptyMessage(EVENT_UPDATE_AVAILABLE_NETWORKS); 399 } 400 } 401 402 /** 403 * @return The available transports. Note that on legacy devices, the only available transport 404 * would be WWAN only. If the device is configured as AP-assisted mode, the available transport 405 * will always be WWAN and WLAN (even if the device is not camped on IWLAN). 406 * See {@link #isInLegacyMode()} for mode details. 407 */ getAvailableTransports()408 public synchronized @NonNull int[] getAvailableTransports() { 409 return mAvailableTransports; 410 } 411 412 /** 413 * @return {@code true} if the device operates in legacy mode, otherwise {@code false}. 414 */ isInLegacyMode()415 public boolean isInLegacyMode() { 416 // Get IWLAN operation mode from the system property. If the system property is configured 417 // to default or not configured, the mode is tied to IRadio version. For 1.4 or above, it's 418 // AP-assisted mode, for 1.3 or below, it's legacy mode. 419 String mode = SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE); 420 421 if (mode.equals(IWLAN_OPERATION_MODE_AP_ASSISTED)) { 422 return false; 423 } else if (mode.equals(IWLAN_OPERATION_MODE_LEGACY)) { 424 return true; 425 } 426 427 return mPhone.getHalVersion().less(RIL.RADIO_HAL_VERSION_1_4); 428 } 429 430 /** 431 * Get the transport based on the APN type. 432 * 433 * @param apnType APN type 434 * @return The transport type 435 */ getCurrentTransport(@pnType int apnType)436 public int getCurrentTransport(@ApnType int apnType) { 437 // In legacy mode, always route to cellular. 438 if (isInLegacyMode()) { 439 return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 440 } 441 442 // If we can't find the corresponding transport, always route to cellular. 443 return mCurrentTransports.get(apnType) == null 444 ? AccessNetworkConstants.TRANSPORT_TYPE_WWAN : mCurrentTransports.get(apnType); 445 } 446 447 /** 448 * Check if there is any APN type of network preferred on IWLAN. 449 * 450 * @return {@code true} if there is any APN preferred on IWLAN, otherwise {@code false}. 451 */ isAnyApnPreferredOnIwlan()452 public boolean isAnyApnPreferredOnIwlan() { 453 for (int i = 0; i < mCurrentAvailableNetworks.size(); i++) { 454 int[] networkList = mCurrentAvailableNetworks.valueAt(i); 455 if (networkList.length > 0 && networkList[0] == AccessNetworkType.IWLAN) { 456 return true; 457 } 458 } 459 return false; 460 } 461 462 /** 463 * Register for data handover needed event 464 * 465 * @param h The handler of the event 466 * @param what The id of the event 467 */ registerForHandoverNeededEvent(Handler h, int what)468 public void registerForHandoverNeededEvent(Handler h, int what) { 469 if (h != null) { 470 mHandoverNeededEventRegistrants.addUnique(h, what, null); 471 } 472 } 473 474 /** 475 * Unregister for data handover needed event 476 * 477 * @param h The handler 478 */ unregisterForHandoverNeededEvent(Handler h)479 public void unregisterForHandoverNeededEvent(Handler h) { 480 mHandoverNeededEventRegistrants.remove(h); 481 } 482 483 /** 484 * Registers the data throttler with DcTracker. 485 */ registerDataThrottler(DataThrottler dataThrottler)486 public void registerDataThrottler(DataThrottler dataThrottler) { 487 if (mAccessNetworksManager != null) { 488 mAccessNetworksManager.registerDataThrottler(dataThrottler); 489 } 490 } 491 492 /** 493 * Get the latest preferred transport. Note that the current transport only changed after 494 * handover is completed, and there might be queued update network requests not processed yet. 495 * This method is used to get the latest preference sent from qualified networks service. 496 * 497 * @param apnType APN type 498 * @return The preferred transport. {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID} if 499 * unknown, unavailable, or QNS explicitly specifies data connection of the APN type should not 500 * be brought up on either cellular or IWLAN. 501 */ getPreferredTransport(@pnType int apnType)502 public @TransportType int getPreferredTransport(@ApnType int apnType) { 503 // Since the latest updates from QNS is stored at the end of the queue, so if we want to 504 // check what's the latest, we should iterate the queue reversely. 505 Iterator<List<QualifiedNetworks>> it = mQueuedNetworksList.descendingIterator(); 506 while (it.hasNext()) { 507 List<QualifiedNetworks> networksList = it.next(); 508 for (QualifiedNetworks networks : networksList) { 509 if (networks.apnType == apnType) { 510 if (networks.qualifiedNetworks.length > 0) { 511 return ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get(networks.qualifiedNetworks[0]); 512 } 513 // This is the case that QNS explicitly specifies no data allowed on neither 514 // cellular nor IWLAN. 515 return AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 516 } 517 } 518 } 519 520 // if not found in the queue, see if it's in the current available networks. 521 int[] currentNetworkList = mCurrentAvailableNetworks.get(apnType); 522 if (currentNetworkList != null) { 523 if (currentNetworkList.length > 0) { 524 return ACCESS_NETWORK_TRANSPORT_TYPE_MAP.get(currentNetworkList[0]); 525 } 526 // This is the case that QNS explicitly specifies no data allowed on neither 527 // cellular nor IWLAN. 528 return AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 529 } 530 531 // If no input from QNS, for example in legacy mode, the default preferred transport should 532 // be cellular. 533 return AccessNetworkConstants.TRANSPORT_TYPE_WWAN; 534 } 535 536 537 /** 538 * Dump the state of transport manager 539 * 540 * @param fd File descriptor 541 * @param printwriter Print writer 542 * @param args Arguments 543 */ dump(FileDescriptor fd, PrintWriter printwriter, String[] args)544 public void dump(FileDescriptor fd, PrintWriter printwriter, String[] args) { 545 IndentingPrintWriter pw = new IndentingPrintWriter(printwriter, " "); 546 pw.println(mLogTag); 547 pw.increaseIndent(); 548 pw.println("mAvailableTransports=[" + Arrays.stream(mAvailableTransports) 549 .mapToObj(AccessNetworkConstants::transportTypeToString) 550 .collect(Collectors.joining(",")) + "]"); 551 pw.println("mCurrentAvailableNetworks="); 552 pw.increaseIndent(); 553 for (int i = 0; i < mCurrentAvailableNetworks.size(); i++) { 554 pw.println("APN type " 555 + ApnSetting.getApnTypeString(mCurrentAvailableNetworks.keyAt(i)) 556 + ": [" + Arrays.stream(mCurrentAvailableNetworks.valueAt(i)) 557 .mapToObj(AccessNetworkType::toString) 558 .collect(Collectors.joining(",")) + "]"); 559 } 560 pw.decreaseIndent(); 561 pw.println("mQueuedNetworksList=" + mQueuedNetworksList); 562 pw.println("mPendingHandoverApns=" + mPendingHandoverApns); 563 pw.println("mCurrentTransports="); 564 pw.increaseIndent(); 565 for (Map.Entry<Integer, Integer> entry : mCurrentTransports.entrySet()) { 566 pw.println("APN type " + ApnSetting.getApnTypeString(entry.getKey()) 567 + ": " + AccessNetworkConstants.transportTypeToString(entry.getValue())); 568 } 569 pw.decreaseIndent(); 570 pw.println("isInLegacy=" + isInLegacyMode()); 571 pw.println("IWLAN operation mode=" 572 + SystemProperties.get(SYSTEM_PROPERTIES_IWLAN_OPERATION_MODE)); 573 if (mAccessNetworksManager != null) { 574 mAccessNetworksManager.dump(fd, pw, args); 575 } 576 pw.println("Local logs="); 577 pw.increaseIndent(); 578 mLocalLog.dump(fd, pw, args); 579 pw.decreaseIndent(); 580 pw.decreaseIndent(); 581 pw.flush(); 582 } 583 logl(String s)584 private void logl(String s) { 585 log(s); 586 mLocalLog.log(s); 587 } 588 log(String s)589 private void log(String s) { 590 Rlog.d(mLogTag, s); 591 } 592 loge(String s)593 private void loge(String s) { 594 Rlog.e(mLogTag, s); 595 } 596 } 597