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