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