• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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