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